How it works...

Phew! This seems like a lot of work! However, the real advantage comes when using multiple programs where the same buffer object can be used for each program. Let's take a look at each step individually.

First, we get the index of the uniform block by calling glGetUniformBlockIndex, then we query for the size of the block by calling glGetActiveUniformBlockiv. After getting the size, we allocate a temporary buffer named blockBuffer to hold the data for our block.

The layout of data within a uniform block is implementation-dependent, and implementations may use different padding and/or byte alignment. So in order to accurately lay out our data, we need to query for the offset of each variable within the block. This is done in two steps. First, we query for the index of each variable within the block by calling glGetUniformIndices. This accepts an array of the names variable (third argument) and returns the indices of the variables in the indices array (fourth argument). Then, we use the indices to query for the offsets by calling glGetActiveUniformsiv. When the fourth argument is GL_UNIFORM_OFFSET, this returns the offset of each variable in the array pointed to by the fifth argument. This function can also be used to query for the size and type, however, in this case we choose not to do so in order to keep the code simple (albeit less general).

The next step involves filling our temporary buffer, blockBufferwith the data for the uniforms at the appropriate offsets. Here, we use the standard library function, memcpyto accomplish this.

Now that the temporary buffer is populated with the data with the appropriate layout, we can create our buffer object and copy the data into the buffer object. We call glGenBuffers to generate a buffer handle, and then bind that buffer to the GL_UNIFORM_BUFFER binding point by calling glBindBuffer. The space is allocated within the buffer object and the data is copied when glBufferData is called. We use GL_DYNAMIC_DRAW as the usage hint here because uniform data may be changed somewhat often during rendering. Of course, this is entirely dependent on the situation.

Finally, we associate the buffer object with the uniform block by calling glBindBufferBase. This function binds to an index within a buffer binding point. Certain binding points are also called indexed buffer targets. This means that the target is actually an array of targets, and glBindBufferBase allows us to bind to one index within the array. In this case, we bind it to the index that we specified in the layout qualifier in the fragment shader: layout (binding = 0) (see Getting ready). These two indices must match.

You might be wondering why we use glBindBuffer and glBindBufferBase with GL_UNIFORM_BUFFER. Aren't these the same binding points used in two different contexts? The answer is that the GL_UNIFORM_BUFFER point can be used in each function with a slightly different meaning. With glBindBuffer, we bind to a point that can be used for filling or modifying a buffer, but can't be used as a source of data for the shader. When we use glBindBufferBase, we are binding to an index within a location that can be directly sourced by the shader. Granted, that's a bit confusing.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.83.150