반응형


모션 블러(Motion Blur)  3D Programming / Programming 

2012/05/14 00:39

복사http://blog.naver.com/sorkelf/40158984437







즉 위 설명은 아래와 같다.

속도벡터 = 현재위치 이전위치

최종 위치 = dot법선,  속도벡터  ) > 0 ? 현재위치 이전위치

이걸 버텍스 셰이더에서 그대로 구현하면..

  //현재의 버텍스 좌표

   float4 NewPos = mul( Pos, m_WVPNew );

   //과거의 버텍스 좌표
   float4 OldPos = mul( Pos, m_WVPOld );

   //버텍스의 속도벡터
   float3 Dir = NewPos.xyz - OldPos.xyz;

   // 버텍스의 이동벡터와 법선을 내적
   float a = dot( normalize( Dir ), normalize( N ) );

   //최종 위치 계산
   if( a < 0.0f )
      Out.Pos = OldPos;
   else
      Out.Pos = NewPos;


이동궤적 볼륨이 반투명으로 렌더링 되므로 깊이 버퍼를 사용하면 볼륨의 다른 부분이 깊이테스트에서 실패하므로 렌더링되지 않는다

그리고 얼마나 이동했는지 계산한다
다음 텍스처 샘플링 위치를 옮기기 위해 투영공간에서의 속도벡터를 구하고 이를 텍스처 좌표계에 맞도록
스케일링 한 것을 출력한다 (투영공간의 범위가 ~1-1 이므로 스케일링에 0.5배가 필요하며 y좌표가 반대이므로 -1을 곱해줌)


현재위치 mul(현재위치,m_WVP);

이전위치 mul(이전위치, m_prevWVP);


속도 = 현재위치 이전위치 / w * 0.5f;

속도.y *= -1.0f


이걸 버텍스 셰이더에서 그대로 구현하면..

  //-1.0f 부터 1.0f 의 범위를 텍스처 좌표계의 0.0f ~ 1.0f의 텍셀 위치를 참조하기 위해 거리를 절반으로 한다

  float2  velocity =  NewPos.xy / NewPos.w - OldPos.xy / OldPos.w;

  Out.Dir.xy =  velocity  * 0.5f;

   //최종적으로 텍셀의 오프셋값이 되기 위해 y방향을 반대방향으로 한다
   Out.Dir.y *= -1.0f;

   //씬의 Z값을 계산하기 위한 파라미터
   Out.Dir.z = Out.Pos.z;
   Out.Dir.w = Out.Pos.w;

 

   return Out;


여기까지가 버텍스 셰이더가 하는 일이다




이동궤적 지오메트리와  깊이 정보

픽셀 셰이더에서는 이동궤적 볼륨에서의 각각 화면좌표위치(In.Tex/In.Tex.w)로부터 속도방향(In.Velocity)로 조금씩 옮기고
오브젝트만을 렌더링한 텍스처를 샘플링한다.
마지막으로 합계한 결과를 샘플 수로 나누어 평균 색을 구한다.

 float4 PS_Final( VS_Final_OUTPUT In ) : COLOR0

{

   //수치를 크게 하면 크게 할수록 부드러움
   int  NumBlurSample = 10;

   //속도 맵으로부터 속도벡터와 Z값을 얻어옴
   float4 Velocity = tex2D( tex1, In.Tex );

   Velocity.xy /= (float)Blur;

   int cnt = 1;
   float4 BColor;

   // 씬의 렌더링 이미지를 얻어옴, a 성분에 Z 값을 저장된다
   float4 Out = tex2D( tex0, In.Tex );

   for( int i=cnt; i NumBlurSample  ; i++ )
   {
      //속도 벡터의 방향 텍셀 위치를 참조하여, 씬의 렌더링 이미지의 색정보를 얻어온다
      BColor = tex2D( tex0, In.Tex + Velocity.xy * (float)i );

      //속도 맵의 Z 값과 속도 벡터 방향에 있는 텍셀 위치를 샘플링 한 씬의 렌더링 이미지의 Z값을 비교한다
      if( Velocity.a < BColor.a + 0.04f )
      {
         cnt++;
         Out += BColor;
      }
   }

   Out /= (float)cnt;

   return Out;
}





샘플 수를 늘리면 좀 더 부드러운 느낌을 낼 수 있지만 렌더링 속도가 느려지므로 샘플 수는 적당히 타협하는 것이 좋다.


이 때

  //속도 맵의 Z 값과 속도 벡터 방향에 있는 텍셀 위치를 샘플링 한 씬의 렌더링 이미지의 Z값을 비교한다
      if( Velocity.a < BColor.a + 0.04f )
      {
         cnt++;
         Out += BColor;
      }

이 부분에서 Z값을 비교해 블러처리를 할 것인가 말것인가를 하는데 
이는 모델 경계상 에서의 생기는 아티팩트를 없애기 위한 것으로

아래 그림 처럼 뒤의 물체가 모션 블러 될때 앞의 물체에 모션블러 결과가 묻어 나는 것을 방지하기 위한 처리로
Z값을 참조하여 앞의 물체인지 뒤의 물체인지 판단후 앞의 물체이면 샘플링 할때 제외 하는 것이다.




일반적인 샘플링 시..

Z값을 고려하여 처리 한 결과

그 외 2.5D 모션 블러의 단점으로 

이동궤적 볼륨이 파괴(같은 버텍스 좌표에서 법선방향이 다른 모델에서 발생)
같은 변을 공유하며 법선방향이 다른 변에 대해서 폴리곤을 미리 생성하여
폴리곤을 늘릴때(이동궤적 볼륨을 만들때) 추가로 렌더링 하는 방식으로 해결 하며




지오메트리 비용 증가(이동궤적볼륨 있음 + 없음 으로 인한 추가모델을 2번 렌더링)
씬은 정적이고 멀리 있는 오브젝트는 크게 영향을 받지 않으며 카메라에 의한 변화만 의존한다고 가정하고
Z버퍼와 스크린 좌표만을 가지고 Velocity를 계산하는 방식으로 해결한다 (알고리즘은 아래와 같음)

  1. 스크린 좌표와 Z버퍼의 값으로부터 픽셀의 월드 좌표를 역산
  2. 월드 좌표를 1 프레임전의 뷰 프로젝션 행렬로 변환하여 1프레임 전의 스크린 좌표를 계산
  3. 현재 스크린 좌표와 1프레임 전의 스크린 좌표 로부터 Velocity를 계산



DX10이상일 경우에는 지오메트리 셰이더에서 Velocity를 참조하여 폴리곤을 잡아 늘리거나 폴리곤을 생성하는 방식을 사용한다
더 자세한건 DX 10 Sample Browser에 있는 Motion Blur 10내용을 참고하길 바란다.


DX10에서의 모션블러시 생성되는 원리



Reference : 

DirectX9 쉐이더 프로그래밍(타카시 이마기레)
CEDEC 2006 차세대기에 대응하는 게임 엔진 설계 CapCom

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

CommitChanges  (0) 2013.01.27
Effect::CommitChanges()  (0) 2013.01.25
인스턴싱 (Instancing)  (1) 2013.01.25
D3DXCreateTextureFromFile 함수  (0) 2013.01.22
다중스트림 셰이더  (0) 2013.01.21

+ Recent posts