问题
EDIT: Working coded example by Apple found at this link: http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html
After creating the vertices for a fixed grid of 200 x 200 squares, I render it by sending the vertices to the GPU using a VBO. How can I then update the colour of the vertices? The colour of hundreds of vertices will change frequently - every few frames.
I previously tackled the problem not using a VBO. I created arrays of vertices and colours and used the following code to render the vertices. I changed the colour of vertices by updating the array triangleColours
:
-(void)render {
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
glClear(GL_COLOR_BUFFER_BIT);
[effect prepareToDraw];
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2,
GL_FLOAT, GL_FALSE, 0, triangleVertices);
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4,
GL_FLOAT, GL_FALSE, 0, triangleColours);
glDrawArrays(GL_TRIANGLES, 0, numTriangleVertices);
glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribColor);
}
Although the above code worked, it ate a lot of battery, so now I'm trying to do it with VBOs. The vertices don't change position, so I understand that VBOs are a good choice to use, but what about changing the colour of the vertices?
This is my current code simplified to draw only a single square:
EDIT: How would I update the code below so it uploads only the vertex colours when they change? How should the VBO setup code and the draw code change? How about updating my verticesColours colours array then calling glBufferSubData()?
// Setup vertices and VBO
// Vertices for a single square
const Vertex Vertices[] = {
// position and colour
{{-20, -20}, {1, 1, 1, 1}},
{{-20, -20}, {1, 1, 1, 1}},
{{-20, -20}, {1, 1, 1, 1}},
{{-20, -20}, {1, 1, 1, 1}},
};
const GLubyte Indices[] = {
0, 1, 2,
2, 3, 0,
};
numIndices = sizeof(Indices)/sizeof(Indices[0]);
[EAGLContext setCurrentContext:self.context];
glEnable(GL_CULL_FACE);
self.effect = [[GLKBaseEffect alloc] init];
self.effect.transform.projectionMatrix = GLKMatrix4MakeOrtho(-50.0, 50.0,
-50.0, 50.0,
0.0, 1.0);
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *) offsetof(Vertex, Position));
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *) offsetof(Vertex, Color));
glBindVertexArrayOES(0);
// Render
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
[self.effect prepareToDraw];
glBindVertexArrayOES(_vertexArray);
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, 0);
}
回答1:
Depends. (Great word, isn't it? Good for all situations.)
If you truly need to mutate the colors of each vertex in unpredictable ways, every time you draw them, then yes you will need to upload the vertex colors each frame. Putting the vertex positions in their own (static) VBO is a good choice, since that allows you to reuse without uploading every time (system memory <-> GPU memory bandwidth always being a precious commodity), but anything that will have to change, well, will have to change.
If you can calculate the color of each vertex programmatically, though, this is where vertex shaders come in handy. (Indeed, what they were made for!) Hopefully, the color of each vertex is some function of some combination of:
- Static per-vertex data. You can upload this once in a VBO and reuse.
- Variable data that is global across the entire array. You use shader uniforms for this, and just upload them once for every draw.
- Perhaps vertex textures, if your platform supports that?
Then, you can write a vertex shader that computes the color from those inputs, and every frame you'll only have to respecify the shader uniforms -- which is usually on the order of a dozen or so floats, total.
So it depends on how you want your colors to change. If you can use a vertex shader, then you can indeed skip out on uploading with every draw. If you can't and/or the mutation is too complicated or arbitrary to do in a vertex shader -- you'll just have to do that CPU-side, and bite the upload bullet.
来源:https://stackoverflow.com/questions/14574660/change-colour-of-vertices-after-they-are-uploaded-using-a-vbo