1. Basic issues and related
Common techniques to Improve Shadow Depth Maps:
https://msdn.microsoft.com/en-us/library/windows/desktop/ee416324 (v=vs.85). aspx
cascaded Shadow Maps
https://msdn.microsoft.com/en-us/library/windows/desktop/ee416307 (v=vs.85). aspx
Soft Shadow
Pcss:http://developer.download.nvidia.com/shaderlibrary/docs/shadow_pcss.pdf
Pcss Shader Sample:http://developer.download.nvidia.com/whitepapers/2008/pcss_integration.pdf
Translucent Shadow
Http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/S2008-Filion-McNaughton-StarCraftII.pdf
Http://www.crytek.com/download/Playing%20with%20Real-Time%20Shadows.pdf
Shadows & Transparency
Translucency Map Generation:
- Depth testing using Depth buffer from a regular opaque shadow map to avoid back projection/leaking
- Transparency Alpha is accumulated-only for objects that's not in "opaque" shadows
- Alpha blended shadow generation pass to accumulate translucency Alpha (sorted back to front)
- In case of cascaded shadow maps, generate translucency map for each cascade
- Shadow terms from Shadow map and translucency map is both combined during deferred Shadow passes with Max () operation S
2. Implementation details and issues
Hardware Shadow Map:
D16/d32/d24s8 as RenderTarget.
Hardware PCF:
- Texture sampling turns on bilinear filtering
- D3d9 with Tex2dproj, d3d11 with Samplecmplevelzero
Min Cone (minimal frustum)
With the shadow map map size fixed, the smaller the frustum, the less content on the shadow map (the active content is constant), so the higher the utilization and resolution.
Naive implementation:
1. Calculate the scene bounding box
2. Calculate the most small cone according to the scene bounding box
3. Render Shadow Map
A better implementation:
1. Calculate the scene bounding box
2. crop the bounding box with a scene camera
3. Use the cropped convex hull to calculate the most small cone
4. Render Shadow Map
Because the scene bounding box is clipped by the camera (intersection), so the bounding box becomes smaller, the resulting frustum becomes smaller.
Because the cones are irregular hexahedral, the frustum and the AABB are obtained by a convex hull. The intersection method can be seen ogre, Ogre has convex realization.
I used another method: with the AABB 12 side and the view cone of 6 face intersection, the 12 sides of the cone and the 6 sides of the AABB to intersection, the resulting intersection if at the same time in the AABB and the cone is the vertex of the convex hull.
If you want to calculate the convex hull in light space's bounding box, then you should first transform each vertex to light space, and then the bounding box.
If the bounding box is first asked, the bounding box is transformed to light space, because the axis alignment of the AABB, the transformation will usually become larger.
Depth bias based on frustum Depth range
Because you are using hardware shadowmap, you need to specify depth bias and slope scaled bias.
since Frustum is based on based on the vertex calculation of convex. if the depth range of the frustum (Znear, Zfar) is not fixed, then the same bias value, the corresponding error will be floating.
Therefore, the bias can be calculated according to the depth range of the cone, so that the error value is fixed. Method:
When rendering shadow map depth, only slope scaled bias is specified and no depth bias is specified.
When rendering an object, shadow Matrix = M * light_projection * Light_view, which is multiplied by a parameter matrix M (Depthbias):
floatoffset = isd3d9?0.5f/ (float) shadowmapsize:0f;//Half Texel offset floatBias =-0.0015f/(Depthrange) *Adjustscale; depthbias[0] = Vector4 (1,0.0f,0.0f, offset)); depthbias[1] = Vector4 (0.0f,1,0.0f, offset)); depthbias[2] = Vector4 (0.0f,0.0f,1.0f, bias)); depthbias[3] = Vector4 (0.0f,0.0f,0.0f,1.0f));
At the same time, due to the computed UV to sample shadowmap, for DX9, at the same time can be pre-applied half pixel offset.
Pcss :
The principle of pcss is relatively simple and there are many variants. The standard implementation is currently in use. Problems encountered:
The penumbra sampling range of PCSS is based on similar triangles.
float Penumbrasize (floatfloat//Parallel plane estimation{ return (zreceiver-zblocker)/ zblocker;}
If the depth of the zblocker is too small (close to 0), then the penumbra sampling range becomes very large and difficult to accept.
This happens when you do self shadow, because the cones are very small. Workaround:
1. The user specifies the size range of the penumbra (shader constant, lightwidthmin, Lightwidthmax) and then makes linear interpolation based on the depth (distance).
or 2. Enlarge depth Range so that the smallest depth is not close to 0
If the shadowed object and the object receiving the shadow are too close, the zreceiver-zblocker is too small, causing the penumbra to be close to 0, leading to aliasing:
The solution can be interpolated with the above linear interpolation, since the linear interpolation minimum is lightwidthmin, guaranteeing the smallest penumbra range.
Or: Add a constant value to the penumbra range, such as 1.0/shadowmapsize
Individuals use lightwidth_min and Max linear interpolation, which also facilitates fine-art control parameters.
Translucent Shadow (not alpha test):
Crytek and Starcraftii have been posted on the above methods, the way is more similar.
Here's my simple implementation:
R8 + Depth16, alpha and depth are plotted simultaneously, a color buffer holds alpha, and a depth buffer saves depth.
Opaque:depth test-less, disable color write.
Transparency:depth test-less, disable Z write, output alpha, enable color blending (addative)
This method is relatively simple, one draw without the render target switch, first draw an opaque object and then draw a translucent object. The Shadow judgment for Alpha in shader is also more hacky: if the alpha value (R8.COLOR.R) is not 0, it is considered to have a shadow and does not require a depth of comparison. Because the alpha value can be written, the depth test does not pass. For pcss that require depth, you can simulate a depth value.
Issue: Self-shadowing is not supported (doesn ' t support auto Shadow). The translucent object that produces the shadow itself, if you want to calculate the shadow, according to alpha!=0 this judgment, also has the shadow ...
How to Improve:
Based on the above method, the transparent objects is added with a depth pass, and two depth graphs are sampled when the shadow is drawn. or change the previous R8 to Rgba, a save transparency, RGB package depth, and separate alpha channels, so you don't have to switch render target.
Two depth pass words more a D16 map, memory consumption is smaller than RGBA.
Problem: Self-shadowing error
| | |
A1 A2 O
As above, O is an opaque object, A1 and A2 are transparent objects.
When multiple layers of transparent objects appear, the shadow of O is right because the alpha of A1 and A2 is mixed.
Based on the above improvements, because of the depth of information, coupled with bias, so A1 will not have a shadow, is also right.
But the shadow of A2 is the same as the shadow of O, and is calculated based on the same alpha. Because A2 is translucent, the shadow performance is not so obvious, the problem here can be ignored.
Or: Use depth to do linear interpolation:
Shadow (UV.XYZ) = Lerp (1-ALPHA_A1A2, 1, saturate ((depth_o-uv.z)/(DEOTH_O-DEPTH_A1)));
Where uv.z is the depth of the current object in the shader. ALPHA_A1A2 is the result of alpha blending. Depth_o is the depth sampled by opaque shadow map. DEPTH_A1 is the depth sampled by transparent shadow map.
This is still not true, because the shadow transparency of the A2 is 1-alpha_a1, independent of distance, but it can solve the z fighting and shadow acne when transparent objects and opaque objects are too close to each other.
Above is the main problem in the work. Another simple record of something else.
Csm
If all the shadows are generated on a single shadowmap, the near resolution is also lower. The CSM mainly uses multiple cascade to improve the shadow resolution near the vicinity.
Previous work has also done PSSM, generally will put a number of shadowmap on a sheet, such as 4 1024x1024 shadowmap, you can use 2048x2048 map, through viewport to draw four areas. The above Crytek also mentioned.
There is also a need for blend processing in the CSM boundary Division, otherwise there will be gaps.
Psm
The biggest feature of Perspect is its near-large size, so the pserspective projection is used to improve the resolution of the near Shadow.
But the general direction light is the parallel light, needs to use the orthographic (parallel) projection, but because the general scene camera is perspective, the frustum is not the box, but after the projection (post perspective space) is a box, D3D is z[0,1] 's flat box, OGL is a cube. In this space, because the direction will have shear, so the direction of the original World space Light to the post perspective space has become a point of light, you can use perspective projection.
The principle is basically this, the implementation of the words will be more tricky.
Another light space perspective Shadow Map (LISPSM) is a PSM, or a perspective projection to improve the accuracy of the near projection. The main change is not to use the scene camera's post perspective space. Because most of the direction in the perspective projection will be deformed, the direction perpendicular to the view direction (parallel to the XY plane) will not change. LISPSM is using this to render depth using a perspective projection that is perpendicular to the illumination direction. If rendered directly with this frustum, the Y value is the depth value along the illumination direction. So first the light space is transformed to the direction of the light, in the transformation back, the resulting z is the depth. This implementation is much simpler than PSM. I've tried it, but it's not very different from the general shadow map, which may be a bit of a problem with the implementation, or a self-shadowing problem that only renders a character.
[Work accumulation] Shadow map problem summary