Saturday, 9 February 2013

Realtime, screen-space local reflections, using C# and SharpDX

The following video shows my own implementation of the technique "Real Time Local Reflections (RLR)" used by Crytek in CryEngine3, and described here.

This particular implementation works with a non-deferred rendering system, and it’s adapted to work particularly well with planar surfaces like roads (which is what we most use it for, here at Simax).

The process is basically doing a texture lookup for the reflections as usual, but instead of using a cubemap, we use a simple texture (a copy of the previous back-buffer). It also needs a copy of the previous frame's depth buffer, to do a raymarch looking for the appropriate sample. The steps are the following:

  1. 1.- Start from the screen position of the pixel you are shading
  2. 2.- Move along the direction of the reflected (and projected to screen space) normal
  3. 3.- At each step, take a sample of the depth buffer, and look for a hit. If found, use the sample of the backbuffer at the same offset. If not, move one step forward until you are out of the texture bounds

Cons

It has a lot of downsides, as the amount of information present on a single texture is very limited. One key aspect is to fade out when you are reaching the limits of the backbuffer and when the reflection vector is facing the viewer (and therefore doesn´t hit the backbuffer). That way, you avoid hard edges in the reflection.

Another limitation is its compatibility with multisampling. The problem is that you need a copy of depth buffer, and if it's multisampled, you need to resolve it to a single sampled resource. Resolving the depth buffer from a multisample resource is not a trivial task, and in DX10 only graphics cards, it seems to be not possible (beside from doing it manually).

The method: ResolveSubResource does a good job with back-buffers, but it doesn´t work with depth-buffers (I haven´t tried in DX11 yet). Another option is to move to DX 10.1 and pass the depth buffer to the shader as a multi-sampled resource, using the Texture2DMS type introduced in DX 10.1. It allows to pass multi-sampled resources to shaders, so the resolving can be done in the shader.

Pros

The major advantage of this method is speed. By grabbing only the previous backbuffer, you can add reflections to almost any object in your scene. Of course, the shader used to draw is slower than a simple one, but nothing compared with the cost of rendering multiple cube-maps or other methods...

Also, despite its cons, it does a pretty convincing job in certain cases. Wet roads, water shaders and such stuff is a perfect case for it, as when you are driving in a simulator, the angle of incidence on the road, and therefore the reflection vector fit well with the back-buffer projection.

Another implementation of the technique can be found here. I haven´t tried it, but it seems to work too…

Cheers !

No comments: