Shadow Mapping

来源:互联网 发布:淘宝便宜又好的文具店 编辑:程序博客网 时间:2024/05/23 19:13
 

What is shadow mapping?

  Shadow mapping is a graphical technique for rendering 3D object's shadow in the real time. Comparing to the Shadow Volume technique, Shadow mapping is ususally faster-run and easier-code.

Figure 0: Shadow...............by Shadow mapping

 

 

 

 

How does shadow-mapping work?

  The main theory of shadow mapping is so intuitive: what light can see will be lit, while what light can't see will be shadowed.

Figure 1: What light can see will be lit. ( from light's perspective space )

 

 

 

Figure 2: What light can't see will be shadowed.

 

  So firstly, I use the "renderShadow" technique to set up every single object's own world matrix, set up light's ViewProj matrix, change every vertex to the light's perspective space, and render these vertices' z and w to a texture called "shadow map", which will hold the smallest depth that light can see. This texture can help the latter shader to answer "if a pixel's depth is given, can the light see this pixel?"

Figure 3: Shadow map( Nearest depth that the light can see in every texel,

The darker the texel is, the nearer the texel is.)

 

  Now I have the shadow map. The next technique I use is called "renderScene", which means that render the scene with shadow map.

 

  While processing, vertex shader not only changes vertex to viewer's space, but also changes it to light's perspective space, and pass these two kinds of vertex to the pixel shader with semantic POSITION and TEXCOORD2 correspondingly. The vetex in view's space is used as the very ordinary scene rendering technique. So let's focus on the vetex in light's perspective space.

 

  When in the pixel shader, it uses the vertexInLight( proecssed after rasterization and it is interpolated vertex data, I call it pixelInLight henceforward ) to generate the coordinates UV in the shadow map texture to read the texel's value, and compare this value with pixelInLight's depth. If pixelInLight's depth is greater, it means the light can't see this pixel, then this pixel won't be lit, and I use a daker lighting calculation on it. If pixelInLight's  depth is less, it means the light can see this pixel, then a lighter calculation is performed.

 

 

 

Bugs

 OK! I've render the scene with shadow successfully!

  However, there are two kinds of aliasing in the shadow!

  The first one, is the zigzag along the edge of the shadow. This makes sense, because the shadow map's resolutin is limited, and hundred of different interpolated vertex data is compared with the same texel in the shadow map, the zigzag appear. This phenomenon can be reduced by increasing the resolution of the shadow map or applying the shadow blur technique:

(lightAmount=lerp(  lerp( sourceVal[0], sourceVal[1], lerps.x ), 
                lerp( sourceVal[2], sourceVal[3], lerps.x ), 
                lerps.y );).

 

Figure 4: Zigzag of the shadow

 

 

 

  The second kind of aliasing is the strange texture in the shadow or even out from the shadow.

 

Figure 5: Strange texture in or out the shadow

 

  What the hell is this?!

  Well, this is caused by a prevalent graphical problem called the "z-fighting".Why "z"? Because we use z to compare with each other; Why "fighting"? Because during the comparison, two z values are very close to each other, and the computer can't clearly detect who wins the comparison or loses the comparison by current prcision of the floating point data, then the aliasing occures.

  The solution for z-fighting is simple: help the shader to compare these two z values.

  One method is tricky: I bias one z value by stealth, and of cause, computer can easily compare them now.

  And another method is to increase the prcision of the data: Shrink the projection frustum. Because in the frustum, x and y are in [-1, 1], and z is in [0, 1], therefore, the fitter the shadow frustum is for the scene, the more precision the shadow map can offer. So, fov should be less, Zn should be less, and Zf-Zn should be less.

原创粉丝点击