프로그래밍 2016. 1. 25. 21:30
728x90
vsm with cascade shadow map 1

 

 

캐스캐이드 기법에 대한 내용을 살펴보자.

밑의 사이트에 cascade shadow map 에 대한 이론이 설명되어 있다.

 

마이크로 소프트

https://msdn.microsoft.com/en-us/library/windows/desktop/ee416307(v=vs.85).aspx

 

NVidia

http://developer.download.nvidia.com/SDK/10.5/opengl/src/cascaded_shadow_maps/doc/cascaded_shadow_maps.pdf

 

 

이 기법에서 프로그래밍적으로 핵심적인 부분은

적절하게 라이트 뷰를 나누는것과,

쉐이더 코드에서 그림자 텍스쳐로 부터 뎁스값을 가져올때,

픽셀과 카메라의 거리값으로 그림자 텍스쳐의 인덱스를 얻어 오는 것이다.

( 그림자 텍스쳐가 근,중,원거리 3개가 사용되었다면,

자신의 픽셀이 참조해야할 하나의 텍스쳐를 알아내는것 )

 

 

코드로 설명하자면,

(zMatrixLookAtLH 등의 함수는 모두 dx함수로 치환할수 있다.)

 

//그림자 뎁스값 생성을 위한 light view

zMatrixLookAtLH( &_matLightView[_iIdx], &light_pos, &light_at, &Vector3(0.f, 1.f, 0.f) );
zMatrixOrthoLH( &_matLightProj[_iIdx], fW, fW, 0.01f, fZ ); 
zMatrixMultiply( &_matLightVP[_iIdx], &_matLightView[_iIdx], &_matLightProj[_iIdx] );

 

필요한 것은

라이트 위치와, 라이트가 바라보는 타겟의 위치

라이트뷰의 넓이와 z 깊이이다.

 

라이트뷰의 넓이와 z 깊이 값이 커질수록, 그림자의 퀄리티는 떨어지게 되므로,

최대한 작게 잡는 것이 그림자의 퀄리티를 높이는데 도움이 된다.

 

 

만들어진 뷰프러스텀으로부터 카메라 위치와의 최대 거리값을 구하려면,

프러스텀을 구성하는 8개의 꼭지점을 구한후

원단면에 해당하는 꼭지점과, 카메라와의 거리를 계산하면 된다.

zMat 등은 모두 dx 구조체로 치환시킬수 있다.

 

const float CalcFarClipDist_Frustum( zMatrix* _pmatV, zMatrix* _pmatP, const Vector3 _vPos )
{
     zMat MatInv, MatVP;
     Vector3 V[8];

 

     V[0].x = -1.0f;  V[0].y = -1.0f;  V[0].z = 0.0f;
     V[1].x =  1.0f;  V[1].y = -1.0f;  V[1].z = 0.0f;
     V[2].x =  1.0f;  V[2].y = -1.0f;  V[2].z = 1.0f;
     V[3].x = -1.0f;  V[3].y = -1.0f;  V[3].z = 1.0f;
     V[4].x = -1.0f;  V[4].y =  1.0f;  V[4].z = 0.0f;
     V[5].x =  1.0f;  V[5].y =  1.0f;  V[5].z = 0.0f;
     V[6].x =  1.0f;  V[6].y =  1.0f;  V[6].z = 1.0f;
     V[7].x = -1.0f;  V[7].y =  1.0f;  V[7].z = 1.0f;


     //인버스 매트릭스로 월드영역으로 변환
     zMatrixMultiply( &MatVP, _pmatV, _pmatP );
     zMatrixInverse( &MatInv, NULL, &MatVP );

 

for( int i = 0; i < 8; i++ )
      zVec3TransformCoord( &V[i], &V[i], &MatInv );

 

     //원단면의 중심을 구한다
     Vector3 vC;
     vC = (V[2]+ V[3] + V[6] + V[7]);
     vC /= 4;

 

     //거리를 구한다
     float fDist = VDistance( vC, _vPos );
     return fDist;
}

 

위의 코드들을 사용하면,

 

근거리, 중거리, 원거리 순으로

라이트의 위치와, 타겟의 위치를 멀리잡으면서,

라이트뷰를 생성시킨후,

라이트뷰에 그림자가 표현되어야할 오브젝트들을 draw 한후,

 

세이더 코드에서 그림자를 계산할때,

각각의 프러스텀의 원거리값을 가져와서,

픽셀과 카메라와의 거리를 구한후

 

픽셀과 카메라와의 거리를, 각각의 프러스텀 거리값에 비교해서,

해당하는 프러스텀으로 만들어진 그림자 텍스쳐에서 뎁스값을 가져오는 방식으로, 계산이 가능해진다.

 

내 나름대로 구현한 방식인데,

보통 알려진 cascade shadow map 구현방식과는 차이가 있을수도 있다.

 

그런데 사실, 나공간에서는

위 방식대로 cascade shadow map 을 구현하지는 않았다.

여러 가지 방식으로 테스트를 해보는 중에,

적절하게 내가 표현하고자 하는 방식에 맞추어 변형을 시켰다.

 

 

 

 

 

728x90

'프로그래밍' 카테고리의 다른 글

obb 충돌 구현 1  (2) 2016.02.18
vsm with cascade shadow map 2  (0) 2016.01.26
vsm 지형 그림자  (0) 2016.01.14
vsm 그림자  (1) 2015.10.13
dof 구현 1  (3) 2015.10.05
posted by BK dddDang
: