Fugly vs Nais

April 13th, 2010 by

Ran into this today :)

// FUGLY
statistics->SetVisibility(false);
debugMenu->SetVisibility(false);
bufferVisualiser->SetVisibility(false);
fpsCounter->SetVisibility(false);*/

// NAIS!
DebugHUD::OverlayItem *items[] = { statistics, debugMenu, bufferVisualiser, fpsCounter };

std::for_each(items,  // First item
	items + sizeof(items)/sizeof(items[0]), // Last item
	std::bind2nd( std::mem_fun(&DebugHUD::OverlayItem::SetVisibility), false) );	// Call the SetVisibility method on the object with true as parameter
Deferred rendering/shading

March 13th, 2010 by

We, which would be me and Marriez finally finished the deferred shading renderer this week.

Deferred shading is different from standard rendering in that it renders the lighting after all the geometry has been rendered. Standard, also called forward rendering requires a geometry pass for every light that influences the rendered geometry. Of course optimization can be made by not doing a pass for a single light but for multiple lights. For every pass however, all the geometry has to be processed, which takes time especially when the geometry is very complex. Forward rendering has a complexity of O(NL) where N is number of objects and L the number of lights.

Deferred shading does a single geometry pass. The geometry pass stores, per pixel, data required for lighting the scene in buffers. The buffers maintain normal, color, depth and material properties. These buffers are then used to perform the final lighting stage in which a pass for every light is done. Because all geometry is only rendered once deferred rendering has a complexity of O(N+L).

Unfortunately deferred shading has some caveat. The geometry buffers only holds data per pixel for a single depth. You cannot store multiple layers of depth which means you cannot do transparency. We solved this by using a forward pass to render the transparent geometry.

I will probably write a more detailed description of how our deferred renderer works in my next post. In the mean time you can enjoy these screenshots. :)

Order independent transparency

February 25th, 2010 by

Well we (Marriez & I) have been implementing lots of new stuff in our research project but there are two things that definitely stick out; the post processing framework and the order independent transparency.

The post processing framework allows very simple stacking of different effects like monochrome, sepia, underwater riple and also High Dynamic Range tonemapping and bloom. The framework automatically determines what rendertargets to use. It also automatically recycles the buffers, effectively creating a rendertarget pool. The framework follows the same approach described in this article but goes a step further. Using the post processing framework we also implemented High Dynamic Range Rendering as one of the post processing framework effects. The effect applies dynamic tone mapping and bloom to the scene.

We also implemented rendering of transparent objects. Transparent objects need to be sorted back to front to create a proper result. We looked at a lot of techniques that sort the renderable items but this requires a lot of processing on the CPU especially since we have a lot of transparent objects in our scene. It also fails if two transparent primitives cross each other because every sort result will produce a faulty image.

After realizing that sorting would not get us very far we looked at order independent transparency. The basic idea is that it does not matter in which order you render the transparent objects the result will always be correct. We first looked at depth peeling. With depth peeling the different layers of transparency that overlap are extracted from the image and rendered in the correct order which produces the final correct image. Testing showed that this technique was very inefficient the more layers that overlapped the more the framerate dropped. While researching a more efficient way to do depth peeling we stumbled upon another technique called weighted average transparency rendering. This technique is not linear in the number of overlapping primitives, requires less video memory (on average), is mostly GPU based and required very little effort to integrate into our existing rendering pipeline. The downside is that the technique does not produce a correct image but an approximation. The technique is described here under Single-pass Approximation  -> Weighted Average.

The technique used the observation that if all the colors for are given pixel are equal than the result is independent of the order in which the  fragments are blended. If the colors are not uniform than we simply replace the multiple colors by a uniform color namely the average of all the colors. When rendering the transparent objects they are additively rendered into an accumulation buffer. The result is an accumulated RGBA color  and the number of fragments per pixel. After this accumulation step the buffers are passed to a post processing step that performs the final calculation. In the original paper they also pass the framebuffer to the post processing step while we choose to use blending for this.