Hi,
I have found this paper dealing with how to compute the perfect bias when dealing with shadow map.
The idea is to:
- get the texel used when sampling the shadowMap
- project the texel location back to eyeSpace (ray tracing)
- get the difference between your frament.z and the intersection with the fragment's face and your ray.
This way you have calculated the error which serve as the appropriate bias for z-fighting.
Now I am trying to implement it, but I experiment some troubles: I am using a OrthoProjectionMatrix, so i think I don't need to divide by w back and forth.
I am good until I am computing the ray intersection with the face. I have a lot of faces failing the test, and my bias is way to important.
This is my fragment shader code:
float getBias(float depthFromTexture)
{
vec3 n = lightFragNormal.xyz;
//no need to divide by w, we got an ortho projection
//we are in NDC [-1,1] we go to [0,1]
//vec4 smTexCoord = 0.5 * shadowCoord + vec4(0.5, 0.5, 0.5, 0.0);
vec4 smTexCoord = lightProjectionMatrix * lightFragmentCoord;
smTexCoord = 0.5 * smTexCoord + vec4(0.5, 0.5, 0.5, 0.5);
//we are in [0,1] we go to texture_space [0,1]->[0,shadowMap.dimension]:[0,1024]
//get the nearest index in the shadow map, the texel corresponding to our fragment
//we use floor (125.6,237.9) -> (125,237)
vec2 delta = vec2(xPixelOffset, yPixelOffset);
vec2 textureDim = vec2(1/xPixelOffset, 1/yPixelOffset);
vec2 index = floor(smTexCoord.xy * textureDim);
//we get the center of the current texel, we had 0.5 to put us in the middle (125,237) -> (125.5,237.5)
//we go back to [0,1024] -> [0,1], (125.5,237.5) -> (0.125, 0.235)
vec2 nlsGridCenter = delta*(index + vec2(0.5f, 0.5f));
// go back to NDC [0,1] -> [-1,1]
vec2 lsGridCenter = 2.0 * nlsGridCenter - vec2(1.0);
//compute lightSpace grid direction, multiply by the inverse projection matrice or
vec4 lsGridCenter4 = inverse(lightProjectionMatrix) * vec4(lsGridCenter, -frustrumNear, 0);
vec3 lsGridLineDir = vec3(normalize(lsGridCenter4));
/** Plane ray intersection **/
// Locate the potential occluder for the shading fragment
//compute the distance t we need to continue in the gridDir direction, the point is "t" far
float ls_t_hit = dot(n, lightFragmentCoord.xyz) / dot(n, lsGridLineDir);
if(ls_t_hit<=0){
return 0; // i got a lot of negativ values it shouldn t be the case
}
//compute the point p with the face
vec3 ls_hit_p = ls_t_hit * lsGridLineDir;
float intersectionDepth = lightProjectionMatrix * vec4(ls_hit_p, 1.0f).z / 2 + 0.5;
float fragmentDepth = lightProjectionMatrix * lightFragmentCoord.z / 2 + 0.5;
float result = abs(intersectionDepth - fragmentDepth);
return result;
}
My intersectionDepth don't match my fragmentDepth, they should be really close
I am struggling with this line of code and the ray plane intersection:
vec4 lsGridCenter4 = inverse(lightProjectionMatrix) * vec4(lsGridCenter, -1.0, 0);
I need to go from NDC space to Eye space, i don't know what should be my z and w component. I am starting with a point in the shadowMap I think my z component should match the near plane so in NDC space it should be -1 but i am not sure. Same for w it's a ray so maybe 0 is a better a choice than one.
I don't know if my plane/ray intersection is wrong but from wikipedia:
\(d = { dot(Po - O) \cdot n \over dir \cdot n}\)
where:
- dir = my vector normalized direction
- Po = a point belonging to the the plane
- O = point belonging to the ray, the origin should match. in eye space the origin should be my light position -> (0,0,0) ?
- n = normal of the plane, the normal of my fragment in eyespace