我已经为此苦苦挣扎了几个星期。我正在制作一个体素游戏,该游戏生成16 ^ 3个块作为要渲染的单个交错缓冲区。我已将大部分工作转移到ThreadExecutor上,但是我无法消除OpenGL的滞后。
下面的代码是我的Chunk类(ChunkMesh.java),它的构造函数在另一个线程上调用,而init
函数是在主线程上运行以初始化OpenGl数据的函数。它需要不到一毫秒的时间,但通常要花费5或更多,并且很少冻结超过两秒钟,这是不可接受的。
我对OpenGL没有超级的经验,我发现的与体素游戏相关的其他线程都没有与我相同的问题,也不适用它们的解决方案。请,如果有人有什么见识,请帮助我。
package client.engine.graphics;
import org.lwjgl.system.MemoryUtil;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13.glActiveTexture;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
public class ChunkMesh {
private int vaoID;
private List<Integer> vboIDList;
private int vertexCount;
public Material material;
private float[] interleaved;
private int[] indices;
public ChunkMesh(float[] positions, float[] texCoords, float[] normals, int[] indices) {
vertexCount = indices.length;
vboIDList = new ArrayList<>();
this.indices = indices;
long buffTime = System.nanoTime();
interleaved = new float[positions.length + texCoords.length + normals.length];
int ind = 0;
for (var i = 0; i < positions.length / 3; i++) {
interleaved[ind++] = positions[i*3];
interleaved[ind++] = positions[i*3+1];
interleaved[ind++] = positions[i*3+2];
interleaved[ind++] = normals[i*3];
interleaved[ind++] = normals[i*3+1];
interleaved[ind++] = normals[i*3+2];
interleaved[ind++] = texCoords[i*2];
interleaved[ind++] = texCoords[i*2+1];
}
buffTime = System.nanoTime() - buffTime;
}
public void init() {
FloatBuffer interleavedBuffer = MemoryUtil.memAllocFloat(interleaved.length).put(interleaved).flip();
interleaved = null;
IntBuffer indicesBuffer = MemoryUtil.memAllocInt(indices.length).put(indices).flip();
indices = null;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
int vboID = glGenBuffers();
vboIDList.add(vboID);
long allocTime = System.nanoTime();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, interleavedBuffer, GL_STATIC_DRAW);
int stride = (3 + 3 + 2) * 4;
//Position VBO
glVertexAttribPointer(0, 3, GL_FLOAT, false, stride, 0);
//Normals VBO
glVertexAttribPointer(1, 3, GL_FLOAT, false, stride, 3 * 4);
//TexCoord VBO
glVertexAttribPointer(2, 2, GL_FLOAT, false, stride, 6 * 4);
allocTime = System.nanoTime() - allocTime;
float totalMs = allocTime / 1_000_000f;
if (totalMs > 5) System.err.println(totalMs);
else System.out.println(totalMs);
//Index VBO
vboID = glGenBuffers();
vboIDList.add(vboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
MemoryUtil.memFree(interleavedBuffer);
MemoryUtil.memFree(indicesBuffer);
}
public int getVaoID() {
return vaoID;
}
public int getVertexCount() {
return vertexCount;
}
public void initChunksRender() {
Texture texture = material.getTexture();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.getID());
}
public void endChunksRender() {
glBindTexture(GL_TEXTURE_2D, 0);
}
private void initRender() {
//Draw the mesh
glBindVertexArray(getVaoID());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
}
private void endRender() {
//Restore State
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindVertexArray(0);
}
public void render() {
initRender();
glDrawElements(GL_TRIANGLES, getVertexCount(), GL_UNSIGNED_INT, 0);
endRender();
}
public void cleanup() {
glDisableVertexAttribArray(0);
//Delete the VBOs
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (int vboID : vboIDList) {
glDeleteBuffers(vboID);
}
glBindVertexArray(0);
glDeleteBuffers(vaoID);
}
public void deleteBuffers() {
glDisableVertexAttribArray(0);
//Delete the VBOs
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (int vboID : vboIDList) {
glDeleteBuffers(vboID);
}
//Delete the VAO
glBindVertexArray(0);
glDeleteVertexArrays(vaoID);
}
}