PDA

View Full Version : Changing a Vertex Attribute



Wasabi
08-06-2011, 06:58 PM
I'm working on a project using OpenGL 3.3 with a NVertex class defined as:

class NVertex
{
float x, y, z;
float FillR,FillG,FillB;
float WireframeR,WireframeG,WireframeB;
float Nx, Ny, Nz; //normals
public:
NVertex();
NVertex(float x, float y, float z, float r=1.f, float g=1.f, float b=1.f);
float GetX() const;
float GetY() const;
float GetZ() const;
void Set(float _x, float _y, float _z, float _Nx, float _Ny, float _Nz, float _FillR=1.f, float _FillG=1.f, float _FillB=1.f,float _WireR=0.f, float _WireG=0.f, float _WireB=1.f);
void SetFillColor(float _r, float _g, float _b);
void SetWireframeColor(float _r, float _g, float _b);
void SetPos(float _x, float _y, float _z);
void SetNormal(float _x, float _y, float _z);
};

Elsewhere in the program, I generate the appropriate buffers.


void MyNGLWidget::GenBuffers()
{
//NFault is a class containing a Mesh class containing the vertexes and indexes.
const NFault* fault = Fault.GetFault();
glGenBuffers(1, &Environment.VBO);
glBindBuffer(GL_ARRAY_BUFFER, Environment.VBO);
glBufferData(GL_ARRAY_BUFFER, fault->GetMesh().Size(), fault->GetMesh().GetVertexes(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0); //VERTEX COORDINATES
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1); //VERTEX COLORS
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(12));
glEnableVertexAttribArray(2); //MESH COLORS
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(24));
glEnableVertexAttribArray(3); //NORMALS
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(36));

glGenBuffers(1,&Environment.VIO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,Environment.V IO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*fault->GetMesh().GetNumIndexes(), fault->GetMesh().GetIndexes(),GL_STATIC_DRAW);
}

All this works perfectly, no problem whatsoever (the shaders are compiled elsewhere). Here's my question, though:

What if I want to change the color of the Mesh (that is, of all the Vertexes contained within it)? Do I simply call

glBindBuffer(GL_ARRAY_BUFFER, Environment.VBO);
glBufferData(GL_ARRAY_BUFFER, fault->GetMesh().Size(), fault->GetMesh().GetVertexes(), GL_STATIC_DRAW);
again (after having altered the mesh colors)? I saw in the doc that this deletes the previous values and puts in new ones. However, do I also have to re-call all the glEnableVertexAttribArray/glVertexAttribPointer calls, or are those maintained?

As well, is there a way of changing only the values of a certain VertexAttribArray? It's a bit silly copying the exact same coordinates and normals in order to change the colors.

Or would I have to break up all these attributes into different buffers? In fact, what's the difference between having one giant buffer as I have now, and having different buffers for different attributes of each vertex? Which is best, given that there's a good chance the colors will have to change?

Aleksandar
08-07-2011, 03:04 AM
What if I want to change the color of the Mesh (that is, of all the Vertexes contained within it)? Do I simply call glBindBuffer(...) again (after having altered the mesh colors)? I saw in the doc that this deletes the previous values and puts in new ones. However, do I also have to re-call all the glEnableVertexAttribArray/glVertexAttribPointer calls, or are those maintained?
Instead of that it is better to call glBufferSubData(). Re-enabling vertex attributes is not necessary if this is the only attribute-configuration you are using in the drawing.


As well, is there a way of changing only the values of a certain VertexAttribArray?
You've already given an answer. Split attributes into several buffers.


In fact, what's the difference between having one giant buffer as I have now, and having different buffers for different attributes of each vertex? Which is best, given that there's a good chance the colors will have to change?
If all attributes are equally changeable then you'll get about 5% better performance with just one (combined) buffer. In your case it is probably better to store colors into a separate buffer.

Wasabi
08-07-2011, 07:18 AM
Thanks. But now how do I split the data into separate buffers, given how they are all contained in the same object? I can't just

glBufferData(GL_ARRAY_BUFFER, fault->GetMesh().Size(), fault->GetMesh().GetVertexes(), GL_STATIC_DRAW);
for each buffer, of course.

Is there some way to use BUFFER_OFFSET() like in AttribPointer()? Or will I have to create a method to get just the data I want?

Aleksandar
08-07-2011, 02:59 PM
It is quite obvious that you cannot use vertices in the same form as before, but you have to reorder them (put colors at the back, for example), or create two separate buffers, and copy color attributes to one of them, and all other attributes to the other. Of course, you can keep color attributes with all others, if you think it is easier, but you should treat them as a data-pad, and read values from the other buffer (or separate part of the same buffer).

The problem with VBOs is that they are 1D arrays and don't allow striding. Using textures is a more flexible solution, but I shouldn't draw your attention from the most obvious and easier solution.

Alfonse Reinheart
08-07-2011, 03:05 PM
The problem with VBOs is that they are 1D arrays and don't allow striding.

What? Vertex attributes very much can have a stride.

Wasabi
08-07-2011, 03:31 PM
It is quite obvious that you cannot use vertices in the same form as before, but you have to reorder them (put colors at the back, for example), or create two separate buffers, and copy color attributes to one of them, and all other attributes to the other

When you say I can't use vertices in the same form, do you mean I need to break up my NVertex class into separate parts? That is, instead of having a single NVertex array, have two arrays, one each of... NVertexGeometry and NVertexColors?

How else can I copy different parts of the object to different buffers?

If I do something like

NVertex* vertexes;
glBufferData(GL_ARRAY_BUFFER, fault->GetMesh().Size(), vertexes->Geometry(), GL_STATIC_DRAW);
I'll only get the geometry of the first element of the array, of course.

Will I have to create an NMesh (the class which contains the array of vertexes) function which compiles the geometry of all the vertexes? Or, as stated above, will I have to split the NVertex array into two different class arrays, one holding the position and normal of the vertexes and the other holding the colors?

Aleksandar
08-07-2011, 03:46 PM
What? Vertex attributes very much can have a stride.

You didn't understand me. Of course that attributes have offsets, but you cannot update, for example 16B, then jump 128B, and again update 16B etc. There is no function that can update VBO using a stride.


When you say I can't use vertices in the same form, do you mean I need to break up my NVertex class into separate parts? That is, instead of having a single NVertex array, have two arrays, one each of... NVertexGeometry and NVertexColors?That is not a split class, just using two attributes (arrays) for different VBOs contents. It is a quite feasible solution. Or you can have a single physical (continuous) array in the main memory, but two pointers. One to the beginning and the other where color attribute values start.

For the update use glBufferSubData(), not glBufferData().