프로그래밍 2015. 3. 10. 15:25
728x90

 

쉐이더 그림자 vsm pcf - 01

 

 

화면을 클릭하면, 크게 보실수 있습니다!

 

그림자의 농도는 조절 가능 합니다.

농도차의 확인을 쉽게 하기 위해서, 되도록 그림자영역을 검게 만들었습니다.

 

 

1. depth

 

 

 

2. depth + pcf

pcf 4단계 적용

 

 

 

3. depth + vsm

 

 

 

4. depth + pcf + vsm

pcf 3단계 적용

 

 

 

5. depth + pcf + vsm

pcf 10 단계 적용

 

 

 

 

구현 방법도 많고,

테스트 방법도 많고,

이리저리 테스트를

 

 

많이도 해 보았습니다!

 

vsm 에 대한 설명은 인터넷에서 충분히 찾아 보실 수 있습니다.

깔끔한 vsm 코드는 여기!

http://developer.download.nvidia.com/SDK/10/direct3d/Source/VarianceShadowMapping/Doc/VarianceShadowMapping.pdf

 

 

렌더타겟 그림자에

깊이값을 저장할때

depth * depth 를 G 에 저장해 둡니다.

R, G 값을 사용.

 

float4 PS_Shadow_1( VS_OUTPUT _In ) : COLOR
{
     float depth_color = _In.depth.z / _In.depth.w;

 

     //r, g, b, a

     return float4( depth_color, depth_color * depth_color, 0.f, 1.f ); 

 

//렌더타겟 텍스쳐 생성 부분

D3DDEVICE->CreateTexture( _iW, _iH, 1, D3DUSAGE_RENDERTARGET, D3DFMT_G32R32F, D3DPOOL_DEFAULT, &m_pRT_Shadow[0], NULL )

 

뎁스값을 비교하는 PS 함수부분

{

       float2 moments = tex2D( TexShadow, uv ).rg; //뎁스갑이다, 0~1 범위의 컬러값이 아니다
                                                                      //뎁스값비교로만 사용할 수 있다.

 

 //VSM

 //cur_depth 는 자기 뎁스 값입니다.
 float fragDepth = cur_depth;
 float fLit = 1.0f;

 float E_x2 = moments.y;
 float Ex_2 = moments.x * moments.x;
 float variance = (E_x2 - Ex_2);

 

 //최소값으로 보정해 두어야만

 //그림자 영역 안에,

 //깊이값의 미묘한 편차에 의한, 지저분한 면이 생기지 않습니다.

 //이 최소값은 투영행렬의 영향(거리값 등....)을 받습니다

 variance = max( variance, 0.00005f );

 

 float mD = (fragDepth - moments.x);
 float mD_2 = mD * mD;
 float p = (variance / (variance + mD_2));

 

 //쉐도우뎁스값이 자기값보다 앞에 있다면(작다면)

 //가리워진것으로 판정하여 그림자 처리를 해주어야 하는데,

 //원래는 이것

 //max( p, fragDepth <= moments.x );

 

 //값뒤집기

 //의외로 좋은 결과
 fLit = max( p, fragDepth > moments.x );
 fLit = (1.f - fLit) + 0.5f;
 if( fLit > 1.f )
     fLit = 1.f;

 

 //컬러에 적용

 //컬러값 * fLit 으로 사용하였습니다.

 //fLit 값이 작을 수록, 픽셀이 어두워 집니다. 

}

 

 

728x90
posted by BK dddDang
: