HexoUniforms 2014-12-26
Uniforms pass data directly from appliaction into any shader stage.
Two flavors of uniforms:
- declared in the default block
- values are stored in buffer objects
Defalut Block Uniforms
A uniform is how we pass data into a shader that stays the same.
MOST COMMON UNIFORM
transformation matrix
Any shader variable can be specified as a uniform, and uniforms can be in any shader stages.
1 | uniform float fTime; |
Uniforms are always considered to be constant.
1 | uniform answer = 42; |
if you declare the same unifrom in multiple shader stages, each of those stages will see the same value of that uniform.
Arranging Your Uniforms
Your shader code by using a location layout qualifier.
1 | layout (location = 17) uniform vec4 myUniform; |
You can figure out what locations were assigned by calling the glGetUniformLocation()
1 | GLint glGetUniformLocation(GLuint program, |
Setting Scalars and Vector Uniforms
1 | glUniform?f(GLint, ...); |
? : 1 to 4
Setting Uniform Arrays
1 | glUniform??v(GLint location, GLuint count, const GLxxxx * value); |
Setting Uniform Matrices
1 | glUniformMatrix??v(GLint location, GLunit count, GLboolean transpose, const GLXXXXX * m); |
The Boolean flag transpose:
- matrix column-major -> GL_FALSE
- matrix row-major -> GL_TRUE
Uniform Blocks
To alleviate the cost of all the glUniform*() calls, OpenGL allows you to combine a group of uniforms into a uniform block and store the whole block in a buffer object.
You can’t keep the default bolck in a uniform buffer object; you need to creat one or more named uniform block.
1 | uniform TransformBlock |
Building Uniform Blocks
standard, agreed upon layout for the data.
1 | layout(std140) uniform TransformBlock |
Once a uniform block has ben decalred to use the stndard, or std140, layout, each member of the block consumes a predefined amount of space in the buffer and begins at an offset that is predictable by following a set of rules:
- Any type consuming N bytes in a buffer begins on a N-byte boundary within that buffer.
shared layout, let OpenGL decide where it would like the data.
You can determine the offsets that OpenGL assigned to your block members. Each member of a uniform block ahs an index that is used to efre to it to find its size and location within the block.
1 | void glGetUniformIndices(GLuint program, |
After you get the uniformIndices array, you have the indices, you can use them to find the location of the block members within the buffer.
1 | GLint uniformOffsets[4]; |
- unifomIndices contains the offsets of the members to the TransformBlock
- arrayStrides contains the strides of the array members(only rotaion, for now)
- matrixStrides contains the strides of the matrix members(only projection_matrix)
1 | unsigned char *buffer = (unsigned char *)malloc(4096); |
find a index of a uniform block in a program
1 | GLuint glGetUniformBlockIndex(GLuint program, |
two-step process to bind a buffer to a uniform block:
- Uniform blocks are assigned binding point
- buffers can be bound to those binding points
to assign a binding point to a uniform block:
1 | void glUniformBlockBinding(GLuint program, |
- uniformBlockIndex is the index of the uniform block you are assiging a binding point to. (call glGetUniformBlockIndex)
- uniformBlockBinding is the index of the uniform block binding point.
specify the binding index of your uniform blocks right in your shader code.
1 | layout(std140, binding = 2) uniform TransformBlock |
Assigning bindings in your shader code avoids the need to call glUniformBlockBinding()
1 | glBindBufferBase(GL_UNIFORM_BUFFER, index, buffer); |
- GL_UNIFORM_BUFFER tells OpenGl that we are binding a buffer to one of the uniform buffer binding point
- index is the index of the binding point and should match waht you specifed either in your shader
- buffer buffer is the name of the buffer object that you want to attach
index is not the index of the uniform block, but the index of the uniform buffer binding poing.
1 | GLuint harry_index = glGetUniformBlockIndex(program, "Harry"); |
1 | layout (binding = 1) uniform Harry |
the shader code is compiled and liked into ta program object, the bindings for the Harry, Bob, and Susan uniform blocks
will be set to the same thing as they would be after executing c code.
The reason of setting the uniform block binding in the shader
- reduces numbers call to OpenGL
- allows the shader to associate a uniform block with a binding point without the block name.
- separate steady state from transient state
- uniform blocks can be quite large
Using Unifroms to Transform Geometry
This is the classic spinnig cube demo:
- create a unit cube located at the origin and store it in buffer objects
- use a vertex shader to apply a sequence of transforms
- construct a basic view matrix, multiply our model and view matrices together to produce a model-view matrix
- create a prespective transformation matrix representing some of the properties of our camera
- pass these into a simple vertex shader using uniforms and draw the cube on the screen