我一直在尝试编写一些代码来生成任何给定大小的迷宫(由 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/