Monday 20 February 2012

ngl::ShaderLib update

Just a quick post to explain some updates to the ngl::ShaderLib sub-system. First of all this doesn't break any existing code, but has in some situations increased frame rate by 10-15%.

First a bit of background, all of the shader lib functions use the getUniformLocation function to query the location of the uniform in the current program and use this GLuint offset to load the values to the uniform in the shader.

This works ok, and generally this only called at the start of the program so doesn't cause too much of a bottleneck. However in most of the demos we load the Model/View/Projection matrix to the Shader each time we move something, and the MVP value will be loaded using the following code (from the ngl:: source)

void ShaderProgram::setUniformMatrix4fv(
                                          const char* _varname,
                                          size_t _count,
                                          bool _transpose,
                                          const float* _value
                                        ) const
{
  glUniformMatrix4fv(getUniformLocation(_varname),_count,_transpose,_value);
}
Here the getUniformLocation is called and doesn't need to be if we pre-cache the value. To do this ngl::ShaderProgram has a new attribute added to it as follows
std::map <std::string, GLuint> m_registeredUniforms;
To use this, once the shader is loaded, compiled and linked we must set it to be active and we can then register the uniform as follows (this will usually be done in the GLWindow::initalizeGL method)
(*shader)["MultipleLights"]->use();
shader->setShaderParam1f("Normalize",1);
shader->registerUniform("MultipleLights","MVP");
shader->registerUniform("MultipleLights","MV");
shader->registerUniform("MultipleLights","M");
shader->registerUniform("MultipleLights","normalMatrix");
shader->registerUniform("MultipleLights","viewerPos");

This will register the uniforms, now when we load the matrix values to the shaders, we can use the "registered" versions of the functions which will look up the values in the map and use the uniform's stored there. This will work unless the shader source is changed and re-compiled. In that case they will need to be re-registered.

void GLWindow::loadMatricesToShader(
                                     ngl::TransformStack &_tx
                                   )
{
  ngl::ShaderLib *shader=ngl::ShaderLib::instance();
  (*shader)["MultipleLights"]->use();
  ngl::Matrix MV;
  ngl::Matrix MVP;
  ngl::Mat3x3 normalMatrix;
  ngl::Matrix M;
  M=_tx.getCurrentTransform().getMatrix();
  MV=_tx.getCurrAndGlobal().getMatrix()*m_cam->getViewMatrix() ;
  MVP=MV*m_cam->getProjectionMatrix();
  normalMatrix=MV;
  normalMatrix.inverse();
  normalMatrix.transpose();
  shader->setRegisteredUniformFromMatrix("MV",MV);
  shader->setRegisteredUniformFromMatrix("M",M);
  shader->setRegisteredUniformFromMatrix("MVP",MVP);
  shader->setRegisteredUniformFromMat3x3("normalMatrix",normalMatrix);
  shader->setRegisteredUniformVec3("viewerPos",m_cam->getEye().toVec3());
}

No comments:

Post a Comment