java - LWJGL/OpenGL - 绘制迷宫只能使用正方形尺寸吗?

标签 java opengl lwjgl maze

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

我有一个 .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,其中包含 float 组,其中包含纹理坐标缓冲区要使用的纹理坐标,键值为 0-16 之间的数字。上面的代码迭代网格并检查当前图 block 周围的空间,并为该墙类型选择正确的纹理坐标。

最后,顶点缓冲区对象代码 - 设置 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);
}

大多数无法解释的变量名称应该是相当不言自明的,它们是在抽象父类(super class)或“Maze”类构造函数中定义的。

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

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

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

最佳答案

您的问题是 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));
    }
}

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

关于java - LWJGL/OpenGL - 绘制迷宫只能使用正方形尺寸吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18392507/

相关文章:

c++ - OpenGL:如何控制我的窗口将使用哪种缓冲方法?

java - lwjgl 3 , glUniformMatrix4 导致 jre 崩溃

java - 将 LWJGL Java 游戏移植到 XBOX

Java LibGDX 输入处理器多点触控

java - Eclipselink 异常 : Isolated Data is not currently supported

java - 从构造函数调用另一个 GRPC 服务

java - 我对 Java 中的通配符有一些错误的概念

c++ - Mac 中的 OpenGL ARB 函数

c++ - 显示不在 3D 中的不移动文本(例如显示 HUD 或帧速率)

java - 停止后移动速度继续有用