Client-Side Vertex Arrays: Difference between revisions
Danielt998 (talk | contribs) mNo edit summary |
No edit summary |
||
(One intermediate revision by one other user not shown) | |||
Line 4: | Line 4: | ||
===Sample Code=== | ===Sample Code=== | ||
I suggest that you interleave your vertex attributes for best performance. The order of of attributes should not matter for performance because it's just a pointer to a memory location for the GPU. Futhermore, you should think of a vertex as not as just a position, but also all the other attributes that go along with it such as normal, texcoord0, texcoord1, texcoord2, color, tangent vectors and binormal vectors.<br> | I suggest that you interleave your vertex attributes for best performance. The order of of attributes should not matter for performance because it's just a pointer to a memory location for the GPU. Futhermore, you should think of a vertex as not as just a position, but also all the other attributes that go along with it such as normal, texcoord0, texcoord1, texcoord2, color, tangent vectors and binormal vectors.<br> | ||
Make a structure for your vertex attributes in your C++ code : | Make a structure for your vertex attributes in your C++ code: | ||
<source lang="cpp"> | |||
struct MyVertex | struct MyVertex | ||
{ | { | ||
float x, y, z; //Vertex | |||
float nx, ny, nz; //Normal | |||
float s0, t0; //Texcoord0 | |||
float s1, t1; //Texcoord1 | |||
float s2, t2; //Texcoord2 | |||
float padding[4]; | |||
}; | }; | ||
</source> | |||
Padding is added to make the vertex structure a multiple of 32 bytes since some GPUs prefer it that way, such as ATI/AMD. | Padding is added to make the vertex structure a multiple of 32 bytes since some GPUs prefer it that way, such as ATI/AMD. | ||
Create an array of vertices and fill your array. Of course, in a real program, you would read some file : | Create an array of vertices and fill your array. Of course, in a real program, you would read some file: | ||
<source lang="cpp"> | |||
MyVertex vertex[50]; | MyVertex vertex[50]; | ||
vertex[0].x=0.0; | vertex[0].x=0.0; | ||
Line 23: | Line 26: | ||
vertex[0].z=0.0; | vertex[0].z=0.0; | ||
and so on.... | and so on.... | ||
</source> | |||
Create an array of indices and setup your indices. Unsigned short is used (16 bit) since that is what most GPUs prefer. Some of them can deal with 32 bit indices as well.<br> | Create an array of indices and setup your indices. Unsigned short is used (16 bit) since that is what most GPUs prefer. Some of them can deal with 32 bit indices as well.<br> | ||
Don't use anything ridiculous like unsigned byte. | Don't use anything ridiculous like unsigned byte. | ||
<source lang="cpp"> | |||
ushort index[99]; | ushort index[99]; | ||
index[0]=0; | index[0]=0; | ||
index[1]=5; | index[1]=5; | ||
index[2]=3; | index[2]=3; | ||
and so on.... | // and so on.... | ||
</source> | |||
Call your gl***Pointer functions to make a INTERLEAVED ARRAY.<br> | Call your gl***Pointer functions to make a INTERLEAVED ARRAY.<br> | ||
Line 36: | Line 42: | ||
You may also need to call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) | You may also need to call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) | ||
<source lang="cpp"> | |||
glEnableClientState(GL_VERTEX_ARRAY); | glEnableClientState(GL_VERTEX_ARRAY); | ||
glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), &vertex[0].x); | glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), &vertex[0].x); | ||
Line 49: | Line 56: | ||
glEnableClientState(GL_TEXTURE_COORD_ARRAY); | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s2); | glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s2); | ||
</source> | |||
Now it's time to render. I have not included the part about setting up texture combiners, or shader, or binding shaders. | Now it's time to render. I have not included the part about setting up texture combiners, or shader, or binding shaders. | ||
<source lang="cpp"> | |||
glDrawRangeElements(GL_TRIANGLES, x, y, z, GL_UNSIGNED_SHORT, index); | glDrawRangeElements(GL_TRIANGLES, x, y, z, GL_UNSIGNED_SHORT, index); | ||
</source> | |||
x would be the very first index, which might be 0. y would be the last vertex which would be 49 (not 50!). z would the number of indices to be processed.<br> | x would be the very first index, which might be 0. y would be the last vertex which would be 49 (not 50!). z would the number of indices to be processed.<br> | ||
Line 69: | Line 79: | ||
In this one, we will make a vertex structure that hold XYZ position, texcoord0 and color (RGBA format). We will declare the color as a uint which in our case is a unsigned 32 bit integer. You should check your target format what type defines a unsigned 32 bit integer. It is a good idea to use RGBA instead of RGB because GPUs prefer to have all of the components. All the components for color make a nice 32 bit data block. We should also state that OpenGL has never up to this point supported the BGRA format for vertex colors. You will notice that glColorPointer doesn't take a format value such as GL_RGBA. It only accepts component values such as 4 in this case. | In this one, we will make a vertex structure that hold XYZ position, texcoord0 and color (RGBA format). We will declare the color as a uint which in our case is a unsigned 32 bit integer. You should check your target format what type defines a unsigned 32 bit integer. It is a good idea to use RGBA instead of RGB because GPUs prefer to have all of the components. All the components for color make a nice 32 bit data block. We should also state that OpenGL has never up to this point supported the BGRA format for vertex colors. You will notice that glColorPointer doesn't take a format value such as GL_RGBA. It only accepts component values such as 4 in this case. | ||
<source lang="cpp"> | |||
struct MyVertex | struct MyVertex | ||
{ | { | ||
float x, y, z; //Vertex | |||
float s0, t0; //Texcoord0 | |||
uint color; //RGBA color | |||
float padding[2]; | |||
}; | }; | ||
</source> | |||
Padding is added to make the vertex structure a multiple of 32 bytes since some GPUs prefer it that way, such as ATI/AMD. | Padding is added to make the vertex structure a multiple of 32 bytes since some GPUs prefer it that way, such as ATI/AMD. | ||
And the calls to the gl****Pointer functions would look like this | And the calls to the gl****Pointer functions would look like this | ||
<source lang="cpp"> | |||
glEnableClientState(GL_VERTEX_ARRAY); | glEnableClientState(GL_VERTEX_ARRAY); | ||
glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), &vertex[0].x); | glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), &vertex[0].x); | ||
Line 93: | Line 106: | ||
//OpenGL wants a component value. 4 in our case. | //OpenGL wants a component value. 4 in our case. | ||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyVertex), &vertex[0].color); | glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyVertex), &vertex[0].color); | ||
</source> | |||
In the above example, we disabled the normal array and some of the texcoord arrays. We enable the color array. | In the above example, we disabled the normal array and some of the texcoord arrays. We enable the color array. | ||
[[Category:Examples]] | [[Category:Examples]] | ||
[[Category:Deprecated]] | [[Category:Deprecated]] |
Latest revision as of 17:54, 2 January 2018
Before VBOs, there were plain old vertex arrays. This means that your vertices and vertex attributes and indices are in RAM.
Of course, this doesn't give the best performance since every time you want GL to draw, the driver has to upload the vertices to the GPU.
Sample Code
I suggest that you interleave your vertex attributes for best performance. The order of of attributes should not matter for performance because it's just a pointer to a memory location for the GPU. Futhermore, you should think of a vertex as not as just a position, but also all the other attributes that go along with it such as normal, texcoord0, texcoord1, texcoord2, color, tangent vectors and binormal vectors.
Make a structure for your vertex attributes in your C++ code:
struct MyVertex
{
float x, y, z; //Vertex
float nx, ny, nz; //Normal
float s0, t0; //Texcoord0
float s1, t1; //Texcoord1
float s2, t2; //Texcoord2
float padding[4];
};
Padding is added to make the vertex structure a multiple of 32 bytes since some GPUs prefer it that way, such as ATI/AMD.
Create an array of vertices and fill your array. Of course, in a real program, you would read some file:
MyVertex vertex[50];
vertex[0].x=0.0;
vertex[0].y=0.0;
vertex[0].z=0.0;
and so on....
Create an array of indices and setup your indices. Unsigned short is used (16 bit) since that is what most GPUs prefer. Some of them can deal with 32 bit indices as well.
Don't use anything ridiculous like unsigned byte.
ushort index[99];
index[0]=0;
index[1]=5;
index[2]=3;
// and so on....
Call your gl***Pointer functions to make a INTERLEAVED ARRAY.
Also, if you are using VBOs in some other part of your code, you would have to bind VBO 0 by calling glBindBuffer(GL_ARRAY_BUFFER, 0)
You may also need to call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), &vertex[0].x);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(MyVertex), &vertex[0].nx);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s0);
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s1);
glClientActiveTexture(GL_TEXTURE2);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s2);
Now it's time to render. I have not included the part about setting up texture combiners, or shader, or binding shaders.
glDrawRangeElements(GL_TRIANGLES, x, y, z, GL_UNSIGNED_SHORT, index);
x would be the very first index, which might be 0. y would be the last vertex which would be 49 (not 50!). z would the number of indices to be processed.
You might also want to read Vertex Formats
In summary:
- Make you vertex structure.
- Make it multiple of 32 bytes in size.
- Use 16 bit integer indices where reasonable.
- Try not to make many redundent calls to GL so that your performance stays the best.
- Don't use glInterleaved array because almost nobody uses it and it's limited. You can read about it here.
Sample Code 2
See Sample Code 1 for a more detailed description.
In this one, we will make a vertex structure that hold XYZ position, texcoord0 and color (RGBA format). We will declare the color as a uint which in our case is a unsigned 32 bit integer. You should check your target format what type defines a unsigned 32 bit integer. It is a good idea to use RGBA instead of RGB because GPUs prefer to have all of the components. All the components for color make a nice 32 bit data block. We should also state that OpenGL has never up to this point supported the BGRA format for vertex colors. You will notice that glColorPointer doesn't take a format value such as GL_RGBA. It only accepts component values such as 4 in this case.
struct MyVertex
{
float x, y, z; //Vertex
float s0, t0; //Texcoord0
uint color; //RGBA color
float padding[2];
};
Padding is added to make the vertex structure a multiple of 32 bytes since some GPUs prefer it that way, such as ATI/AMD.
And the calls to the gl****Pointer functions would look like this
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), &vertex[0].x);
glDisableClientState(GL_NORMAL_ARRAY);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s0);
glClientActiveTexture(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTexture(GL_TEXTURE2);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
//OpenGL wants a component value. 4 in our case.
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyVertex), &vertex[0].color);
In the above example, we disabled the normal array and some of the texcoord arrays. We enable the color array.