Closed matt77hias closed 7 years ago
I finally found the cause of the problem. There appears to be a problem with the shadow map of both the omni light and spotlight. While debugging, I noticed by accident that the light-view-to-light-projection (lview_to_lprojection
) 00
and 11
matrix entries were not equal. Due to the aspect ratio of 1, both matrix entries must be equal. Furthermore, due to the FOV of $\pi/2$, these matrix entries must be equal to 1 (assuming no floating-point precision issues).
The constructor of my PerspectiveCamera
class expects a width
, height
, FOVy
, near
, far
order or aspect ratio
, FOVy
, near
, far
order and correctly handles the creation of the view-to-projection transformation matrix via redirecting to XMMatrixPerspectiveFovLH
expecting a FOVy
, aspect ratio
, near
, far
order. Since, I did not want to create a corresponding PerspectiveCamera
for each light per frame, I bypassed that class by directly providing a member method in my OmniLight
and SpotLight
classes redirecting to XMMatrixPerspectiveFovLH
using the wrong order of arguments. This explains why the above images are wrong.
The generated shadow map of the spotlight is still equal to one of the six shadow maps of the omni light, although both use the same but wrong world_to_lprojection
transformation matrix (which contains the wrong lview_to_lprojection
transformation matrix). The HLSL code for the spotlight uses the cview_to_lprojection
transformation matrix, which includes lview_to_lprojection
, and thus will perform the "right" mapping. The HLSL code for the omni light uses the cview_to_lview
transformation matrix, which does not include lview_to_lprojection
, and thus will not take the non-uniform scaling of the 00 and 11 entries into account, resulting in some non-linear stretching and thus the wrong mapping. This explains why the above images differ for the omni light and spotlight.
After fixing the bug:
Omni Light (6 faces) shadow factor:
Omni Light (1 face) shadow factor:
Spotlight shadow factor:
SampleCmpLevelZero
When using this method on a signed-normalized or unsigned-normalized format (which is the case), the comparison value is automatically clamped between 0.0 and 1.0. The two perspective cameras looking along the positive or negative x-axis (along the middle hallway) associated with the omni light, will have "rays" which are not occluded by the scene's geometry due to the far plane at distance 3. Therefore, these pixels (displaying the shadow factor) will always be lit for comparison values larger than or equal to 1.0f
(since all such values are clamped to 1.0f
).
Spotlight
My spotlight's intensity is cut off at a distance of 3 and at an angle of $\pi/4$ radians (umbra angle). The corresponding light camera has a near plane at a distance of 0.1, a far plane at a distance of 3, an aspect ratio of 1 and a vertical/horizontal FOV of $\pi/2$. The spotlight is positioned somewhere above the tree and faces downward to the floor.
The shadow map of my spotlight has a resolution of 512x512. I use the following DXGI formats:
DXGI_FORMAT_R16_TYPELESS
: texture resource;DXGI_FORMAT_D16_UNORM
: DSV (one for each spotlight);DXGI_FORMAT_R16_UNORM
: SRV (oneTexture2DArray
for all, spotlights).My shadow factor is calculated in HLSL as:
Here, the hit position in light projection space coordinates is calculated as follows from the hit position in camera view space coordinates (shading space):
I obtain the following images after visualizing the shadow factor (this is not the light contribution of the spotlight) (and some linear fog as well):
This seems to result in the correct behavior (see the shadows of the leaves, pillars and curtains). The bright border on the first image starts at the position of the spotlight and is due to the near plane distance of 0.1. This border will completely vanish after multiplying the shadow factor with the spotlight's contribution.
Omni light
My omni light's intensity is cut off at a distance of 3. The corresponding light camera has a near plane at a distance of 0.1, a far plane at a distance of 3, an aspect ratio of 1 and a vertical/horizontal FOV of $\pi/2$. This means that one of the six light cameras (after applying some rotations), is completely identical to the spotlight camera above. I double checked this in the code:
Frame 1:
world_to_lprojection
(spotlight):world_to_lprojection
(fourth omni light camera):world_to_lprojection
represents the world-to-light-projection transformation matrix (world-to-camera-view-to-world-to-light-view-to-light-projection). I go to camera view first to mimic the same multiplications between my depth passes and shading passes to reduce z-fighting (although, this does not result in visual differences so far).So apart from the fact that a spotlight corresponds to one DSV (and is part of one SRV to a
Texture2DArray
for all spotlight shadow maps) and an omni light corresponds to six DSVs (and is part of one SRV to aTexture2DCubeArray
for all omni light shadow cube maps), the shadow map generation is pretty much the same for both types of lights.The shadow map of my omni light has a resolution of 512x512. I use the following DXGI formats:
DXGI_FORMAT_R16_TYPELESS
: texture resource;DXGI_FORMAT_D16_UNORM
: DSV (one for each omni light);DXGI_FORMAT_R16_UNORM
: SRV (oneTexture2DCubeArray
for all, omni lights).My shadow factor is calculated in HLSL as:
Here, the hit position in light view space coordinates is calculated as follows from the hit position in camera view space coordinates (shading space):
The conversion of the z coordinate to NDC space is done as follows:
with the following dual C++ method:
I obtain the following images after visualizing the shadow factor (this is not the light contribution of the omni light) (and some linear fog as well):
This is clearly wrong. All six shadow maps seem kind of stretched. Without the stretching, the curtain's shadow would still be in the close vicinity of the curtain itself and the leaves' shadow would be much smaller (equal to the leaves' shadow for the spotlight). Furthermore, the circular shadow at the end of the pillar's shadow is associated to the buckets in front of the curtains.
Any ideas what goes or could go wrong?
For clarity, the following two images show the shadow factor of the cube map face corresponding to the spotlight, for the omni light by adding:
The lit area seems a bit (how much?) larger than for the spotlight.
SampleCmpLevelZero
An other strange observation is that using a depth value of 1.1 for my spotlight's PCF filtering (
SampleCmpLevelZero
) always results in a 0 value as expected:whereas for my omni light this is not the case:
Even if I use a value equal to 100000.0, I'll notice lit areas?
Depth Biasing
I use
DepthBias = 100;
(to prevent shadow acne; note that I use 16bit depth maps)SlopeScaledDepthBias = 0.0f; DepthBiasClamp = 0.0f;
for all my Rasterizer states.PCF filtering
I use the following sampler comparison state for PCF filtering (my shadow maps have no mipmaps) for both spotlights and omni lights.