Using uniform variables with shaders

Uniform variables present a way to pass variables from the application into GLSL shaders. However, you are limited to pass numerical values, vectors, and matrices only.

The dynamic rendering pipeline doesn't use immediate mode functions to set up vertices or matrices. This means functions such as gl.Vertex, gl.Rotate, gl.Translate, and gl.Scale are of no use anymore. For this situation, vertices are stored in vertex buffers. Other variables such as model view and projection matrix have to be supplied by uniform variables. These variables are also used often to set up or change the behavior of the shader program during runtime. For example, you can adjust the glowing effect amount in your shader program.

Getting ready

Each uniform variable has its own numerical location identifier. This identifier is used to access almost any uniform variable. The location identifier is limited to primitive values such as integer, float, and vectors. Matrices present a special case where you can upload the whole matrix in one step, but you can retrieve only one element from the shader program at one time. You can obtain a uniform variable location with the gl.GetUniformLocation function. There are three ways to use this function:

  • The location of a single primitive value:
    local location = gl.GetUniformLocation(shader_program, "variable_name")
  • The location of an array element:
    local location = gl.GetUniformLocation(shader_program, "array_variable[1]")
  • The location of a structure element:
    local location = gl.GetUniformLocation(shader_program, "structure_variable.element")

Let's assume that shader_program is the valid identifier for the shader program. This function returns the location identifier of the specified uniform variable. If such a variable doesn't exist in the shader program or is discarded in the process of compilation, the returned value is -1. The uniform variable is discarded if it isn't actively used in the shader program.

How to do it…

Now that you've got the location of the uniform variable, you can either set the content of the uniform variable or obtain its value.

Writing into uniform variables

You can set the uniform variable by one of these three functions: gl.Uniformi, gl.Uniformf, and gl.UniformMatrix. The first one is used in integer values, the second is for float number, and the last one is for matrices.

Both gl.Uniformi and gl.Uniformf accept two to five parameters. The first one is always the location of the uniform variable. The second one can be a primitive numeric value or Lua table. Lua tables are usually used for vectors. The following examples show how to set a primitive float number and a vector of floats:

local primitive_value = 1.5
local vector = {1.0, 2.0, 3.0}
gl.Uniformf(location, primitive_value)
gl.Uniformf(location, vector[1], vector[2], vector[3])
gl.Uniformf(location, vector)

Setting up matrices is a bit more difficult. Matrix values have to be stored in a flat Lua table. Matrix sizes can vary from 2 x 2 to 4 x 4 elements. You can also let the gl.UniformMatrix function to transpose your matrix. It means that matrix rows will be swapped with matrix columns. This is useful if you're supplying matrices that consist of multiple vectors. The following example shows how to upload the whole matrix of size 4 x 4:

local x,y,z = 1,2,3
local translation = {
  1, 0, 0, x,
  0, 1, 0, y,
  0, 0, 1, z,
  0, 0, 0, 1,
}
local rows, columns = 4, 4
local transpose = false
gl.UniformMatrix(location, translation, rows, columns, transpose)

Reading from uniform variables

Uniform variables can be read from shader programs with the gl.GetUniform functions. There are four versions of this function. One for each type of value: integer, unsigned integer, float, and double. Each of these functions can return one or more variables as return values. This depends on whether the queried variable is a primitive type such as a float, an integer, or a vector. The following table lists all the versions of the gl.GetUniform function:

Function names

Return types

gl.GetUniformi

Integer

gl.GetUniformui

Unsigned integer

gl.GetUniformf

Float

gl.GetUniformd

Double

Generic function specification accepts two arguments:

gl.GetUniform(shader_program, location)

For example, if you'd want to obtain a 3D vector from the shader program, you'd use the following code:

local x,y,z = gl.GetUniformf(shader_program, location)

All three variables would be filled with vector variable content.

How it works…

Uniform variables are available for all parts of the shader program. For instance, you can access the same uniform variable from the vertex and fragment shaders. You should always try to minimize the amount of uniform variable updates. Every update consumes a small part of bandwidth between CPU memory and GPU memory.

..................Content has been hidden....................

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