1

我一直在尝试编写一些代码来生成任何给定大小的迷宫(由 32x32 瓷砖组成),但是在渲染代码中遇到了一个奇怪的问题,因为只有方形迷宫才能正确纹理化。

我有一个 .png 文件,其中包含所有可能的墙壁纹理和地板纹理,并且取决于在纹理方法期间当前所选墙壁周围墙壁的位置,应选择此 .png 的正确部分以使墙壁融合在一起很好。然而,如前所述,这只适用于方形迷宫(注意,渲染是使用顶点缓冲区对象完成的)。

这是生成迷宫的代码(目前,它只是用墙壁随机填充空间,我计划在修复此问题后调整这部分以实际生成可解决的迷宫):

public void run() { // The maze is part of a thread called World, which runs alongside a Renderer thread
    mazeWidth = 20;
    mazeHeight = 15;
    maze = new byte[mazeWidth][mazeHeight];
}

public static void setUpMaze() {
    for (int x = 0; x < mazeWidth; x++) {
        for (int y = 0; y < mazeHeight; y++) {
            // TODO Make proper maze generation code
            maze[x][y] = (byte) mazeGenerator.nextInt(2);
        }
    }
}

为要绘制的三角形生成顶点的代码:

private float[] getMazeGrid() { // The 12 comes from the number of coordinates needed to define a square/single tile - 2 triangles, 6 vertices, 2 coordinates per vertex
    float[] mazeGrid = new float[12 * World.mazeWidth * World.mazeHeight];
    int yOffset = 0;
    int xOffset = 0;
        // The if statements adjust the minimum x/y coordinates for each tile, the for iterates through the tiles
        for (int i = 0; i < World.mazeWidth * World.mazeHeight; i++) {
            if (i % World.mazeWidth == 0) {
                xOffset = 0;
            } else {
                xOffset += 32;
            }
            if (i % World.mazeWidth == 0 && i != 0) {
                yOffset += 32;
            }
            // The code below defines one square of the grid
            mazeGrid[12 * i + 0] = xOffset;
            mazeGrid[12 * i + 1] = yOffset;
            mazeGrid[12 * i + 2] = xOffset;
            mazeGrid[12 * i + 3] = yOffset + 32;
            mazeGrid[12 * i + 4] = xOffset + 32;
            mazeGrid[12 * i + 5] = yOffset + 32;
            mazeGrid[12 * i + 6] = xOffset + 32;
            mazeGrid[12 * i + 7] = yOffset + 32;
            mazeGrid[12 * i + 8] = xOffset + 32;
            mazeGrid[12 * i + 9] = yOffset;
            mazeGrid[12 * i + 10] = xOffset;
            mazeGrid[12 * i + 11] = yOffset;                
        }
    return mazeGrid;
}

以及确定应该使用纹理的哪一部分的代码:

private float[] getTexCoords(int x, int y) {
    texNumKey = 0;
    if (World.maze[x][y] == 1) {
        if (y > 0) {
            if (World.maze[x][y - 1] == 1) texNumKey += 1;
        }
        if (x > 0) {
            if (World.maze[x - 1][y] == 1) texNumKey += 2;
        }
        if (x < World.mazeWidth - 1) {
            if (World.maze[x + 1][y] == 1) texNumKey += 4;
        }
        if (y < World.mazeHeight - 1) {
            if (World.maze[x][y + 1] == 1) texNumKey += 8;
        }
    } else if (World.maze[x][y] == 0) {
        texNumKey = 16;
    }
    return texMap.get(texNumKey);
}

注意:texMap 是一个 HashMap,它包含带有纹理坐标的浮点数组,纹理坐标缓冲区将使用该数组,以 0-16 的数字作为键。上面的代码遍历网格并检查当前瓷砖周围的空间,并为该墙类型选择正确的纹理坐标。

最后,顶点缓冲区对象代码 - 设置 VBO:

public void setUp() {
    initialiseTextureMap();

    vertexData = BufferUtils.createFloatBuffer(12 * World.mazeWidth * World.mazeHeight);
    vertexData.put(getMazeGrid());
    vertexData.flip();

    textureData = BufferUtils.createFloatBuffer(12 * World.mazeWidth * World.mazeHeight);
    for (int x = 0; x < World.mazeWidth; x++) {
        for (int y = 0; y < World.mazeHeight; y++) {
            textureData.put(getTexCoords(x, y));
        }
    }
    textureData.flip();

    vboVertexHandle = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
    glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    vboTextureCoordHandle = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vboTextureCoordHandle);
    glBufferData(GL_ARRAY_BUFFER, textureData, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

并绘制 VBO:

public void draw() {            // Draws the entity
    glBindTexture(GL_TEXTURE_2D, loadTexture(this.textureKey).getTextureID());

    glBindBuffer(GL_ARRAY_BUFFER, this.vboVertexHandle);
    glVertexPointer(2, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, this.vboTextureCoordHandle);
    glTexCoordPointer(2, GL_FLOAT, 0, 0);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glDrawArrays(GL_TRIANGLES, 0, 12 * World.mazeWidth * World.mazeHeight);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

大多数无法解释的变量名称应该是相当自我解释的,它们是在抽象超类或“迷宫”类构造函数中定义的。

因此,为了清楚起见,当我将 mazeWidth 和 mazeHeight 的值设置为彼此相同的值时,上面的代码可以完美运行,但如果它们不同,则纹理不会正确分配给图块 - 这是代码示例工作和失败,顶部是 10 x 10 迷宫,底部是 10 x 11:迷宫示例

编辑:在纹理坐标缓冲区设置中切换 x 和 y for 循环后: 迷宫示例 2

如果您需要任何其他信息/我错过了一些重要的信息,请告诉我。

4

2 回答 2

1

您的问题是 x 和 y 的 for 循环与 push 方法的组合。您首先循环列,而不是先跨行。-put假设行第一循环。

这将很快解决问题:

for (int y = 0; y < World.mazeHeight; y++) {
    for (int x = 0; x < World.mazeWidth; x++) {
       textureData.put(getTexCoords(x, y));
    }
}

您的纹理选择也必须更新,镜像在对角线上。例如,如果您选择路径向南的纹理,现在将使用向东的路径绘制它。

于 2013-08-23T00:09:30.910 回答
0

在设置中

尝试改变

for (int x = 0; x < World.mazeWidth; x++) {
    for (int y = 0; y < World.mazeHeight; y++) {
        textureData.put(getTexCoords(x, y));
    }
}

for (int y = 0; y < World.mazeHeight; y++) {
    for (int x = 0; x < World.mazeWidth; x++) {
        textureData.put(getTexCoords(x, y));
    }
}
于 2013-08-23T00:08:58.213 回答