# Shadow mapping, bias before the w divide ?!

Hello all,

I am currently following the tutorial from Fabien Sanglard:

I pretty much understand everything except the bias involved when passing the light transformation to the shader:

``````void setTextureMatrix(void)
{
static double modelView;
static double projection;

// Moving from unit cube [-1,1] to [0,1]
const GLdouble bias = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0};

// Grab modelview and transformation matrices
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetDoublev(GL_PROJECTION_MATRIX, projection);

glMatrixMode(GL_TEXTURE);
glActiveTextureARB(GL_TEXTURE7);

// concatating all matrices into one.
glMultMatrixd (projection);
glMultMatrixd (modelView);

// Go back to normal matrix mode
glMatrixMode(GL_MODELVIEW);
}

``````

The fragment shader does something like:

``````
// Vertex shader uses the matrix built in the code:

// Used to lower moiré pattern and self-shadowing

``````

It seems that the viewport scaling is performed before the w divide and I don’t get it, the viewport transform should be done after the w divide.
I have tried to remove the bias and do it after the w divide in the shader:

In the code:

``````

``````

``````

``````

I still get the shadow by doing the view port after the w divide (as expected).

Now I’ve done it on paper and to perform the viewport transform before the w divide doesn’t produce the same result as doing the w divide and then the viewport transform.

I wonder if the graphic result is “OK” looking but mathematically incorrect in this tutorial.

Bump. I followed the same tutorial and also had issues with bias. I ended up using polygon offset, which isn’t a good solution because it can leave 1px gaps at grazing angles.

Polygon offset is a real bad solution, because it’ll work on your graphics card, you switch over to ATI or Intel or whatever, and you’ll get entirely different results …

Polygon offset seems more consistent for orthographic projections, but indeed, another downside is that implementations may vary between vendors.

*Edit: there is an argument to be made for polygon offset though. Read this:
So what’s the GLSL code equivalent to glPolygonOffset?

Another bias solution touted alongside glPolygonOffset (which can suffer depth blow-ups on tangents and allegedly can hurt/kill ZCULL/Hi-Z perf), is tweaking your projection matrix to do a depth offset:

Have read about it but not implemented it, as PolygonOffset works well enough here without any significant perf loss.

I understand that polygon offset allows to tweak the z generated and attempts to solve z-figthing…but I don’t think the bias matrix I mention is trying to achieve this.

It really looks like a [-1,1] -> [0,1] thing…which doesn’t make sense to me.

``````
/ Moving from unit cube [-1,1] to [0,1]
const GLdouble bias = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0};

``````

Yes, you’re right. And your interpretation…:

It really looks like a [-1,1] -> [0,1] thing…which doesn’t make sense to me.

is spot-on. This (effectively) converts a light’s NDC-space X,Y coordinate (-1…1, -1…1) into (0…1, 0…1) for use as a texture coordinate for shadow map texture lookup. It truth it operates in clip-space before the perspective divide, but that doesn’t really matter. (x0.5+w0.5)/w = 0.5*x/w+0.5

This “* 0.5 + 0.5” bias matrix has nothing to do with reducing shadow map acne. I think remdul misinterpretted the meaning of bias here, and then we all chimed in with techniques for reducing shadow map acne. Sorry about that.

Bias alone in shadow map context is ambiguous. Often refers to acne reduction “bias”, but in this context is also used as the name of the NDC-to-texcoord transform.

Just to clarify:

1. Applying bias transform before perspective divide (i.e. in CLIP SPACE):
``````
(x,y,z,w) * bias = (0.5*x + 0.5*w, ..., ..., w)
Then perspective divide = ( 0.5*x/w + 0.5, ..., ... )

``````
1. Applying bias transform “after” perspective divide (i.e. in NDC SPACE):
``````
(x,y,z,w) -> Perspective divide = (x/w, y/w, z/w)
Then apply bias transform = (0.5*x/w + 0.5, ..., ... )

``````