MULTIMEDIA

Open GL : Storing Transformed Vertices—Transform Feedback (part 1)

10/17/2012 4:17:09 AM
In OpenGL, it is possible to save the results of the vertex or geometry shader into a buffer object. This is a feature known as transform feedback. When transform feedback is used, a specified set of attributes output from the vertex shader or geometry shader are written into a buffer. When no geometry shader is present (remember, geometry shaders are optional), the data comes from the vertex shader. When a geometry shader is present, the vertices generated by the geometry shader are recorded. The buffers used for capturing the output of vertex and geometry shaders are known as transform feedback buffers. Once data has been placed into a buffer using transform feedback, it can be read back using a function like glGetBufferSubData or by mapping it into the application’s address space using glMapBuffer and reading from it directly. It can also be used as the source of data for subsequent drawing commands.

Transform Feedback

Transform feedback is a special mode of OpenGL that allows the results of a vertex or geometry shader to be saved into a buffer. Once the information is present in the buffer, it can be used as a source of vertex data for more drawing commands. Any attribute output from the vertex or geometry shader can be stored into the buffers. However, you can’t simultaneously record the output of the vertex shader and the geometry shader. If a geometry shader is active, only the output of the geometry shader is accessible. If you need the raw data from the vertex shader, you need to pass it through the geometry shader unmodified. The position of transform feedback is illustrated in Figure 1.

Figure 1. Schematic of the OpenGL pipeline, including transform feedback.

As you can see, transform feedback buffers sit between the output of the geometry shading and vertex assembly stages. As the geometry shader is an optional stage, if it is not present, the data actually comes from the vertex shader—this is denoted by dotted lines. Although the diagram shows transform feedback buffers feeding the vertex assembly stage, this is only to illustrate the feedback loop that is created (hence the term, transform feedback). While OpenGL will allow you to bind the same buffer as a transform feedback buffer and as a vertex buffer simultaneously, the results will not be defined if you do this, and you almost certainly won’t get what you wanted.

The set of vertex attributes, or varyings, to be recorded during transform feedback mode is specified using

void glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar ** varyings, GLenum bufferMode);

					  

The first parameter to glTransformFeedbackVaryings is the name of a program object. The transform feedback varying state is maintained per program object. This means that different programs can record different sets of vertex attributes, even if the same vertex or geometry shaders are used in them. The second parameter is the number of varyings to record and is also the length of the array whose address is given in the third parameter. This third parameter is simply an array of C-style strings giving the names of the varyings to record. These are the names of the out variables in the vertex or geometry shader. Finally, the last parameter specifies the mode in which the varyings are to be recorded. This must be either GL_SEPARATE_ATTRIBS or GL_INTERLEAVED_ATTRIBS. If bufferMode is GL_INTERLEAVED_ATTRIBS, the varyings are recorded into a single buffer, one after another. If bufferMode is GL_SEPARATE_ATTRIBS, each of the varyings is recorded into its own buffer.

Consider the following piece of vertex shader code, which declares the output varyings:

out vec4 vs_position_out;
out vec4 vs_color_out;
out vec3 vs_normal_out;
out vec3 vs_binormal_out;
out vec3 vs_tangent_out;

To specify that the varyings vs_position_out, vs_color_out, and so on should be written into a single interleaved transform feedback buffer, the following C code could be used in your application:

static const char * varying_names[] =
{
    "vs_position_out",
    "vs_color_out",
    "vs_normal_out",
    "vs_binormal_out",
    "vs_tangent_out"
};
glTransformFeedbackVaryings(program, 5, varying_names,
                            GL_INTERLEAVED_ATTRIBS);

Not all of the outputs from your vertex (or geometry) shader need to be stored into the transform feedback buffer. It is possible to save a subset of the vertex shader outputs to the transform feedback buffer and send more to the fragment shader for interpolation. Likewise, it is also possible to save some outputs from the vertex shader into a transform feedback buffer that are not used by the fragment shader. Because of this, outputs from the vertex shader that may have been considered inactive (because they’re not used by the fragment shader) may become active due to their being stored in a transform feedback buffer. Therefore, after specifying a new set of transform feedback varyings by calling glTransformFeedbackVaryings, it is necessary to link the program object using

glLinkProgram(program);

Once the transform feedback varyings have been specified and the program has been linked, it may be used as normal. Before actually capturing anything, you need to bind a buffer object as the transform feedback buffer. When you have specified the transform feedback mode as GL_INTERLEAVED_ATTRIBS, all of the stored vertex attributes are written one after another into a single buffer. To specify this buffer, call

glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);

Here, GL_TRANSFORM_FEEDBACK_BUFFER tells OpenGL that we want to bind a buffer to be used to store the results of the vertex or geometry shader to the GL_TRANSFORM_FEEDBACK_BUFFER binding point. The second parameter is the name of the buffer object that we previously created with a call to glGenBuffers.

Before any data can be written to a buffer, space must be allocated in the buffer for it. To allocate space without specifying data, call

glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, size, NULL, GL_DYNAMIC_COPY);

The first parameter is the buffer to allocate space for. You can use any buffer binding you like just for the purpose of binding a buffer and allocating space for it. However, OpenGL might make assumptions about what the buffer is going to be used for based on the first binding point it is bound to, and so, especially if this is a new buffer, the GL_TRANSFORM_FEEDBACK_BUFFER binding point is a good choice. The size parameter specifies how much space you want to allocate in bytes. This is up to your application’s needs, but if, during transform feedback, too much data is generated to fit into the buffer, the excess will be thrown away. NULL tells OpenGL that no data is being given that you only want to allocate space for later. The last parameter, usage, gives OpenGL a hint as to what you plan to do with the buffer.

There are many possible values for usage, but GL_DYNAMIC_COPY is probably a good choice for a transform feedback buffer. The DYNAMIC part tells OpenGL that the data is likely to change often but will likely be used a few times between each update. The COPY part says that you plan to update the data in the buffer through OpenGL functionality (such as transform feedback) and then hand that data back to OpenGL for use in another operation (such as drawing). 

To specify which buffer the transform feedback data will be written to, you need to bind a buffer to one of the indexed transform feedback binding points. There are actually multiple GL_TRANSFORM_FEEDBACK_BUFFER binding points for this purpose, which are conceptually separate, but related to the general binding GL_TRANSFORM_FEEDBACK_BUFFER binding point. A schematic of this is shown in Figure 2.

Figure 2. Relationship of transform feedback binding points.


To bind a buffer to any of the indexed binding points, call

glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, index, buffer);

As before, GL_TRANSFORM_FEEDBACK_BUFFER tells OpenGL that we’re binding a buffer object to store the results of transform feedback, and the last parameter, buffer, is the name of the buffer object we want to bind. The extra parameter, index, is the index of the GL_TRANSFORM_FEEDBACK_BUFFER binding point. An important thing to note is that there is no way to directly address any of the extra binding points provided by glBindBufferBase through functions like glBufferData or glCopyBuffer. However, when you call glBindBufferBase, it actually binds the buffer to the indexed binding point and to the generic binding point. Therefore, you can use the extra binding points to allocate space in the buffer if you access the general binding point right after calling glBindBufferBase.

A slightly more advanced version of glBindBufferBase is glBindBufferRange, whose prototype is

void glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);

					  

The glBindBufferRange function allows you to bind a section of a buffer to an indexed binding point, whereas glBindBuffer and glBindBufferBase can only bind the whole buffer at once. The first three parameters (target, index, and buffer) have the same meanings as in glBindBufferBase. The offset and size parameters are used to specify the start and length of the section of the buffer that you’d like to bind, respectively. You can bind different sections of the same buffer to several different indexed binding points simultaneously. This enables you to use transform feedback in GL_SEPARATE_ATTRIBS mode to write each attribute of the output vertices into separate sections of a single buffer. If your application packs all attributes into a single vertex buffer and uses glVertexAttribPointer to specify nonzero offsets into the buffer, this allows you to make the output of transform feedback match the input of your vertex shader.

If you specified that all of the attributes should be recorded into a single transform feedback buffer by using the GL_INTERLEAVED_ATTRIBS parameter to glTransformFeedbackVaryings, the data will be written into the buffer bound to the first GL_TRANSFORM_FEEDBACK_BUFFER binding point (that with index zero). However, if you specified that the mode for transform feedback is GL_SEPARATE_ATTRIBS, each output from the vertex shader will be recorded into its own separate buffer (or section of a buffer, if you used glBindBufferRange). In this case, you need to bind multiple buffers or buffer sections as transform feedback buffers. The index parameter must be between zero and one less than the maximum number of varyings that can be recorded into separate buffers using transform feedback mode. This limit depends on your graphics hardware and drivers and can be found by calling glGetIntegerv with the GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS parameter. This limit is also applied to the count parameter to glTransformFeedbackVaryings.

There is no upper limit on the number of separate varyings that can be written to transform feedback buffers in GL_INTERLEAVED_ATTRIBS mode, but there is a maximum number of components that can be written into a buffer. For example, it is possible to write more vec3s than vec4s into a buffer using transform feedback. Again, this limit depends on your graphics hardware and can be found using glGetIntegerv with the GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS parameter.

It is not possible to write one set of output varyings interleaved into one buffer while writing another set of attributes into another buffer. When transform feedback is active, the output varyings are either all stored, interleaved into one buffer, or stored packed into several different buffers or sections of buffers. Therefore, if you plan to use transform feedback to generate vertex data for subsequent passes, you need to consider this when you plan your input vertex layout. The vertex shader is generally a little more flexible in the way that it is able to read vertex data than in the way data can be written through transform feedback.

Once the buffers that are to receive the results of the transform feedback have been bound, transform feedback mode is activated by calling

void glBeginTransformFeedback(GLenum primitiveMode);

Now whenever vertices pass through a vertex or geometry shader, output varyings from the later shader will be written to the transform feedback buffers. The parameter to the function, primitiveMode, tells OpenGL what types of geometry to expect. The acceptable parameters are GL_POINTS, GL_LINES, or GL_TRIANGLES. When you call glDrawArrays or another OpenGL drawing function, the basic geometric type must match what you have specified as the transform feedback primitive mode, or you must have a geometry shader that outputs the appropriate primitive type. For example, if primitiveMode is GL_TRIANGLES, you must call glDrawArrays with GL_TRIANGLES, GL_TRIANGLE_STRIP, or GL_TRIANGLE_FAN, or you must have a geometry shader that produces GL_TRIANGLE_STRIP primitives. The mapping of transform feedback primitive mode to draw types is shown in Table 1.

Table 1. Values for primitiveMode
Value of PrimitiveModeAllowed Draw Types
GL_POINTSGL_POINTS
GL_LINESGL_LINES, GL_LINE_STRIP, GL_LINE_LOOP
GL_TRIANGLESGL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN

Vertices are recorded into the transform feedback buffers until transform feedback mode is exited or until the space allocated for the transform feedback buffers is exhausted. To exit transform feedback mode, call

glEndTransformFeedback();

All rendering that occurs between a call to glBeginTransformFeedback and glEndTransformFeedback results in data being written into the currently bound transform feedback buffers. Each time glBeginTransformFeedback is called, OpenGL starts writing data at the beginning of the buffers bound for transform feedback, overwriting what might be there already. Some care should be taken while transform feedback is active as changing transform feedback state between calls to glBeginTransformFeedback and glEndTransformFeedback is not allowed. For example, it’s not possible to change the transform feedback buffer bindings or to resize or reallocate any of the transform feedback buffers while transform feedback mode is active.

Other  
 
Video tutorials
- How To Install Windows 8 On VMware Workstation 9

- How To Install Windows 8

- How To Install Windows Server 2012

- How To Disable Windows 8 Metro UI

- How To Change Account Picture In Windows 8

- How To Unlock Administrator Account in Windows 8

- How To Restart, Log Off And Shutdown Windows 8

- How To Login To Skype Using A Microsoft Account

- How To Enable Aero Glass Effect In Windows 8

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen
programming4us programming4us
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th