   Shadow Mapping for large terrain - Help Needed!!!
  Hi;I am try to implement shadow mapping for my terrain. So far; it turned up to be the most terribly, damned problematic thing in 3D programming I have ever got myself into. For the moment, my shadow mapping logic works like that: I stuff all terrain nodes(quadtree leaf nodes) visible by my viewing frustum into a bounding volume(not an AABB exactly, a more tighter one). After that, I project the bounding volume corners onto the shadow plane.(The light comes from the sun, it is directional lighting.) Then I build a lighting frustum,a box actually, and obtain lighting modelview and projection matrices out of it. The rest is usual shadow mapping.I am using a 1024x1024 shadow map and suffering from very disturbing aliasing. Increasing the resolution helps, but increased fill rate hits the performance badly. I will switch to parallel split shadow maps to improve this.The other problem is the worst one. My system does have terrible shadow leaking/bleeding artifacts which I couldn't get rid off! I only let the back faces of the terrain polygons to be drawn on the shadow map, and to prevent light from leaking on these back faces, I add a negative bias from the shadow values read from the shadow map.It seems every shadow mapping implementation suffers from a certain amount of bleeding, but mine is just untolerable, especially when the light direction gets more horizontal.Here is a link showing the situation:http://img32.imageshack.us/img32/1553/bleeding.jpgI am using a 1024x1024 Shadow Map here and PCF, too. The code in the pixel shader is:float s0=(tex2D(ShadowMap,shadowMapUV.xy).r  - 0.01    < input.shadowMapPos.z) ? 0.0f : 1.0f;float s1=(tex2D(ShadowMap,shadowMapUV.xy + float2(texelSize,0.0f)).r  - 0.01 < input.shadowMapPos.z) ? 0.0f : 1.0f;float s2=(tex2D(ShadowMap,shadowMapUV.xy + float2(0.0f,texelSize)).r  - 0.01   < input.shadowMapPos.z) ? 0.0f : 1.0f;float s3=(tex2D(ShadowMap,shadowMapUV.xy + float2(texelSize,texelSize)).r - 0.00 < input.shadowMapPos.z) ? 0.0f : 1.0f;float2 ab  =frac(input.shadowMap_unNorm.xy);float2 _1_ab=float2(1.0f,1.0f)-ab;float shadowCoeff=_1_ab.x*(_1_ab.y*s0 + ab.y*s2) + ab.x*(_1_ab.y*s1 + ab.y*s3);I am using higher bias values but they don't help. I have learned about OpenGL's glPolygonOffset; and tried to emulate in Direct3D: In the pixel shader for the shadow map, i do:struct PS_INPUT{float4 Pos : TEXCOORD0;};float4 Main(PS_INPUT input) : COLOR{float3 Pos=input.Pos;float slope_bias=max(abs(ddx(Pos.z)),abs(ddy(Pos.z)));return float4(Pos.z-slope_bias,0.0,0.0,1.0);};This, too, turned out to be bogus.I need to finish this project in 2 weeks, but this problem hindered me so bad and I am running out of time. What should I do, what are your suggestions?Thanks in advance   
  Yup, the image looks bad...Shadow for terrain is not an easy task. From the image I would say the calculation is completely wrong.Rendering back faces of the terrain is not going to help you, since the terrain is not a closed shape (actually it shouldn't work at all unless you duplicated each face and set the normal in the opposite direction of the original face).I don't understand the last three lines of your code. The correct code should be:float shadowCoeff= (s0+s1+s2+s3) * 0.25;Also when you calculate s3 you are not using any bias. You should use the same bias for all samples.Since you have two weeks you should consider implementing one of the cascaded shadow algorithms which yield good results (google for cascaded shadow maps, or parallel split shadow maps).Another improvement would be to find the right bias. Change your code so the bias is a variable that can be changed dynamically during runtime. Then you can tune it to the right value (finding a proper value makes a big difference).If any of this doesn't work or make sense to you, please post a grayscale image of your shadowmap and the code for calculating the lights transformation.   ;Quote:Rendering back faces of the terrain is not going to help you, since the terrain is not a closed shape (actually it shouldn't work at all unless you duplicated each face and set the normal in the opposite direction of the original face).Why do you think so? The terrain is not a closed object, but it acts like one. Imagine a hill for example, you can only draw the polygons which face to the backside according to the light's point of view, and these polygons will constiute the occluding geometry correctly. I made a simple drawing to show this: http://img39.imageshack.us/img39/3542/backface.jpgBy the way, I draw to the shadow map both with the front and back sides culled in different times and the result doesn't change.(Well of course, the shadows begin to leak on the front sides of the terrain, when rendering the front faces)I mistakenly forgot the bias number of s3 in my code, but this doesn't affect something much.I already dynamically change the bias, but the problem won't go away: Those "streched" shadows just change their shapes. They get more thick or thin, depending the amount of bias. When I switch to a bigger resolution shadow map (2048x2048,4096x4096) the flaw seems to begin to heal by some amount. In those scenes the light's direction is nearly horizontal. (-0.5,-0.1,1.0) Those flawed triangles are mostly the ones which are flat; dot(Triangle.Normal,LightDirection) is very close to 0 at those. I think this can be some sort of very magnified aliasing but I still can't find the exact reason.   ;  Nice discussion!I'm sorry i can't help you over suggest using Trapezoidal Shadow Mapping instead of parallel split.I'll stay tuned.   ;  Nice discussion!I'm sorry i can't help you over suggest using Trapezoidal Shadow Mapping instead of parallel split.I'll stay tuned.   ;  The single easiest thing you can do to improve quality is to use Variance Shadow Maps. Tutorial.Easy to implement: use a FP32 texture for your shadow map (rg channels are sufficient) and store distance and distance ^ 2 into the two channels.Then instead of a boolean shadowing function (shadow ? 1.0 : 0.0) use a distribution like below and multiply your fragment by the result:float chebyshevUpperBound(float distance){// We retrieve the two moments previously stored (depth and depth*depth)vec2 moments = texture2D(ShadowMap,ShadowCoordPostW.xy).rb;// Surface is fully lit. as the current fragment is before the light occluderif (distance <= moments.x)return 1.0;// The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check// How likely this pixel is to be lit (p_max)float variance = moments.y - (moments.x*moments.x);variance = max(variance, 0.00002);float d = distance - moments.x;float p_max = variance / (variance + d*d);return p_max;}Don't forget to enable texture filtering for improved looks. You can even apply a separable gaussian filter to smooth the shadow even more. Finally, with this method you don't need to bias your shadow map anymore.And I agree with your sentiment. Shadow mapping is the single biggest damn problem in realtime 3d graphics.   ;Quote:Original post by 67rtyusWhy do you think so? The terrain is not a closed object, but it acts like one. Imagine a hill for example, you can only draw the polygons which face to the backside according to the light's point of view, and these polygons will constiute the occluding geometry correctly. I made a simple drawing to show this: http://img39.imageshack.us/img39/3542/backface.jpgI don't think it would matter whether you draw the back faces or the front faces (it's only a matter of switching the winding order), see:If the orange X is what you've stored in your shadow map (since you've used an offset) then when you go to draw the green X, it's obviously not in shadow, when you go to draw the red X, it's obviously in shadow. The problem is the tip, which is where I can see most of your problems seem to be coming from, it doesn't really matter what you use as the offset, it'll always be wrong in certain cases.I think the terrain you're using is kind of pathalogical in the sense that it's got a lot of little "tips". If your terrain was more rounded and less "bumpy" you might see that it's actually not so bad...I think if you implemented one of the other shadow-map techniques, you'll see some improvement.   