Monthly Archives: September 2014

Integrating RenderDoc

A few days ago a new version of RenderDoc was released, and while reading the changelist I discovered that Temaran has made a really cool plugin which integrate RenderDoc directly in Unreal Engine 4.

This is extremely useful. More than once I launched debugging from Visual Studio, found a weird bug, and had to launch it again from RenderDoc, trying to reproduce the bug.

So I looked at the source code uploaded on Github by Temaran, removed the UE4 related code and only kept a single class to be able to load RenderDoc and trigger a capture directly from my engine.

You can find the code here: https://github.com/oks2024/RenderDoc-Manager

In the end it’s just two header and one cpp file. You just have to provide some paths, like where you want to store the captures and your RenderDoc folder. In my case I use the portable version and stored it in Perforce. Keep in mind that your build target must match the RenderDoc version, you can’t mix x86 and 64bits.

You can either bind a key to RenderDoc that will trigger a capture or use the StartFrameCapture()/EndFrameCapture() functions. I use the latter because it allows me to skip the update part of my engine, capturing only the rendering functions.

It’s working great in my small engine, I’m using it for a couple of days and hadn’t noticed any issue. I know that it can slow down the resources creation so for a bigger engine it’s not be something you want to have always enabled.

As you can see it’s very a basic code skeleton, and most of the code is from Temaran’s plugin, but I found it really usefull and thought it worth sharing.

I think I will add functions (at least to set capture options without having to recompile) as I need them, and I will try to keep the Github repository up to date. And if you have any suggestion, it’s on github, so feel free to leave a comment or add your modifications :).

Apart from debugging, it may also be usefull for creating automated tests. With the appropriate script you can load a level, move the camera through several positions, and take captures. And after that it should be possible to get the images (and maybe even timings) from the captures, and compare them to make sure your last submit did not break the rendering.

Baldur Karlsson is doing an amazing work on RenderDoc, with regular updates and new features. I was already one of my favorite tool, and it’s not going to change !

Improved shadows using dithering and temporal supersampling

To be able to implement volumetric lights I had to start with shadows for the sun light. As it wasn’t my primary focus I went for a straightforward shadow map implementation on a 2k texture. It’s easy and quick to code, but yeah, the results are ugly.

BasicShadowMaps

Yes, you can count pixels in the shadows.

 

I didn’t planned to implement a more advanced shadow map technique anytime soon, but I also didn’t want to stay with those ultra pixaleted shadows, so I tried to apply my two current favorite techniques: dithering and temporal supersampling :).

Let see what it can do !

First step, offset the shadow map bias by a value given by a Bayer matrix :


 

float shadow = 1.0f;

float ditherValue = ditherPattern[screenSpacePosition.x % 4][screenSpacePosition.y % 4];

if (shadowMapValue < worldByShadowCamera.z - bias * ditherValue)
shadow = 0.0f;

And then a bilateral blur. In my engine I already have a bilateral blur pass for the SSAO, with one free channel in the texture. So I just added the shadow value in the alpha channel of my SSAO texture and got the blur for free. It’s also convenient for the lighting stage as the tiled deferred shader can read both AO and sun light shadow in one tap.

Here is what it looks like now:

ShadowDither

It look way better, and it was really a few lines of codes ! Plus by merging it with the ambient occlusion it’s almost free !

But in some places the dither patern is really noticeable.DitherPattern

DitherPattern2

And in movement there is a lot of flickering.

It’s now time for some temporal supersampling !

Again in my case it was really easy as I already implemented this for the ambient occlusion. I just had to store a “previous frame shadows” texture and give it to my AO shader that already take care of rejecting bad previous pixels based on depth.

The flickering is almost totally gone ! But as you notice there is a lot of ghosting, especially when the sun light is moving. This is because  wrong pixels rejection is only based on their depth value, it’s good enough for AO, but not for shadows. When the sun is moving depth won’t change and yet the previous value shouldn’t be used.

So I added a pixel rejection based on the difference between the current and previous values. It means that if the value changed too much between two frames then something must be wrong. The hard part is to find the right function and the right values to be able to remove the obviously wrong datas but still keep enought informations to be efficient. It’s just my first experiments with this and I need to read some papers/presentations and do more tests to improve the result, and maybe write more about it. Here is my results so far.

It’s better ! A little of the flickering is back, but it’s still a great improvement compared to what I had at first.

But the issue with the dithering pattern being noticeable in some places isn’t resolved. To remove this I used two tricks. First I changed the dither offset used by a given pixel each frame. It would normally induce a lot of flickering, but the temporal supersampling smooth it and it become unnoticeable.

Then I randomly change the sun direction by a small amount. In not yet perfectly happy with this as it’s currently really noticeable even if it remove some artifact and had a soft shadow effect. Maybe I should use a predefined pattern instead of a completly random offset, in order to have a better temporal stability.

Temporal and jitter

 

That’s it for now ! There is still a lot of room for improvement, but  just using some quick tricks and existing resources in my engine I was able to improve the looks of my shadows, at a very limited cost and in a few hours. I really like the possibilities offered by the temporal supersampling, I will definitely use it more !

To conclude here is two screenshots of the shadows only, before and after.

ShadowsOnlyBefore

ShadowsOnlyAfter