使用VBO上传顶点后更改其颜色 [英] Change colour of vertices after they are uploaded using a VBO

查看:108
本文介绍了使用VBO上传顶点后更改其颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在此链接中找到了Apple的工作编码示例: http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html

为200 x 200平方的固定网格创建顶点后,我通过使用VBO将顶点发送到GPU来渲染它.然后如何更新顶点的颜色?数百个顶点的颜色会频繁变化-每隔几帧.

我以前没有使用VBO解决了这个问题.我创建了顶点和颜色的数组,并使用以下代码渲染了顶点.我通过更新数组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);
}

尽管上面的代码行得通,但它却消耗了很多电池,因此现在我正尝试使用VBO来实现.顶点不会改变位置,因此我知道可以使用VBO,但是改变顶点的颜色呢?

这是我当前的简化为仅绘制一个正方形的代码:

编辑:如何更新下面的代码,使其在更改顶点颜色时仅上载它们? VBO设置代码和绘制代码应如何更改? 如何更新我的verticesColours colors数组然后调用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);
}

解决方案

取决于. (好话,不是吗?适合所有情况.)

如果您确实需要以不可预测的方式改变每个顶点的颜色,则每次绘制它们时,是的,您将需要在每一帧上载顶点颜色.将顶点位置放在自己的(静态)VBO中是一个不错的选择,因为它使您可以重复使用而不必每次都上载(系统内存<-> GPU内存带宽始终是宝贵的商品),但是任何会进行更改,那么,进行更改.

但是,如果您可以通过编程方式计算每个顶点的颜色,那么顶点着色器会派上用场. (实际上,它们是为它们制造的!)希望,每个顶点的颜色是以下各项的某种组合的函数:

  1. 每个顶点的静态数据.您可以在 VBO 中上传一次并重复使用.
  2. 整个数组中全局的变量数据.为此,您可以使用着色器制服,并且每次绘制都只需上传一次.
  3. 也许顶点纹理,如果您的平台支持的话?

然后,您可以编写一个顶点着色器,以计算这些输入的颜色,并且每帧只需要重新指定着色器均匀性(通常总共要打12个左右浮点). /p>

因此,这取决于您希望颜色如何改变.如果可以使用顶点着色器,那么每次绘制时确实可以跳过上载.如果您不能这样做和/或该突变过于复杂或任意,以至于无法在顶点着色器中进行操作,则只需要在CPU端进行操作,然后咬住上传项目符号即可.

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);
}

解决方案

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.

这篇关于使用VBO上传顶点后更改其颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆