Deferred Shading: First prototype

I finally did it! After several days testing, reasearching the net, going through tons of 3D math and uncounted frustrating hours, I have the first working prototype of the deferred renderer running. My main problems was a bug in my normals and mainly reconstructing the view space position from the depth buffer. Especially the on the last one was suprisingly tricky and forced me to dig through matrix math stuff again.

Nevertheless I have all main problems tackled and hopefully can do some nice things now. For the moment a screenshot of the prototype. It has 3 lights active and is fully deferred rendered.

Deferred Shading: G-Buffer

Another quick update on the deferred shading progress. I finished prototyping the G-Buffer. Here is the layout:

GL_R32F  |                       Depth                       |
GL_RG16F |         NormalX         |         NormalY         |
GL_RGBA8 |   ColorR   |   ColorG   |   ColorB   | MaterialID |
GL_RGBA8 | SpecularR  | SpecularG  | SpecularB  | Shininess  |

And now a screenshot. On the left you can see the 4 buffers, starting from the bottom: Depth, Color, Normal and Specular.

The main render is still done with default rendering. I’ll implement the deferred shading pass next.


Shader fun

Lately I updated the engine renderer to use core OpenGL 3 only. While there are still some things to work out the engine is now running completely on shaders. This allowed me to do implement some amazing things.

1. Completly flexible vertex formats.

Adding a new vertex definition is pretty easy now. First you need to typedef a struct for storing the vertices:

typedef struct myVertexType
  F32V3 position;
  F32V3 normal;
  F32V2 texCoord0;
  F32 blendFactor;
} myVertexType_t;

The next step is to create a definition for the vertex type:

nxVertexAttribute_t myVertexDef[] = {
  { nxVertex::Position, 3 },
  { nxVertex::Normal, 3 },
  { nxVertex::TexCoord0, 2 },
  { SID("BlendFactor"), 1 },
  { nxVertex::End, sizeof(myVertexType_t) }

And that’s it. This can be done completly seperated from the engine. So no engine recompiles needed!

The first 3 attribute names (nxVertex::Position, …) are predefined in the engine and automatically linked to all shaders. “BlendFactor” is a custom attribute name which must match to the corresponding name and type in the shader (“in float BlendFactor”). The numbers after the names are the size of the attribute in 4 byte steps. The last element “nxVertex::End” is to tell the engine that the definition is complete. “sizeof(…)” is the stride of the vertex type.

2. Framebuffer Objects

To get the real power out of shaders, framebuffer objects are a must have. So I implemented them into the engine and started to play around with them for a bit. Up to now I can create FBO’s and attach textures to them, which are used as render buffers. Then the FBO can be activated and used for rendering. After that the attached texture can be used as input for further shading passes or used for normal texture mapping. This allows some very interesting effects like mirror surfaces, enivormental mapping or procedural texture generation.

I created a basic demo which first renders the scene into a FBO. In the next pass the textures from the FBO are blended into the scene. The two textures used as buffers in the FBO are color and depth:

3. Next: Deferred Shading

The whole thing of this OpenGL 3, shader, FBO thing is that it allows the implementation of deferred shading. I really liked the idea behind this technique when I first read about it and now it’s the time to implement it by myself. Some links if you’re interested in the topic:

Deferred Shading Tutorial (PDF)

Deferred Shading – Wikipedia

That’s it for now. I’ll post some more pics if I have something nice to look at.

NX-Engine progress

While still doing some Python integration I started working on several other parts of the engine.

1. Ported from SDL 1.2 to SFML 2.0

Up to now the engine used SDL 1.2 as it’s wrapper around low level stuff like creating windows and getting events. This worked ok so far but had some major drawbacks:

  • SDL is licensed under LGPL. While still an opensource license and far better than GPL, it is only allowed to dynamically link against the library.
  • SDL 1.2 isn’t able to create OpenGL 3+ contexts.
  • The source code isn’t as clean and readable as I would wish. (C code)

I was aware of SFML for quite a while and while the 2.0 version is still in development and has some bugs it offers clear advantages:

  • Lincense is zlib/png which is awesome because it allows dynamic/static linking + pretty much total freedom.
  • It is possible to create OpenGL 3+ contexts.
  • Source code is very nice and clean. (C++ object oriented)

So I got rid of SDL and plugged SFML into the engine. To my suprise this was easier than I thought and the whole process was smoothly done in a few hours. Maybe a sign for a good engine structure? I hope so!

While SFML has it’s benefits there was some drawbacks aswell. 1. Image loading support isn’t as good as SDL_image and 2. SFML doesn’t support condition variables for thread synchronization. I worked around this problems by integrating DevIL for image loading and porting all threading stuff to boost::thread.

DevIL is an excellent library with an absolutley lovely API which is pretty much the same as OpenGL. It offers support for an amazing range of picture formats and perfectly fits the needs of the engine.

2. gDEBugger fun and optimizations

If you haven’t heard of gDEBugger yet, it is an OpenGL profiler, analyzer, debugger with some nice features. It was recently made available for free and every OpenGL programmer should grab a copy immediately. With the help of this program I was able to optimize the renderer in the engine quite a bit by removing redundant GL calls. The results of 1 hour work were an increase of the FPS in valgrind’s memcheck by the factor 2,5x !

3. Actors for the engine

I started to implement some actor stuff in the engine. Up to know this allows the creation and deletion of objects through script. Next steps are moving things around by script commands and coupling of the system with the scene graph.