I’ve gotten a late start on this rendering thing. One of the pieces I’ve been struggling with is math. I’ve improved quite a bit over the past year and I’m actively educating myself to catch up. Recently, a friend of mine asked me for some help with a matrix problem. Here’s what I told him to help him debug (I wish I could go back in time and tell myself this!):
- If you’ve got a series of matrix multiplications, make all of the terms identity. Then change each to be a real value one by one. For example: Let’s say you’re rendering an object with a lot of sub-meshes or sub-objects. You’d set the subobject’s transforms to identity and the main object’s transform to identity. This will make everything render on top of each other. From here, you concentrate on getting the sub-objects transforms correct, then finally work on the main object’s transform.
- Try creating situations where the results of an equation would be identity. For example: When using a shadow map, you need a matrix which transforms a point from camera space to light space. If the camera and the light have the same transform (and FOV, view distance, etc) then this matrix will be identity. If you run it through your code and it’s not, you know you’ve got some problems to solve!
- Pay close attention to what space your source data is in. If you feed object space points to a function that expects world space points, it’s not going to work!
- Check out Octave, it’s basically a free version of MATLAB. You can use this to play with matrices and vectors, probably much quicker than you can do in-engine.
These are just general divide and conquer debugging tips applied to math. But for a person new to large amounts of math in programming, it can be non-obvious to think about applying those debugging techniques to math problems. Does anyone out there have their own favorite math debugging tips?
Let’s say you’ve got a render state problem. If object A is on the screen at the same time object B is on the screen, object A gets screwed up. Here’s a quick way of using PIX to track it down:
- Take a snapshot of the frame that works and a snapshot of the frame that fails.
- In PIX, find the draw call that draws object A in the frame that works
- Go to the device state tab
- Copy and paste each page of state into a text file
- Repeat for the frame that fails, save this to a separate text file.
- Diff the text files with your favorite diff tool!
This is much easier than trying to diff the states manually within PIX itself. PIX should have a draw call diff as part of its standard functionalty!
I’ve only been doing graphics stuff seriously for about a year. One of the first things I tackled was shadow mapping. I got a simple shadow map implementation going and then implemented Variance Shadow Maps. It’s based on statistics and the big deal is that you can filter your shadow map and get filtered shadows as a result. At the time, I didn’t understand why that was true. I had assumed it was a special property of the Chebychev Inequality. I just implemented it and went on. Yesterday, I quickly tested Exponential Shadow Maps. While looking at it, it finally struck me why it was filterable:
These new shadow map techniques are smooth functions based on the occluder and receiver distances to the light!

Above is my Microsoft Paint created graphs (grabbed this style of graphing from Pat Wilson heh). On the left is ESM, you can see that it smoothly drops from 1 (fully lit) to 0 (fully shadowed). So if you massage your shadowmap and you get values on the x-axis (which is occluder – receiver), you’ll see that there will be a border of grey values (basically from -5 to 0 in the graph above, btw this is not what e^(c*o-r) actually looks like, heh). On the right, standard shadow mapping is just a step function. If you move this a little bit below zero, you’re immediately shadowed completely.
This is a also a reason why you don’t need to worry about shadow map bias as much with these new techniques. Because the shadow function isn’t all or nothing, if occluder – receiver is -.9999, you’re going to look basically lit. But in standard shadow mapping, -.9999 is fully shadowed, and you’ll get shadow acne.
So you could draw any random function as a 1d texture and use that for shadow mapping! These other techniques are just ways of creating that function in a way that is fast and makes sense visually.
The silly thing is that I knew why standard shadow maps were not filterable from the get-go, I just didn’t “invert” my thinking to figure out why these new methods were filterable.