OpenGL glBufferSubData - 无法让它工作
OpenGL glBufferSubData - can't get it to work
我需要用新顶点更新我的网格。我这样创建 VBO(最初创建时只有一个顶点):
public Mesh(float[] vertex, int size)
{
texture = null;
meshType = 1; //will draw lines
FloatBuffer verticesBuffer = null;
IntBuffer indicesBuffer = null;
int vboID;
try
{
vertexCount = size;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
vboIDList = new ArrayList<>();
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
// Indices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
indicesBuffer = MemoryUtil.memAllocInt(size); // !!! Must be manually freed!
indicesBuffer.put(new int[]{0}).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
// unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
finally
{
if (verticesBuffer != null)
{
MemoryUtil.memFree(verticesBuffer); // Freeing vertex buffer
}
if (indicesBuffer != null)
{
MemoryUtil.memFree(indicesBuffer); // Freeing indices buffer
}
}
}
然后我想更新 VBO 缓冲区并将新顶点写入其中。请注意,我确实创建了 VBO 以便为我的新顶点提供足够的 space,并且我控制它不会被过度填充。我还控制每次渲染调用绘制的元素数量,因此我不会绘制空的 0/0/0 顶点。
我的问题是,这段代码有效:
public void updateVBO(float[] vertices, int[] indices, int size)
{
if (meshType == 1)
{
lineCount = size;
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
try
{
//System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
//float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(vertices.length); // !!! Must Be manually freed!
subDataF.put(vertices).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, subDataF, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
//int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(indices.length); // !!! Must Be manually freed!
subDataI.put(indices).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, subDataI, GL_STATIC_DRAW);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
所以当我传递整个顶点数组并从头开始重新分配 VBO 内存时 - 它绘制的正是我需要的。
但是我想使用 glBufferSubData,这样我就不会在每次添加新顶点时都重新分配内存。
此代码不起作用:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(3); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, position * 3 * 4, subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(1); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, position * 4, subDataI);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
另外我知道它没有优化我创建 floatbuffer 和 intbuffer 的方式,我只想在清理它之前让它工作。我尝试了很多东西,因此最后一段代码很奇怪。
不过,我还是不明白我做错了什么。我确实检查过我是否正确传递了所有数据,并且位置(和偏移量)似乎是按应有的方式计算的。它只是不绘制任何东西,而当我使用 glBufferData 时它会绘制。
谁能解释一下我哪里出错了?
在所有建议之后,这就是我的最终结果,但它仍然根本不起作用:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(3); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, (long)(position * 3 * 4), (FloatBuffer)subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(1); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindVertexArray(vaoID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, (long)(position * 4), (IntBuffer)subDataI);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
我确实检查过 VAO ID 是否正确。
正如我所想的那样,这很愚蠢,与 VAO 绑定等完全无关。
问题是,当我最初创建 VBO 时,我是这样做的:
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
我假设因为我为 size*3 浮点数分配缓冲区,所以它将是那个大小,当我把它放在 VBO 中时 - 它会分配 size*3*4 字节,即足够 size*3浮动。
原来不是!因为我只将一个顶点(3 个浮点数)放入缓冲区 - 它只会分配那个数量的 space。所以当我稍后尝试使用 glBufferSubData - 它只有 spaces 用于 GPU 上的 3 个浮点数,并且自然不会将值放在我需要的地方。我真的很惊讶它并没有完全崩溃。
为了解决这个问题,目前我这样做了:
// Vertices VBO generation
...
verticesBuffer.put(vertex).put(new float[size*3 - 3]).flip();
...
所以基本上我是手动将一个空数组放入 FloatBuffer,这确保了缓冲区的大小正确。
结果如下:
构造函数:
public Mesh(float[] vertex, int size)
{
texture = null;
meshType = 1; //will draw lines
FloatBuffer verticesBuffer = null;
IntBuffer indicesBuffer = null;
int vboID;
try
{
vertexCount = size;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
vboIDList = new ArrayList<>();
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).put(new float[size*3 - 3]).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
// Indices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
indicesBuffer = MemoryUtil.memAllocInt(size); // !!! Must be manually freed!
indicesBuffer.put(new int[size]).flip(); // I need the first element 0 anyway
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
// unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
finally
{
if (verticesBuffer != null)
{
MemoryUtil.memFree(verticesBuffer); // Freeing vertex buffer
}
if (indicesBuffer != null)
{
MemoryUtil.memFree(indicesBuffer); // Freeing indices buffer
}
}
}
然后更新:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(vert.length); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, (long)(position * 3 * 4), (FloatBuffer)subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(index.length); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, (long)(position * 4), (IntBuffer)subDataI);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
并且有效。请注意代码有点脏,我在发布答案之前没有清理它。
我需要用新顶点更新我的网格。我这样创建 VBO(最初创建时只有一个顶点):
public Mesh(float[] vertex, int size)
{
texture = null;
meshType = 1; //will draw lines
FloatBuffer verticesBuffer = null;
IntBuffer indicesBuffer = null;
int vboID;
try
{
vertexCount = size;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
vboIDList = new ArrayList<>();
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
// Indices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
indicesBuffer = MemoryUtil.memAllocInt(size); // !!! Must be manually freed!
indicesBuffer.put(new int[]{0}).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
// unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
finally
{
if (verticesBuffer != null)
{
MemoryUtil.memFree(verticesBuffer); // Freeing vertex buffer
}
if (indicesBuffer != null)
{
MemoryUtil.memFree(indicesBuffer); // Freeing indices buffer
}
}
}
然后我想更新 VBO 缓冲区并将新顶点写入其中。请注意,我确实创建了 VBO 以便为我的新顶点提供足够的 space,并且我控制它不会被过度填充。我还控制每次渲染调用绘制的元素数量,因此我不会绘制空的 0/0/0 顶点。
我的问题是,这段代码有效:
public void updateVBO(float[] vertices, int[] indices, int size)
{
if (meshType == 1)
{
lineCount = size;
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
try
{
//System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
//float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(vertices.length); // !!! Must Be manually freed!
subDataF.put(vertices).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, subDataF, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
//int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(indices.length); // !!! Must Be manually freed!
subDataI.put(indices).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, subDataI, GL_STATIC_DRAW);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
所以当我传递整个顶点数组并从头开始重新分配 VBO 内存时 - 它绘制的正是我需要的。 但是我想使用 glBufferSubData,这样我就不会在每次添加新顶点时都重新分配内存。 此代码不起作用:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(3); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, position * 3 * 4, subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(1); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, position * 4, subDataI);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
另外我知道它没有优化我创建 floatbuffer 和 intbuffer 的方式,我只想在清理它之前让它工作。我尝试了很多东西,因此最后一段代码很奇怪。
不过,我还是不明白我做错了什么。我确实检查过我是否正确传递了所有数据,并且位置(和偏移量)似乎是按应有的方式计算的。它只是不绘制任何东西,而当我使用 glBufferData 时它会绘制。
谁能解释一下我哪里出错了?
在所有建议之后,这就是我的最终结果,但它仍然根本不起作用:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(3); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, (long)(position * 3 * 4), (FloatBuffer)subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(1); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindVertexArray(vaoID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, (long)(position * 4), (IntBuffer)subDataI);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
我确实检查过 VAO ID 是否正确。
正如我所想的那样,这很愚蠢,与 VAO 绑定等完全无关。
问题是,当我最初创建 VBO 时,我是这样做的:
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
我假设因为我为 size*3 浮点数分配缓冲区,所以它将是那个大小,当我把它放在 VBO 中时 - 它会分配 size*3*4 字节,即足够 size*3浮动。
原来不是!因为我只将一个顶点(3 个浮点数)放入缓冲区 - 它只会分配那个数量的 space。所以当我稍后尝试使用 glBufferSubData - 它只有 spaces 用于 GPU 上的 3 个浮点数,并且自然不会将值放在我需要的地方。我真的很惊讶它并没有完全崩溃。
为了解决这个问题,目前我这样做了:
// Vertices VBO generation
...
verticesBuffer.put(vertex).put(new float[size*3 - 3]).flip();
...
所以基本上我是手动将一个空数组放入 FloatBuffer,这确保了缓冲区的大小正确。
结果如下: 构造函数:
public Mesh(float[] vertex, int size)
{
texture = null;
meshType = 1; //will draw lines
FloatBuffer verticesBuffer = null;
IntBuffer indicesBuffer = null;
int vboID;
try
{
vertexCount = size;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
vboIDList = new ArrayList<>();
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).put(new float[size*3 - 3]).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
// Indices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
indicesBuffer = MemoryUtil.memAllocInt(size); // !!! Must be manually freed!
indicesBuffer.put(new int[size]).flip(); // I need the first element 0 anyway
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
// unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
finally
{
if (verticesBuffer != null)
{
MemoryUtil.memFree(verticesBuffer); // Freeing vertex buffer
}
if (indicesBuffer != null)
{
MemoryUtil.memFree(indicesBuffer); // Freeing indices buffer
}
}
}
然后更新:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(vert.length); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, (long)(position * 3 * 4), (FloatBuffer)subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(index.length); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, (long)(position * 4), (IntBuffer)subDataI);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
并且有效。请注意代码有点脏,我在发布答案之前没有清理它。