Wednesday, May 11, 2016

glVertexAttribPointer.Usage

Cited Tutorial

opengl.api

..
              : Define an array of generic vertex attribute data

        void glVertexAttribPointer(GLuint index
                                                        , GLint size
                                                        , GLenum type
                                                        , GLboolean normalized
                                                        , GLsizei stride
                                                        , const GLvoid * pointer
        );

        glVertexAttribPointer specifies the location and data format of the array of generic vertex attributes at index index to use when rendering.
...
[contents]

[STRIDE]

...
One important thing i changed in this tutorial is the format of data.
We don't have one VBO for vertices and one for texture coordinates,
but with each vertex,
we have three floats for vertex followed by two floats for texture coordinates.
After that we, just need to tell OpenGL, when calling glVertexAttribPointer(),
what's the distance between two consecutive attributes -the STRIDE- .
In this case, 
the distance between two consecutive vertex attributes is sizeof whole vertex data,
i.e. sizeof(vec3) + sizeof(vec2) -its 5 floats-.
...

Vertex buffer offset and stride

The vertex format information above tells OpenGL how to interpret the data. The format says how big each vertex is in bytes and how to convert it into the values that the attribute in the vertex shader receives 
But OpenGL needs two more pieces of information before it can find the data. 
It needs a byte offset from the start of the buffer object to the first element in the array. So your arrays don't always have to start at the front of the buffer object. 
It also needs a stride, which represents how many bytes it is from the start of one element to the start of another.  
The offset​​ defines the buffer object offset. Note that it is a parameter of type const void *​ rather than an integer of some kind. This is in part why it's called glVertexAttribPointer, due to old legacy stuff where this was actually a client pointer.  
offset..bytes- between ATTRIBUTES of each single...VERTEX...Data... 】
So you will need to cast the integer offset into a pointer. In C, this is done with a simple cast: (void*)(byteOffset)​. In C++, this can be done as such: reinterpret_cast<void*>(byteOffset)​.  
The stride​ is used to decide if there should be bytes between vertices. If it is set to 0, then OpenGL will assume that the vertex data is tightly packed. So OpenGL will compute the stride from the given other components. So if you set the size​ to be 3, and type​ to be GL_FLOAT, OpenGL will compute a stride of 12 (4 bytes per float, and 3 floats per attribute). 
stride..bytes- stride between VERTICES of the whole...VERTEX.Data...】 

Interleaved attributes

The main purpose of the stride​ attribute is to allow interleaving between different attributes. This is conceptually the difference between these two C++ definitions:
struct StructOfArrays
{
  GLfloat positions[VERTEX_COUNT * 3];
  GLfloat normals[VERTEX_COUNT * 3];
  GLubyte colors[VERTEX_COUNT * 4];
};

StructOfArrays structOfArrays;

struct Vertex
{
  GLfloat position[3];
  GLfloat normal[3];
  Glubyte color[4];
};

Vertex vertices[VERTEX_COUNT];
structOfArrays​ is a struct that contains several arrays of elements. Each array is tightly packed, but independent of one another. vertices​ is a single array, where each element of the array is an independent vertex.
If we have a buffer object which has had vertices​ uploaded to it, such that baseOffset​ is the byte offset to the start of this data, we can use the stride​ parameter to allow OpenGL to access it:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(baseOffset + offsetof(Vertex, position))); 
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(baseOffset + offsetof(Vertex, normal))); 
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), reinterpret_cast<void*>(baseOffset + offsetof(Vertex, color)));
Note that each attribute uses the same stride: the size of the Vertex​ struct. C/C++ requires that the size of this struct be padded where appropriately such that you can get the next element in an array by adding that size in bytes to a pointer (ignoring pointer arithmetic, which will do all of this for you). Thus, the size of the Vertex​ structure is exactly the number of bytes from the start of one element to another, for each attribute.
The macro offsetof​ computes the byte offset of the given field in the given struct. This is added to the baseOffset​, so that each field points to the start of its own data relative to the beginning of the Vertex​ structure.
As a general rule, you should use interleaved attributes wherever possible. Obviously if you need to change certain attributes and not others, then interleaving the ones that change with those that don't is not a good idea. But you should interleave the constant attributes with each other, and the changing attributes with those that change at the same time.

Submitting Vertex Data

Your application creates a vertex structure that holds all the elements for each vertex. For each element , you enable a client array and provide a pointer and offset to OpenGL so that it knows how to find those elements.

typedef struct _vertexStruct
{
    GLfloat position[2];
    GLubyte color[4];
} vertexStruct;
     void DrawGeometry()
     {
         const vertexStruct vertices[] = {...};
         const GLubyte indices[] = {...};
              glEnableClientState(GL_VETEX_ARRAY);
         glVertexPointer(2
                                  , gl_float
                                  , sizeof(vertexStruct)
                                  , &vertices[0].position
         );
         //
         glEnableClientState(GL_Color_Array);
         glColorPointer(4                                 , GL_Unsigned_Byte
                                 , sizeof(vertexStruct)
                                 , &vertices[0].color         );
 
         glDrawElements(GL_Triangle_Strip
                                    , sizeof(indices)/sizeof(GLubyte)                                    , GL_Unsigned_Byte                                    , indices         );
     }




Each time you call glDrawElements, OpenGL must copy all of the vertex data into the command buffer, which is later copied to the hardware. The copy overhead is still expensive.
...
[]
[]

[]
[]
[]








No comments:

Post a Comment