PDA

View Full Version : Uniform Buffer Object question



McLeary
02-26-2011, 08:08 AM
I'm trying to understand what Uniform Buffer Objects (UBO) are. I read the UBO Wiki Page and what I understood was that UBO can only be used to change data of an uniform block.

The problem I am facing is that I need an uniform variable for each face I am drawing. This can be easily accomplished using the immediate drawing style, but since this is the slower mode to draw something I trying to use a buffer array with uniform values.

Another question, it is possible to force any varying variable to not be interpolated from vertex to fragment shader?

ZbuffeR
02-26-2011, 10:25 AM
For the first question, you should send data per vertex, as classic varying (that what happens in immediate mode anyway).
For the second question, you can define a vertex shader output or fragment shader input as 'flat', meaning no interpolation occurs.

Red_Riot
03-09-2011, 07:55 PM
UBOs are basically data sets that get uploaded to the GPU for easy access by the GPU so it doesn't have to deal with a data transfer from the CPU to the GPU. It can just draw from a local resource 'server' instead of having to get a data transfer from the OpenGL API or the 'client'

specifically, sounds like you're using named uniform blocks backed by a UNIFORM_BUFFER

Sounds like you're using uniforms on the Geometry layer however, which I'm inexperience with. =(

You know how to load them into a buffer and the shader though correct?

McLeary
03-09-2011, 08:02 PM
Actually I solved this problem using vertex attributes buffer. Uniform variables can be set only once per shader execution. One can define a buffer of vertex attributes and use glVertexAttribPointer() to pass one attrib for each vertex.

Red_Riot
03-10-2011, 03:40 PM
UBOs are typically associated with a named uniform block, which looks like this in GLSL version 150 (and 140+ i think, I'm not completely sure what version introduced what)

uniform nameBlock
{
vec3 trans;
vec4 proj;
vec4 quat;
vec3 cquat;
};

when linked to GLSL, the shader program will draw values from the buffer associated with these variables. This is nice because the variables are already on the GPU via the buffer.

So using a VBO and a named uniform buffer has a few steps:
-declare the named buffer in the shader program ("nameBlock")
-get info about the block in your OpenGL API
-make an appropriate buffer for the named buffer
-link the shader program to the buffer object.

Here's an example:
// char array of the variable names in my shader program
const GLchar* names[] = {"trans", "proj", "quat", "cquat"};
GLint uniActive; // how many active variables are in my shader program

// get block information
uniBlockID = glGetUniformBlockIndex(shader_Prog, "nBlock"); // get the named block ID
glGetActiveUniformBlockiv(shader_Prog, uniBlockID, GL_UNIFORM_BLOCK_BINDING,
&uniBlockBind); // get the named block binding
glGetActiveUniformBlockiv(shader_Prog, uniBlockID, GL_UNIFORM_BLOCK_DATA_SIZE,
&uniBlockSize); // get the named block size (in bytes)
glGetActiveUniformBlockiv(shader_Prog, uniBlockID, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
&uniActive); // get how many active uniforms are in the block, all uniforms in a block are considered active by default

// get the index of the uniforms
GLuint *uniIndex = new GLuint[uniActive];
glGetUniformIndices(shader_Prog, uniActive, names, uniIndex);

uniBufferOffset = new GLint[uniActive];
// NOTE: THIS IS COMPLETELY DIFFERENT THAN THE INDEX OF THE UNIFORMS WITHIN THE NAMED BUFFER (which are mostly likely 0,1,2,3 ect in order)
glGetActiveUniformsiv(shader_Prog, uniActive, uniIndex, GL_UNIFORM_OFFSET, uniBufferOffset);
// this gets the index of the uniform variables in your program and then sets an offset for how far in the data for each variable is. data is typically packed in block sof 16 bytes, so even if it's one float, you'll probably be indexed 16 bytes to the next uniform even if the previous only used 1 or 4 or whatever. offset[0] will be for your first variable, in the example 'trans' and offset[1] for the next, or proj


// now that we k now the data, make a buffer for us
glGenBuffers(1, &id_UniBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, id_UniBuffer);
GLfloat *nullData = new GLfloat[uniBlockSize / 4];
memset(nullData,0,uniBlockSize);
glBufferData(GL_UNIFORM_BUFFER, uniBlockSize, nullData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);

and lastly we have to link up the shader program with our buffer:

glUniformBlockBinding(shader_Prog, uniBlockID, uniBlockBind);
glBindBufferBase(GL_UNIFORM_BUFFER, uniBlockID, id_UniBuffer);

if i want to change data in the buffer for the appropriate offset, where uniBufferOffset[0] is my offset for 'trans'

GLfloat RGL_Translate[3];
glBufferSubData(GL_UNIFORM_BUFFER_EXT,uniBufferOff set[0],12,RGL_Translate);