PDA

View Full Version : Uniforms



DreamCore
10-12-2013, 03:37 AM
Hi,

I am learning how to use Uniforms in OpenGL to provide data to my shaders. I have the following code (the forum decides to do some weird formatting in the code):


#include "sb6.h"
#include <vmath.h>
#include <math.h>
#include <stdlib.h>

using namespace sb6;

class my_application : public sb6::application
{
private:
GLuint buffers[2];
GLuint rendering_program;
GLuint vertex_array_object;

public:
void startup( void )
{
rendering_program = compile_shaders();
glGenVertexArrays(1, &vertex_array_object );
glBindVertexArray( vertex_array_object );

// Generate names for the two buffers
glGenBuffers( 2, buffers );

// The data used for vertex positions
static const float positions[] =
{
0.25, -0.25, 0.5, 1.0,
-0.25, -0.25, 0.5, 1.0,
0.25, 0.25, 0.5, 1.0
};

// The data used for vertex colors
static const float colors[] =
{
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0
};

// Bind the first attribute and initialize it
glBindBuffer( GL_ARRAY_BUFFER, buffers[ 0 ] );
glBufferData( GL_ARRAY_BUFFER, sizeof( positions ), positions, GL_STATIC_DRAW );
glVertexAttribPointer( 0, 4, GL_FLOAT, GL_FALSE, 0, NULL );
glEnableVertexAttribArray( 0 );

// Bind the second attribute and initialize it
glBindBuffer( GL_ARRAY_BUFFER, buffers[ 1 ] );
glBufferData( GL_ARRAY_BUFFER, sizeof( colors ), colors, GL_STATIC_DRAW );
glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 0, NULL );
glEnableVertexAttribArray( 1 );

// Get the indices of the uniform block
static const GLchar* uniformNames[ 4 ] =
{
"TransformBlock.scale",
"TransformBlock.translation",
"TransformBlock.rotation",
"TransformBlock.projection_matrix"
};
GLuint uniformIndices[ 4 ];
glGetUniformIndices( rendering_program, 4, uniformNames, uniformIndices );

// Find the locations of the uniform block members
GLint uniformOffsets[ 4 ];
GLint arrayStrides[ 4 ];
GLint matrixStrides[ 4 ];
glGetActiveUniformsiv( rendering_program, 4, uniformIndices, GL_UNIFORM_OFFSET, uniformOffsets );
glGetActiveUniformsiv( rendering_program, 4, uniformIndices, GL_UNIFORM_ARRAY_STRIDE, arrayStrides );
glGetActiveUniformsiv( rendering_program, 4, uniformIndices, GL_UNIFORM_MATRIX_STRIDE, matrixStrides );

// Allocate some memory for our buffer (don't forget to free it later)
unsigned char* buffer = ( unsigned char* ) malloc( 4096 );
memset( buffer, 0, sizeof( buffer ) );

// Store the scale in the buffer
*( ( float* )( buffer + uniformOffsets[ 0 ] ) ) = 3.0f;

// Store the translation in the buffer
( ( float* )( buffer + uniformOffsets[ 1 ] ) )[ 0 ] = 1.0f;
( ( float* )( buffer + uniformOffsets[ 1 ] ) )[ 1 ] = 2.0f;
( ( float* )( buffer + uniformOffsets[ 1 ] ) )[ 2 ] = 3.0f;

// Store the rotation in the buffer
const GLfloat rotations[] = { 30.0f, 40.0f, 60.0f };
unsigned int offset = uniformOffsets[ 2 ];

for( int n = 0; n < 3; n++ )
{
*( ( float* )( buffer + offset ) ) = rotations[ n ];
offset += arrayStrides[ 2 ];
}

// Store the matrix in the buffer
const GLfloat matrix[] =
{
1.0f, 2.0f, 3.0f, 4.0f,
9.0f, 8.0f, 7.0f, 6.0f,
2.0f, 4.0f, 6.0f, 8.0f,
1.0f, 3.0f, 5.0f, 7.0f
};

for( int i = 0; i < 4; i++ )
{
GLuint offset = uniformOffsets[ 3 ] + matrixStrides[ 3 ] * i;

for( int j = 0; j < 4; j++ )
{
*( ( float* )( buffer + offset ) ) = matrix[ i * 4 + j ];
offset += sizeof( GLfloat );
}
}

free( buffer );
}

void shutdown( void )
{
glDeleteVertexArrays(1, &vertex_array_object );
glDeleteProgram( rendering_program );
}

void render( double currentTime )
{
const GLfloat color[] = { 0.0f, 0.2f, 0.0f, 1.0f };
glClearBufferfv( GL_COLOR, 0, color );

// Use the program object we created earlier for rendering
glUseProgram( rendering_program );

glDrawArrays( GL_TRIANGLES, 0, 3 );
}

GLuint compile_shaders( void )
{
GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;

// Source code for the vertex shader
static const GLchar* vertex_shader_source[] =
{
"#version 430 core \n"
" \n"
"layout ( location = 0 ) in vec4 position; \n"
"layout ( location = 1 ) in vec4 color; \n"
" \n"
"layout(std140) uniform TransformBlock \n"
"{ \n"
" float scale; \n"
" vec3 translation; \n"
" float rotation[ 3 ]; \n"
" mat4 projection_matrix; \n"
"} transform; \n"
" \n"
"out vec4 vs_color; \n"
" \n"
"void main( void ) \n"
"{ \n"
" gl_Position = position; \n"
" vs_color = color; \n"
"} \n"
};

// Source code for the fragment shader
static const GLchar* fragment_shader_source[] =
{
"#version 430 core \n"
" \n"
"in vec4 vs_color; \n"
" \n"
"out vec4 color; \n"
" \n"
"void main( void ) \n"
"{ \n"
" color = vs_color; \n"
"} \n"
};

// Create and compile the vertex shader
vertex_shader = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( vertex_shader, 1, vertex_shader_source, NULL );
glCompileShader( vertex_shader );

// Create and compile the fragment shader
fragment_shader = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( fragment_shader, 1, fragment_shader_source, NULL );
glCompileShader( fragment_shader );

// Create program, attach shaders to it, and link it
program = glCreateProgram();
glAttachShader( program, vertex_shader );
glAttachShader( program, fragment_shader );
glLinkProgram( program );

// Delete the shaders as the program has them now
glDeleteShader( vertex_shader );
glDeleteShader( fragment_shader );

return program;
}
};

DECLARE_MAIN( my_application );

For some reason "glGetUniformIndices" returns garbage to the "uniformIndices" array, and because of that I get a crash when i try to load a value for the "scale" into the buffer.

Any suggestions?

Thanks
Robin

Dan Bartlett
10-12-2013, 05:44 AM
You need to use "transform.scale" instead of "TransformBlock.scale". See the syntax section of http://www.opengl.org/wiki/Interface_Block_(GLSL)

DreamCore
10-13-2013, 08:27 AM
You need to use "transform.scale" instead of "TransformBlock.scale". See the syntax section of http://www.opengl.org/wiki/Interface_Block_(GLSL)

Thanks for your reply, but unfortunately it did not make any difference changeing from TransformBlock to transform and the exact same error persists.

Dan Bartlett
10-13-2013, 09:08 AM
Actually, you had it right the first time (TransformBlock.scale to be used when accessed from OpenGL side). What values are being returned? is it the value of GL_INVALID_INDEX (-1 or 0xFFFFFFFFu) returned? Maybe it is because you aren't using them in your shader so they have been optimised away. Passing a value of GL_INVALID_INDEX back into other functions doesn't seem to be allowed by spec.

DreamCore
10-13-2013, 10:57 AM
The index returned is the same for every uniform in the block, 4294967295. I tried "using" them in the shader but that did not change anything.

Dan Bartlett
10-13-2013, 11:40 AM
If there was an error, nothing would be written to uniformIndices, so the fact it's returning 4294967295 (which is equal to 0xFFFFFFFFu = GL_INVALID_INDEX) probably indicates there's no other error.

Are you sure you're using the values in such a way that they have an effect on the position of vertices or the final colour of triangles rendered? If they don't have any effect on what is being rendered, the GLSL compilers are pretty good at optimising the code away.

DreamCore
10-13-2013, 12:50 PM
Ah I wasn't actually doing anything "usefull" with it. But it feels kinda bad that the program crashes just becauase the compiler decides to optimize away stuff. Is there a way around this (othan than explicitly checking if every single index is equal to GL_INVALID_INDEX and not doing the memory stuff if so is the case)?

GClements
10-13-2013, 05:15 PM
Ah I wasn't actually doing anything "usefull" with it. But it feels kinda bad that the program crashes just becauase the compiler decides to optimize away stuff. Is there a way around this (othan than explicitly checking if every single index is equal to GL_INVALID_INDEX and not doing the memory stuff if so is the case)?
If you use a fixed layout (std140 or std430), then you don't need to query the layout.