|
|
(3 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
| {{infobox feature
| | #REDIRECT [[Vertex Specification#Vertex Array Object]] |
| | core = 3.0
| |
| | core_extension = [http://www.opengl.org/registry/specs/ARB/vertex_array_object.txt ARB_Vertex_Array_Object]}}
| |
| | |
| '''Vertex Array Objects''' (VAO) are [[OpenGL Objects]] that store the set of bindings between [[Vertex Attributes]] and the user's source vertex data.
| |
| | |
| == VAO State ==
| |
| | |
| Vertex Array Objects are subject to a degree of misunderstanding, primarily due to the way that [[Vertex Buffer Objects]] are associated with vertex attributes. | |
| | |
| VAOs are a collection of state, like all OpenGL Objects. Unlike [[Textures|texture objects]] or [[Buffer Objects]], VAOs are pure state objects; they do not contain any large blocks of data or anything.
| |
| | |
| If you were to define the VAO state in terms of a C structs, it would look like the following:
| |
| | |
| <source lang="cpp">
| |
| struct VertexAttribute
| |
| {
| |
| bool bIsEnabled = GL_FALSE;
| |
| int iSize = 4; //This is the number of elements in this attribute, 1-4.
| |
| unsigned int iStride = 0;
| |
| VertexAttribType eType = GL_FLOAT;
| |
| bool bIsNormalized = GL_FALSE;
| |
| bool bIsIntegral = GL_FALSE;
| |
| void * pBufferObjectOffset = 0;
| |
| BufferObject * pBufferObj = 0;
| |
| };
| |
| | |
| struct VertexArrayObject
| |
| {
| |
| BufferObject *pElementArrayBufferObject = NULL;
| |
| VertexAttribute attributes[GL_MAX_VERTEX_ATTRIB];
| |
| }
| |
| </source>
| |
| | |
| The values given in the struct, the ones to the right of the "=", represent the default state of a newly-created VAO.
| |
| | |
| : '''Legacy Note''': In contexts where the fixed-function pipeline is still available, VAOs can still be used. They simply store more attributes, namely the fixed-function attributes set up by commands like <code>glVertexPointer</code>, <code>glNormalPointer</code> and so forth. So the VAO struct in the above pseudo-code example would have additional VertexAttribute objects stored in it. Similarly, compatibility mode allows pBufferObjectOffset to be a client pointer; whether it is a client pointer or a buffer object offset depends on whether a buffer object is in <code>pBufferObj</code>.
| |
| | |
| === Semantics ===
| |
| | |
| So what does all of this state mean?
| |
| | |
| Let us say that you are issuing a <code>glDrawElements</code> command while a particular VAO is bound. In our pseudo-code, let us say that the VAO binding is called <code>pVAO</code>. Here is what will happen, relative to our pseudo-code definition.
| |
| | |
| The <code>pVAO->pElementArrayBufferObject</code> is the buffer object from which vertex indices will be pulled. If this is NULL (ie: bound to zero), an error is raised: you can use <code>glDrawArrays</code>, but not <code>glDrawElements</code> without an element buffer.
| |
| | |
| If attribute index zero is not enabled (<code>pVAO->attributes[0].bIsEnabled == GL_FALSE</code>), an error is raised; attribute index 0 must always be enabled in a VAO you render with.
| |
| | |
| For each attribute ''i'' for which <code>pVAO->attributes[i].bIsEnabled == GL_TRUE</code>, the buffer object (<code>pBufferObj</code>) will be read starting at the offset value (<code>pBufferObjectOffset</code>), with the given stride (<code>iStride</code>) for each element and of the given number of fields and type components (<code>iSize</code> and <code>eType</code>). One value is read from all of the enabled attributes for each index from the element array buffer. The assemblage of attributes for a single index from the element array buffer constitutes a single vertex, and will be passed along for vertex processing.
| |
| | |
| A more detailed look at how rendering from VAO state works is in the article on [[Vertex Specification]].
| |
| | |
| == VAO Functions ==
| |
| | |
| As with all standard OpenGL Objects, when a VAO is bound to the context, all functions that modify these state fields will modify them for this object.
| |
| | |
| The <code>VertexArrayObject::pElementArrayBufferObject</code> is controlled by the binding of GL_ELEMENT_ARRAY_BUFFER. Calling <code>void glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObj)</code> will set this field of the VAO.
| |
| | |
| The <code>VertexAttribute::bIsEnabled</code> field is set by {{code|glEnableVertexAttribArray(attribIndex)}} and {{code|glDisableVertexAttribArray(attribIndex)}}, for the given attribute index.
| |
| | |
| The other vertex attribute state is governed by two functions:
| |
| | |
| void VertexAttribPointer( GLuint ''index'', GLint ''size'', GLenum ''type'',
| |
| GLboolean ''normalized'', GLsizei ''stride'', const void *''offset'');
| |
| void VertexAttribIPointer( GLuint ''index'', GLint ''size'', GLenum ''type'',
| |
| GLsizei ''stride'', const void *''offset'' );
| |
| | |
| You may notice that neither of these functions takes a buffer object name. This is because they attach the buffer object implicitly. Rather than having these functions take a buffer object directly, they simply use whatever buffer object is currently bound to GL_ARRAY_BUFFER. Thus, before calling either of these functions, the user should call <code>glBindBuffer(GL_ARRAY_BUFFER, bufferObj)</code> with the buffer of interest for this attribute.
| |
| | |
| : '''Note:''' Changing the GL_ARRAY_BUFFER binding does ''not'' affect VAO state. This is different from the GL_ELEMENT_ARRAY_BUFFER binding, which is directly part of VAO state. It is only when calling one of these two functions that the GL_ARRAY_BUFFER binding matters to the VAO.
| |
| | |
| The same buffer object can be used by multiple attributes. This is perfectly legitimate and can result in faster performance. Depending on the vertex data, of course.
| |
| | |
| These functions will cause the <code>index</code> attribute to be modified. In terms of our pseudo-code example, the parameters are equivalent to the state as follows:
| |
| | |
| iSize <= size
| |
| iStride <= stride
| |
| eType <= type
| |
| bIsNormalized <= normalized
| |
| pBufferObjectOffset <= offset
| |
| pBufferObj <= current GL_ARRAY_BUFFER binding
| |
| | |
| The {{code|offset}} parameter is technically a pointer in {{code|glVertexAttribPointer}} calls. It is however interpreted as a byte-offset into the buffer object that is currently bound to GL_ARRAY_BUFFER. To call this function, you have to perform a cast operation:
| |
| | |
| <source lang="cpp">
| |
| glVertexAttribPointer(..., (void*)(byte_offset));
| |
| </source>
| |
| | |
| Where {{code|byte_offset}} is an integer.
| |
| | |
| The "IPointer" version of the function is used to create integral attributes. Thus, when you use this function, <code>VertexAttribute::bIsIntegral</code> is automatically set to GL_TRUE. Similarly, when you use the other function, it is set to GL_FALSE. Since integral attributes cannot be normalized (as attribute normalization makes no sense when applied to integral attributes), this function does not have a ''normalized'' field.
| |
| | |
| It is perfectly legal to call these functions ''before'' calling the enable/disable functions.
| |
| | |
| These are the only functions that affect VAO state.
| |
| | |
| === Double-precision attributes ===
| |
| | |
| OpenGL 4.1, and implementations that support the [http://www.opengl.org/registry/specs/ARB/vertex_attrib_64bit.txt GL_ARB_vertex_attrib_64bit extension], allow the use of double-precision vertex attributes.
| |
| | |
| All vertex attribute functions previously discussed set the {{code|bIsDouble}} field to GL_FALSE. The only way to specify a double-precision attribute is with this new function:
| |
| | |
| void VertexAttribLPointer( GLuint ''index'', GLint ''size'', GLenum ''type'',
| |
| GLsizei ''stride'', const void *''offset'' );
| |
| | |
| The ''type'' field must be GL_DOUBLE. The rest work as expected. Using this function sets {{code|bIsDouble}} to GL_TRUE. If this function is used, the user must be using a `double` or `dvec` attribute type in the vertex shader.
| |
| | |
| == Legacy ==
| |
| | |
| {{deprecated}}
| |
| | |
| If you are not using shaders (or using a form of shader that doesn't accept [[GLSL]]'s generic attributes), there are a number of alternate functions for setting the non-generic vertex attributes.
| |
| | |
| VAOs encapsulate the non-generic attribute data as well. <code>glEnableClientState</code> and <code>glDisableClientState</code> function like <code>glEnableVertexAttrib</code> and <code>glDisableVertexAttrib</code>, except for non-generic attributes.
| |
| | |
| Texture coordinates are access a bit differently. There is only one texture coordinate setup function, <code>glTexCoordPointer</code>, and it only works for one texture coordinate. You can change which coordinate this function modifies by calling <code>glClientActiveTexture</code> with the texture index you wish to use. This function also controls which texture gets enabled/disable with <code>glEnableClientState</code> and <code>glDisableClientState</code>.
| |
| | |
| Overall, the gl*Pointer calls take the same parameters as <code>glVertexAttribPointer</code>, but there are some differences. None of the non-generic vertex arrays can feed an integral attribute, so there is no equivalent to <code>glVertexAttribIPointer</code>. And some of these functions are missing some fields compared to <code>glVertexAttribPointer</code>, because these fields are assumed to be a certain value. They also usually lack an explicit "normalize" field; the values are normalized or not intrinsically.
| |
| | |
| Table 2.5 in the OpenGL 3.2 compatibility specification details what the restrictions are on these functions.
| |
| | |
| == See Also ==
| |
| | |
| * [[Vertex Specification]]
| |
| * [[Vertex Attributes]]
| |
| | |
| == Reference ==
| |
| | |
| * [[:Category:Core API Ref Vertex Arrays]]: Function documentation for all functions that affect VAOs and VAO state.
| |
| | |
|
| |
|
| [[Category:Vertex Specification]] | | [[Category:Vertex Specification]] |
| [[Category:Objects]] | | [[Category:Objects]] |