Home | Adding fullscreen shaders can make rendering look a little less synthetic. |
|
Introduction
Fullscreen shaders van be used since v0.6 to add some special effects to the entire rendered screen. Racer supports Cg (fragment/pixel) shaders to perform this task. Creating these shaders is relatively doable compared to doing Cg shaders for objects, since there are less variables to watch out for.
Note that fullscreen shaders require relatively newer hardware; I myself originally developed these shaders on an nVidia 7950 card (which is not really new at the time of development, fortunately). The impact on framerate is quite ok compared to the older method of copying the framebuffer contents back to a texture (glCopyTexImage2D) which was available to do a crude motion blur. You'll need an up-to-date graphics card that supports these 2 OpenGL extensions: GL_EXT_framebuffer_object and GL_ARB_texture_non_power_of_two. The first makes FBO's available, the 2nd makes sure that textures with a non-power of 2 sizes can be created.
If Racer fails to load or run the shaders, you might not have hardware high-end enough to support fullscreen shaders.
The Flow
Normally, Racer renders directly to the framebuffer. This means rendering to the back buffer, and when all is ready, swap the front and back buffers. With fullscreen shaders, things get a little different; instead of drawing to the framebuffer, first Racer draws onto an offscreen texture (currently implemented using an FBO, a framebuffer object (15-7-08)). Then, for single pass effects, this texture is used in combination with a fullscreen shader and rendered into the framebuffer itself. For dual pass effects, the first shader is used to render into a 2nd FBO, and then the contents of FBO 2 are rendered into the framebuffer, with 2 textures available; the result of shader1 in FBO1 (in texture unit 0) and the original render (un-fullscreen-shaded, in texture unit 1).
One downside to using FBO's is that anti-aliasing of the originally rendered images (as rendered into the texture) are not anti-aliased. Perhaps I can work a way around that somehow.
If you couldn't follow a thing of what's described above, it might be good to read up a bit on OpenGL Cg shaders perhaps. Things here do get quite technical.
First let's try a single-pass Try the following to get a sepia screen.
Here is the sepia.cg shader (refer to Google or nVidia to find out more about the Cg shader language):
struct VertOut { float2 tc0 : TEXCOORD0; };
struct FragOut { float4 col : COLOR; };
FragOut main(VertOut vin, uniform sampler2D tex0 : TEXUNIT0 ) { FragOut fout; float4 vWeightsBW=float4(0.3,0.59,0.11,0); float4 vWeightsSepia=float4(1.0,0.8,0.6,1); float4 cColor=tex2D(tex0,vin.tc0); float brightness=dot(cColor,vWeightsBW);
fout.col=brightness*vWeightsSepia;
return fout; }
Actually, this example doesn't use shaders yet, but uses the FBO motion blur method to get a better motion blur than in older versions.
Racer (v0.6+) comes with a fullscreen bloom example. To enable this, do the following:
How this works? The first pass (using bloom_h.cg) blurs a bit
on horizontal direction and uses pow() to add severe contrast; dark colors are
blackened while whiter colors are blown out. You can see the result of purely
the first shader if you keep fs_filter2 empty.
The 2nd pass (bloom_v_mix.cg) does a vertical Guassian blur and simultaneously
adds the results of the bloom_h.cg shader (available in texture unit 0) to the
original image (in texture unit 1).
An example of the bloom filter (on Swiss Stroll):
EXPERIMENTING FURTHER
The Cg shaders offer a very wide field of experimentation. Graphics cards only develop further to implement more and more dynamic programming. Try writing your own shaders to come with nice effects. Racer comes with a few example Cg scripts (none too shocking) to get you started; check the data/renderer/fullscreen_shaders directory for a bit of inspiration.
(last updated November 13, 2012 )