我一直在尝试编写一些代码来生成任何给定大小的迷宫(由 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
如果您需要任何其他信息/我错过了一些重要的信息,请告诉我。