shadow mapping을 위해 DSV resource를 SRV에 바인딩하여 작업을 진행하였다. 다만 문제가 발생한 부분은 물체의 깊이 값을 비교할 때 발생하였다.
Shadow Mapping을 통하여 그림자를 그리는 원리는 단순한다.
1. Shadow Viewport로 설정하여 Shadow Mapping을 위한 '조명' 시점의 Depth Map을 그린다.
2. 그린 Depth Map을 Lighting HLSL에 연결한다.
3. 가져온 [1] Depth Map의 깊이값과 [2] 현재 Lighting을 그리고 있는 물체의 '조명' 시점에서의 깊이 값을 비교한다.
4. 만약, 현재 그리고 있는 물체의 '조명' 시점의 깊이 값이 클 경우 그림자를 인식한다.
이것은 Depth Map을 그릴때 조명이 물체 뒤에 가려진 부분에 대해서는 인식하지 않는다는 것을 이용 한것이다. 가려진 부분에 대해서 Lighting을 그릴 때 조명의 앞을 가리는 물체가 없는 상태에서 서로의 깊이 값을 비교해 그림자를 인식하는 것이다.
즉, [2] > [1] ? 1.0 : 0.0
과 같은 식이다.
발생한 문제점은 [2] 깊이 값이 항상 크게 나온다는 문제가 발생하였다.
float4 lightScreen = mul(float4(posWorld, 1.0), shadowData.lightViewProj);
lightScreen.xyz /= lightScreen.w; // Clip -> NDC
// 2. [-1, 1] -> [0, 1]
lightScreen = lightScreen * 0.5 + 0.5;
lightScreen.y = 1.0 - lightScreen.y; // texcoord는 y축 방향이 다르므로
float closestDepth = ShadowMap.Sample(LinearClampSampler, lightTex.xy).r;
float currentDepth = lightScreen.z;
shadow = closestDepth; // [1]
shadow = currentDepth; // [2]
.
.
.
return float4(ambient + (diffuse + specular) * (1.0 - shadow), 1.0);
위 사진에서 확인해본다면,
[1]이 확실히 낮은 곳(shadow 값)이 있는 것을 볼 수 있다.
[2]의 값의 경우에는 조명시점에서 해당 물체를 그릴 때의 깊이값을 shadow값으로 적용했기 때문에 조명시점에서의 해당 물체의 깊이 값이 적용되어, Lighting 자체가 전반적으로 약해진 것을 볼 수 있다.
왜 항상 currentDepth > closestDepth 인 것일까?
- 말 그대로 CurrentDepth값이 항상 크다.
- 왜 항상 큰 것일까? 둘은 똑같은 View * Proj 행렬을 통해서 변환이 된다.
- 기존의 shadow map에서 그려지지 못했던 물체의 뒷쪽 평면의 깊이 값에 대해서 Lighting 과정에서 그리게 된다.
- 물체 뒷쪽 평면의 '조명' 시점의 깊이 값을 알 수 있게 되고 그것을 이용해 shadow map과 비교해 그림자를 인식해야 한다.
- 근데? 물체 뒷쪽 부분의 평면말고도 다른 부분들이 모두 currentDepth가 크게 나온다. 이 이야기는 평면부분의 shadow map하고 Lighting 할 때 조명 시점에서의 평면 깊이값을 비교하게 되는데 여기서 문제가 발생한다는 이야기다.
1. 평면을 shadow map을 그릴 때 포함하지 않는다.
하지만 해당 해결방법은 단순해서 확장성과 코드 작성에 악영향을 줄 수 있다.
2. camera 시점의 viewPos에서 조명 시점에서의 좌표로 변경해보자!
float4 shadowMapCoords = mul(float4(viewPos, 1.0), shadowData.shadow_matrices[0]);
float3 UVD = shadowMapCoords.xyz / shadowMapCoords.w;
UVD.xy = 0.5 * UVD.xy + 0.5;
UVD.y = 1.0 - UVD.y;
shadow_matrices[0]은 camera의 invView * 조명의 viewProj을 곱한 값이다. 이러한 방식을 통해서 값을 도출하였더니 어느정도 동작하는 것을 확인할 수 있었다.
(P.S. 해당 방법이 해결방법으로 통한다는 의미가 이상하긴 하다. 기존 방법과 차이점이 없기 때문이다. world->light view->light proj 하는 방법이랑, camera view->world->light view->light proj 결과적으로 똑같을 수 밖에 없기 때문이다. 이것은 내가 world 좌표계를 구할때 행렬곱하는 계산의 어느부분을 실수한게 아닐까 싶다..)
다만, 아직도 그림자 구현이 이상한 것을 알 수 있다.
추측하기에는 RasterizerState에서 Cull 모드를 Back을 한 상태로 shadow Map을 그렸기 때문에 이러한 현상이 나타나는 것으로 짐작할 수 있다. 실제로 Cull 모드를 Front로 변경하게 되면 해당 현상이 확연하게 완하되는 것을 볼 수 있었다.
약간 줄이 나타나 있는 것을 볼 수 있었는데, 이 부분은 Bias 값을 조절함으로써 해결할 수 있었다. Lighting에다가만 그림자 효과를 적용함으로써 더욱 더 사실적인 그림자를 표현할 수 있게 되었다.
'Graphics' 카테고리의 다른 글
AABB에 대해서 (0) | 2024.07.30 |
---|---|
bug : camera의 Projection 행렬 값 오류 (0) | 2024.07.24 |
ECS에 대해서 - 1편 - (0) | 2024.07.18 |
bug : ResizeBuffers() 가 정상작동하지 않는 문제. (0) | 2024.07.17 |
bug : Shader stage did not run (0) | 2024.07.17 |