xygine Feature: Deferred Rendering

Although I claimed that I wouldn't be posting a lot about xygine outside the wiki, I also have to admit that every once in a while I like to give my own horn a damned good toot. One of my favourite features of xygine is the MultiRenderTexture. This class inherits the sf::RenderTarget class from SFML, making it a compatible drawing target that behaves not unlike a regular sf::RenderTexture. The main difference is that it contains up to 4 textures which are all drawn on at the same time. This is ideal for effects such as deferred rendering, where normal map, colour and mask data are all drawn to seperate textures, then blended in a single call which performs all the lighting calculations at once. This gives rather pleasing results when combined with the lighting and default normal map renderer provided with xygine (the banding is an unfortunate side-effect of video compression):

It is of course also flexible enough that user defined shaders can be implemented easily for any effect desired. The source for the demo is now included as part of the example project in the xygine repo. The textures were created from a 3D model made by a good friend of mine, whose other, rather beautful, creations for Dota2 can be found here.

There is one small caveat however: due to the inverse Y coordinates of SFML the output of the MultiRenderTexture can appear upside-down when drawn with a regular sf::Sprite. SFML works around this internally by flipping its textures, but unfornately xygine does not have access to this. It can be easily worked around when using an sf::Sprite, however, by setting the sprite's Y scale to -1. VertexArrays can simply invert their texture coordinates, and, when feeding the output to a shader uniform (as one would, when combining the textures in to a final image), the inversion doesn't matter at all because it is as OpenGL natively expects it to be.

Of course the MultiRenderTexture isn't limited to deferred rendering - other tricks can be performed if you're feeling creative. For example this scene is rendered to one texture normally, but on the second texture a faux 'depth' value of the drawable is used to set the pixel colour. Blurring a copy of the scene and then blending it using the faked depth texture can provide an interesting depth-of-field effect:

uniform sampler2D u_texture;
uniform float u_depth;

void main()
    gl_FragData[0] = texure2D(u_texture, gl_TexCoord[0].xy);
    gl_FragData[1] = vec4(vec3(depth), 1.0);

MRT Textures

uniform sampler2D u_colourTexture;
uniform sampler2D u_blurredTexture;
uniform sampler2D u_depthTexture;

void main()
    float mix = texture2D(u_depthTexture, gl_TexCoord[0].xy).r; //all channels are the same so pick one
    vec4 colour = texture2D(u_colourTexture, gl_TexCoord[0].xy);
    vec4 blurredColour = texture2D(u_blurredTexture, gl_TexCoord[0].xy);
    gl_FragColor = mix(colour, blurredColour, mix);

Output of blended textures

This is but one of the many features xygine has to offer. To find out more about what you can do with xygine take a look at the wiki.


Popular Posts