Wednesday, September 16, 2009

Storing shader parameters in a std::map

Setting a shader parameter in Cg is pretty simple: (note, this code hasn't been compiled)

// Initialize CG context
cgContext = cgCreateContext();
checkForError("creating Cg context");

cgSetParameterSettingMode(cgContext, CG_DEFERRED_PARAMETER_SETTING);
checkForError("setting up deferred parameter setting");

checkForError("setting debug mode to false");

// Set up profile
_cgProfile = cgGLGetLatestProfile(_profileType);


// Load program
_cgProgram =

// Get named parameters
_lightPosition = cgGetNamedParameter(_cgProgram, "lightPosition");

// Set parameter
float4 _lightPos[4] = {10, 10, 10, 1};
cgSetParameter4fv(_lightPosition, _lightPos);

I like to wrap everything up in an object, so I end up with a shader object that exposes methods to set the parameters and then call shader->update(); to load the uniform data into the shader.

This eliminates writing the setup code each time, but adds a lot of overhead in creating a bunch of private variables for the CGparameters, seting up a method that gets all of the named parameters and then write methods to set the parameters. It's nice once it is done because you just instantiate the shader, call load and start setting parameters.

The process become tedious when parameters are changed or added, which is a part of the development process. You have to create or remove private variables and methods. Since I'm not perfect, I sometimes make mistakes and the frustration mounts.

What if I wanted to create a more dynamic enviroment where the shaders can be changed at run time and the list of uniform variables shows up in a dialog box for easy changing? Not possible with my current set up.

So, I changed my base shader class to read all of the parameters in a shader program and build a map that maps parameter names to CGparameters. Then I added some overloaded functions that take a parameter name and a value, like a Matrix, Vector, Point or Color and calls the appropriate function to set the variables.

Loading a shader and setting variables is as easy as:

CGShader* frag = new CGFragmentShader("", "shadow");
frag->set("shadowMap", _fbo->depthTex());

No more building custom classes to wrap everything up. It's all done for me. Structs are not supported and no type checking is done. But this gets me going and speeds up development. I'll add support for structs and type checking as needed.

No comments:

Post a Comment