Making a 3D Game with OpenGL: Deferred shading and stuff

// July 19th, 2012 // OpenGL

Lately OpenGL and C++ is pretty much the only thing I do for clients, mostly for installations and iPad apps. And that’s gowning pretty well.  But as a creative code guy, I pretty much stayed in our own tech subculture. But when it comes to cutting edge graphic techniques, we can learn a lot from those other guys, the game developers.

So one sunny afternoon, I decided to do just that and I started to make my own 3D game from scratch.

I wanted to write a blog-post when it was finished. But I hugely underestimated the work (Now I understand why indie gamedevelopers take +3 years to finish a game). And I’ve already done so much it wouldn’t fit in one blog post. So I’m going to try to make multiple blog-posts, to light out different technical things I’ve used for my game, and keep you updated about the progress of the game itself.

The game:

Or more game engine, since I don’t really have any game play at the moment:

As you can see, there are still a lot of glitches and things to be done, but I’m happy where it’s going.

Some of the things I’ve done so far (not always complete, final or clean).

-The terrain generation, it’s an infinite/live generated terrain.
-Seamless day-night transitions.
-Cascade shadow maps, SSAO (screen space ambient occlusion).
-Normal maps, alpha textures, alpha shadows.
-Some simple LOD (level of detail) setup for the terrain mesh and the 3D objects.
-Bone animations in the vertex shader + interpolations between the animations. (models are loaded with Assimp)
-The main part of the rendering pipeline.
-Learned the basics of modeling and animating in Blender :)
-and a lot of other stuff.

The current Render pipeline

It’s very WIP at this moment, but here is a diagram of how the current rendering is done. More about this below.
(click for the full size image, open in new tab if you get the popup)

Deferred Shading:

One of the things I wanted to try was deferred shading, just for the heck of it. But I’m really glad I did. Since it seems much faster, and has some additional advantages (there are also some disadvantages)

How does it work:

You just render all the main geometry once, In 3 textures. a depth texture, a color texture with just the diffuse. and a color texture with the normals in worldspace.
you can do that in OpenGL all at once, with an FBO (frame buffer object) with multiple color attachments. And since you don’t do any lightning, its pretty fast. After that, you use those textures to calculate the lighting etc.

The big advantage is that you only have to calculate the lightning on the pixels that are actually visible on the screen. So you have no overhead of overlapping objects. And if you want to do some post processing stuff, like ambient occlusion or depth of field, you already have the depth texture and normal texture in place.

To get back from the depth to the worldspace, you just multiply the screen space with the inverse of the perspective matrix:

float depth = texture2D(depthTexture, uv_var).x*2.0-1.0;
vec3 viewSpace ;
viewSpace .xy = uv *2.0 -1.0;
viewSpace.z=depth;
vec4 worldSpace = perspectiveInvMatrix* vec4(viewSpace,1.0);
worldSpace.xyz/=worldSpace.w;

But what I really liked about it, is that you can have a lot of dynamic lights in your scene. When you use forward shading, your happy if you can use a couple of lights. But but with deferred shading you can have hundreds. You just render the lights as volumes in a separate pass (sphere for a point light, a cone for a spotlight etc). So you only have to calculate the light on the position where it really affects things, and since you use the normal and depth texture as input, only on the geometry you really see.

The light volumes rendered as normal geometrie:

The fragment shader calculation I use for the light volumes:

vec3 dir = worldPos.xyz-lightCenter; // worldPos from the depth
float l = length( dir);
float dist =1.0-pow((clamp (l ,0.0,lightSize_var)/lightSize_var),2.0); // quick light falloff
float lambert  =clamp(dot(normalize(dir) , -normal ),0.0,1.0); //shading
gl_FragColor = vec4(lightColor *dist * lambert   ,1.0);

The result of the Light pass:

I just use a blendfunct GL_ONE, GL_ONE (add) for all the lights, although technically not correct. But it looks good enough.
The lights in the final scene:

Lambert texutre lookup

An other neat trick I discovered while doing research for this, is using a Texture to lookup your shading color (found it in the Valve Team Fortress 2 Paper).
The great thing about this is that you can edit your shading in photoshop. In my case I used a 2D texture, so I can have al the subtle light differences between day and night.

This is the texture I use now, but it still needs some work:

I just use the shading color for the u and the time for the v lookup.

Here is the plain old shading:

And the shading after the look-up:
Night:

Day:

That’s it for now, hopefully some more blog-posts to follow this up :)

Source code and assets at Github ( at your own risk )

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

14 Responses to “Making a 3D Game with OpenGL: Deferred shading and stuff”

  1. Hans says:

    pfff jezus christ, you’re so on a whole other level :) nice one kris, looking forward to further posts ’bout this :)

  2. Kris says:

    Nice writeup!
    It makes much more sense now then when you explained it to me ;)
    Posting it online also increases the chances of being used for a “real” project someday

  3. roxlu says:

    Wow Kris, this is amazing! Doing all this stuff with just one person! You’re a machine! Love you’re sharing all this information!

  4. kikko says:

    That’s amazing! thanks for sharing and detailing your work

  5. esimov says:

    Really looking forward for the next part. Great writeup!

  6. Wow, where do you find the energy for this?

  7. rackdoll says:

    Awesome work chris. Thnx for pointing out the deferred shading!

  8. Guchan says:

    Well, I’m sharing some code and information on my website too but this is amazing. You are the man. Thank you for being so generous.

  9. Kailash says:

    Can you pls.. mail me the source code..

  10. Umair says:

    Can u plz mail me the complete source code of above program,it wud reali help me.thanks

  11. hager says:

    Can you pls.. mail me the source code..

  12. Kris says:

    you can download the sourcecode here: https://github.com/neuroprod/npDeferredS (zip)

  13. Noman says:

    hi my friends!!! plz friends help me i need a simple game in openGL can any have a game so plz send me on my email id plz plz plz plz send me source code of a game in openGL plzzzzzzzz this is my email id “Nomanzeb3@gmail.com”

  14. You are a saint for releasing this to the public. I have not enjoyed getting familiar with OpenGL, and you have saved my bacon.

    Or at least, made the bacon must tastier. I’m curious about the shadows from the trees stretching on the edges of the screen. I suppose it’s something I’ll understand better as I poke around.

Leave a Reply