Thursday, 11 November 2010

Imitating OpenGL Fixed functionality pipeline in OpenGL 4.x (Part 1 of many)

So when converting some of my demos I decided to do the spotlight demo from last year, this uses the built in OpenGL spotlight and the normal fixed functionality OpenGL pipeline.

This year I've ported all of my code to the newer 3.x / 4.x OpenGL pipeline which as deprecated a number of gl commands ( a full list are here) but the core to most of the initial work is in the follow section from Appendix E or the document


Begin / End primitive specification - Begin, End, and EdgeFlag* (sec- tion 2.6.1); Color*, FogCoord*, Index*, Normal3*, SecondaryColor3*, TexCoord*, Vertex* (section 2.7); and all associated state in tables 6.4 and 6.5. Vertex arrays and array drawing commands must be used to draw primitives.
and

(section 2.8); Frustum, LoadIdentity, LoadMatrix, LoadTransposeMatrix, MatrixMode, Mult- Matrix, MultTransposeMatrix, Ortho, PopMatrix, PushMatrix, Ro- tate, Scale, and Translate 

What this basically means is the immediate mode OpenGL is no longer core to OpenGL 3/4 and we must use the GPU as much as possible. Most of this work involves the OpenGL matrix stack and the use of immediate mode, which is slow and inefficient and not available in OpenGL ES (used for mobile devices such as iPhone).

NGL already supports the use of GLSL shaders and with the ngl::Transform and ngl::TransformStack classes we can do all of the glRotate, glTranslate, glScale functions as well as the glPush/PopMatrix commands.

There are also methods built into the Transform / TransformStack to load these matrix values to a shader to use in GLSL. 

For example in fixed functionality OpenGL each call to glVertex will pass through the following processes

This is easy to implement as the ngl::Camera class will calculate these values based on our Virtual Camera configuration of Eye, Look and Up (for the View matrix) and Current Transform Stack for the  Model element of the ModelView matrix combination.

The projection is also calculated in the camera class and loaded to the shader. The following Vertex shader shows the calculaition of the current Vertex based on these values as well as the fragment normal.
uniform mat4 projectionMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ModelMatrix;


varying vec3 fragmentNormal;
varying mat4 transform;

void main(void)
{
  fragmentNormal = (ViewMatrix*ModelMatrix*vec4(gl_Normal, 0.0)).xyz;
  transform=projectionMatrix*ViewMatrix*ModelMatrix;
  gl_Position = transform*gl_Vertex;
}

In the above example the uniform mat4 variables are passed to the shader from our program and represent the current state of the MODELVIEW and PROJECTION matrices at the time of the vertex processing. For example usually we would set the projection of the camera and the view from the camera once a frame (or if fixed at the start of the program), then the modelling transformations of the current set of vertices will be set to position our objects as show in the following configuration code.
ngl::Vector From(0,0,8);
ngl::Vector To(0,0,0);
ngl::Vector Up(0,1,0);

m_cam= new ngl::Camera(From,To,Up,ngl::PERSPECTIVE);
// set the shape using FOV 45 Aspect Ratio based on Width and Height
// The final two are near and far clipping planes of 0.5 and 10
m_cam->setShape(45,(float)720.0/576.0,0.5,10,ngl::PERSPECTIVE);
// now to load the shader and set the values
// grab an instance of shader manager
ngl::ShaderManager *shader=ngl::ShaderManager::instance();
// load a frag and vert shaders
shader->loadShader("Blinn","shaders/Vertex.vs","shaders/Fragment.fs");
// set this as the active shader
shader->useShader("Blinn");
// now pass the modelView and projection values to the shader
shader->setShaderParamFromMatrix("Blinn","ViewMatrix",m_cam->getModelView());
shader->setShaderParamFromMatrix("Blinn","projectionMatrix",m_cam->getProjection());

This will basically set up a static view similar to the standard gluLookAt function, any modelling transformation such as Push/Pop matrix and glRotate / glTranslate / glScale are loaded to the Model part of the matrix when drawing as show in the following code segment
ngl::Transformation trans;
trans.setRotation(m_spinXFace,m_spinYFace,0);
// set this in the TX stack
m_transformStack.setGlobal(trans);
// now set this value in the shader for the current ModelMatrix
shader->setShaderParamFromMatrix("Blinn","ModelMatrix",m_transformStack.getCurrAndGlobal().getTransposeMatrix());

// get the VBO instance and draw the built in teapot
ngl::VBOPrimitives *prim=ngl::VBOPrimitives::instance();


m_transformStack.pushTransform();
{
 shader->setShaderParamFromMatrix("Blinn","ModelMatrix",m_transformStack.getCurrAndGlobal().getTransposeMatrix());
 prim->draw("teapot");
} // and before a pop
m_transformStack.popTransform();

So far so good, we can view, transform and project our models using OpenGL 3/4.x and this system is on the GPU (thanks to the ngl::VBOPrimitives class which wraps our data onto the GPU and mimics a lot of the glut primitives which are all immediate mode gl)

Next we need to look at lighting and material properties and how to shade everything. This is where it get complicated, and will be in the next post.

No comments:

Post a Comment