Loïc Baumann's Blog

Team System and .Net stuffs

July 2004 - Posts

Perspective Shadow Mapping

Perspective Shadow mapping is a real pain…
I can’t get it work correctly, I’m putting the code on hold, and I’ll get back on it later.

Craaaaaaaaash!

Lost three days into a partition crash!
Almost lost the 150gigs of data stored there, took more than a day to recover everything.

The beginning of shadow mapping

Implemented the spot light rendering.
I have now the three basic types of light: directional, point and spot

Added a Gaussian filter after the creation of the Occlusion Map.
The results speak themselves, that is definitely a must have!

The nightmare has begun: shadows…
I knew that would be one of the hardest parts of the rendering (if not the hardest), and it is…
As usual, I started by reading many papers and slideshows.I also looked the archives of the GD-Algorithms mailing list, and put back the topic because people there were apparently silent since one year ago.

Between the two families, as I rely on the pixel power, my choice naturally tends to Shadow Maps. In the land of shadow maps, many people have different opinions about what is the best to use, and with time passing, it doesn’t seem to converge into one particular technique.
Single buffer, multiple buffers, post perspective or not, trapezoidal, done in light space, oh my god…

Before starting to ask for people’s opinion, I had faith into the Perspective Shadow Mapping (aka PSM), after reading its revision from Simon Kozlov in the GPU Gems. Many people still say it’s not a viable technique, because of its numerous special cases which are really hard to solve.

The only thing everybody agrees is to make the most effort to limit the viewing frustum of the light, so I guess I’m starting from this point, and will head later on the PSM.
For now, I’ve implemented the basic of shadow mapping. Precision and point lights are coming next…

Trying to gain more precision, I first tried to make the depth comparison using a R32F buffer instead of the Depth Buffer. So I had to render my scene in that buffer, which is 60% slower than into the Depth Buffer only (from my tests).
The whole thing doesn’t worth it, it’s slower, and as it’s not using the Z-Bias, the result is pretty bad (and I really don’t want to make a Pixel Shader to emulate it). So I stick with fast rendering D24X8 surface.

I would like to thank Mark Harris from nVidia for his advices and support.

Screenshots:


Basic shadow mapping

Ambient occlusion: done!

I’ve programmed the routine to compute a texture storing the ambient occlusion of a given mesh. The result is as expected: great! (see the screenshots).

The computing process can take a while, had to throw a lot of rays per texel to get an accurate result. 512 is a good number. So for a 256*256 texture, you have at least 33 million rays thrown. When I say at least, it’s because if a given texel is shared by two faces of the mesh (across the edge), the double are thrown.

Thanks to the opcode library, it doesn’t take forever…
I’ll certainly add an option to filter the produced picture (useful when the ray count is low).

Screenshots:

The mesh (courtesy of Bruno Dosso) is 12592 triangles and 6424 vertices.

Computed on a Athlon XP 2800+. You can see the render time in the texture’s window caption.


Basic rendering, no diffuse texture, no ambient occlusion texture.


Diffuse Texture, without Ambient Occlusion


256*256 occlusion map, 16bits, 1024 rays per texel.


Same as left, with a diffuse texture.


The computed Ambient Occlusion Texture, done in 2min27sec.

Updating the lighting

Not much, I made the renderer plug-able for our shaders, add a better lighting support (see screenshots).

I added a fourth Render Target.
The surface type is D3DFMT_A8R8G8B8, it stores the specular intensity, specular power, and occlusion factor (not computed actually).

I also tried to palletize the Material settings.
I made the whole dynamic system which stores all the materials’ settings into a texture, with a look up index stored per pixel in the MRT. Everything went fine and smooth, but I dropped it because I don’t have the feeling it’s something necessary.

Read many papers on subsurface scattering, ambient occlusion and parallax mapping.
I had to make sure everything could fit in the current architecture!

Screenshots:


Deferred Shading renderer version! I like this!!! :)
The point light is red, has short range and a high power, the specular highlight looks great. And it’s hundred times better when you can move the camera and lights in real-time! :)

Standard Renderer version.
The floor is a dumb square, so forget about specular lighting. The Point light (at the left) has a small range, that’s it does absolutely nothing on the floor.

Screenshots of the intermediate buffers:


Final Render


Final without Tonemap


Albedo


Position of each pixel in 3D space. Yes you can see the cylinder and the sphere, just look closer! :)


Depth of each pixel


Normal of each pixel


Blurred version, used by the ToneMapping process

First shot of the renderer

I’ve spent too much time the last few days to make D3DX working with Irion.
The library is static, and doesn’t like our custom new/delete operators. The bug is not solved yet (appears to be a problem on the Microsoft’s side), but I temporary bypassed it.

Big big thank to Greeg Peeper from Microsoft for his help and support!

HLSL and D3D .FX roxx
It eases and speeds the work so much. I had several problems (still the mysterious D3DX bug) to compile/open a .fx file in my project, but I guess it only happens to me…

So I started a new Renderer project (IrionSM3Renderer)
Ripped a lot of the code from the IrionDX9Renderer one (Vertex Buffer and other D3D resources creation and maintenance).

Let’s go for the Deferred Shading.

1) Created three Rendering Targets, 32bits wide each.
 The first is D3DFMT_A8R8G8B8 to store the albedo.
 The second is D3DFMT_R32F to store the pixel’s Z.
 The third is D3DFMT_G16R16F to store the X and Y components of the pixel’s normal.
 I think I’ll need a fourth one later to add material properties.

2) Program the following rendering passes:
 • Rendering into the MRTs. Nothing complex, except a little detail I explain below.
 • Do the lighting, for each light I parse the MRTs, computing the lighting for each pixel and accumulate the result in a D3DFMT_A16B16G16R16F buffer (why bother).
 • Display the accumulation buffer by copying it in the back buffer (have to take care of few things to make the 3D GUI Helpers still rendering with the standard path).

As usual, I had few matrices issues, and I also didn’t realised that storing data in the Rendering Target can only be in the [0, 1] range and not [-1, 1] (like the normals…).

All the data are transformed into the camera’s space, I can reconstruct the Normal ’s Z (Z = sqrt(1-X²-Y²)) as I don’t mind about the sign of the vector (always positive in camera’s space).

That’s all for now…Diffuse and Specular lighting is done, with a basic material.

I modified the Test3D program
to be able to switch on the fly between the DX9Renderer and the SM3Renderer.
It’s great, I can see the differences instantaneously!

Screenshots Time!

Per pixel lighting, yummy.

Note: the lighting is not the exact same one because I don’t take into account all the material settings. The specular is not at the same place as the FFP version, I think I’ll figure it out later.

DX9 Fixed Function Pipeline version.

SM3 Renderer

 Ok, I have my new GeForce 6800 GT, the latest beta of the DirectX 9.0c SDK, the latest beta of nVidia’s drivers (SM3 enabled). Let’s start!

I read many papers, watched some samples, I’m getting back in the 3D programming slowly as I spent the past month working on 3D Editor and game logic.

Few words come to my mind: Perspective Shadow Mapping, Parallax Mapping, Ambient Occlusion, HDR, and Deferred Shading.

The most critical part of the brainstorming was: should I go for the Deferred Shading?

I mean the whole technique is really appealing:
 • It’s suited for hardware like the R300 and NV40 (good precision, Multiple Rendering Targets).
 • Come on, true per-pixel lighting!
 • Distinct stages for the rending process: albedo computation/MRT setup, lighting, post process (HDR, Blur, Fog, Glow …), which means high plugability!
 • Perspective Shadow Mapping should work nicely with.
 • It should only get better and faster on next hardware.

But:
 • Hum…transparency? How? Where?
 • Antialising…not so much, but we can walk round this.
 • Can’t use complex Materials such as the ones for SH lighting.
 • High pixel power is needed, can this technique run a great game scene at a suitable framerate on a X800 or 6800 GT?

Ok, let’s do it, the technique itself is so attractive to me, I have to try it out!