Change colour of vertices after they are uploaded using a VBO

末鹿安然 提交于 2019-12-11 03:45:35

问题


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:

  1. Static per-vertex data. You can upload this once in a VBO and reuse.
  2. Variable data that is global across the entire array. You use shader uniforms for this, and just upload them once for every draw.
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!