반응형


http://blog.naver.com/sorkelf/40151293786


Direct3D 9 에 래스터라이즈 규칙


DirectX는 삼각형 폴리곤을 베이스로써 렌더링이 수행된다.

당연하겠지만 잘 생각해보면 다음과같은 변환이 필요하다는것을 알게 된다


삼각형 폴리곤의 각 버텍스는 부동소수점(float)로 표현된다. 소수점은 이론상으로는 연속된 값이다.

이 버텍스가 여러가지로 수치변환되어 최종적으로는 스크린 좌표로 변환된다.

 

이 스크린 좌표는 [ 정수 ]로, 스크린상의 점은 엄밀히 작은 정방형이다.

정수는 아는대로 불연속한 것이다.

연속이 어느새 불연속이 된것은 그다지 신경쓰지 않지만 실은 매우 중요한 것이다


연속한 폴리곤을 불연속적인 픽셀로 바꾸려면 몇가지 룰이 필요하다.

그 룰을 [ 레스터라이제이션 룰 (Rasterization Rule) ]이라고 한다. 

예를 들면 아래 폴리곤에 있는 3개의 버텍스의 스크린 위치가 결정됐다고 했을대 그 주위와 내부는 어떻게 칠해질까를 생각해본다



   변을 포함하고 있는 어떤 파란 색으로 칠해질까? 만일 전부 칠해지나? 면적이 넓으면 칠해지나?

이것들이 제대로 결정되어있지 않으면 외관이 완전히 변해버린다.


이것은 특히 스크린 픽셀을 의식한 렌더링( 2D의 HUD나 포스트 이펙트 렌더링 같은 것)

에 커다란 영향을 주게 된다


여기에서는 이렇게 평범할수도 있지만 중요한 래스터라이제이션 룰에 대해 설명하고자 한다. 

또한 언급이 없는 한 폴리곤은 스크린의 범위로 수치가 변환되고 있다고 한다. ( 단 소수점임)

또한 사각형들은 화면의 도트 그 자체이다




① 스크린 도트와 버텍스의 위치 관계


   폴리곤이 여러가지 변환을 거쳐 스크린의 범위와 같은 값이 됐다고 하자. 단 이 값은 부동소수점 그대로이다. 이때의 폴리곤의 소수점 값과 스크린의 도트는 다음과 같은 위치 관계가 된다


 

오렌지색 점이 폴리곤이 변환된 소수점 값이며, 빨간 숫자가 스크린좌표이다. (0이 기점인 것에 주의)

소수점의 정수값(3.0이라던지)이 도트 중앙에 있는것이 포인트이다.


 DirectX에서는 [ 오렌지색 점이 폴리곤내에 포함되어있다면 기본적으로 렌더링한다 ] 라는

룰이 적용되어 있다


[ 기본적 ]이란것은, 단지 이 룰만 적용하는 것은 문제가 있다는 것이다.

예를들면, 4X4의 작은 HUD를 표시하려고 할때의 이미지는 아래와 같다

이것을 위에있던 그림과 맞춰보자

잘 보면 가로 세로 5픽셀에 걸쳐져있다. 4X4로 할려고했더니 5X5?? 


또 하나 별도의 문제. DirectX의 폴리곤은 삼각 폴리곤이다. 

위의 사각 폴리곤을 삼각형으로 분할하면 어떻게 될까

  왼쪽 하단 폴리곤과 Right-Top 폴리곤의 경계선은 오렌지색의 점을 양쪽 모두 포함하고 있다.

라는 것은 이 곳은 2번 칠해진다 라는 것이 된다. 


포함하고 있는 부분을 단순히 칠한다라는 것만으로는 여러가지 문제가 생기게 되버린다는 것이다

여기서 DirectX나 각종 GUI계에서는 [ Top - Left Filling Convention ] 이라는 룰을 채택한다



② Top-Left Filling Convention


 ①에 있는 문제를 해결하기 위해 DirectX에서는 Top-Left Filling Convention 이라는 룰을 적용하고 있다. 이것은、「Top-Left 있는 도트는 채택, Right-Bottom에 있는 도트는 채택하지 않음」이라는 심플한 룰이다. 여기서 말하는 Left-Top과 Right-Bottom이란 무엇인가?


    우선 [ Left ] 이란 삼각 폴리곤의 변이 폴리곤의 중앙으로부터 봤을때 왼쪽에 있는 측면을 말한다.

[ Right ]는 그 반대이고, [ Top ]은 수평이며 중앙보다 위에있는 부분을 가리킨다. [ Bottom ]은 Top과 반대이다

 

 

   칠하려고했던 도트가 변에 대응(相当)하고 있는 경우, 그것이 Top-Left이면 채택, Right-Bottom이면 채택 하지 않는다. 이 룰을 위에서 봤던 사각 폴리곤에 적용하면 아래와 같이 된다

 

   파란색 셀은 왼쪽 하단의 폴리곤에 의해 칠해지는 곳이다. 이 폴리곤에는 왼쪽, 오른쪽, 하단이 있지만 그 가운데 오른쪽변과 아래쪽 변에 속해있는 셀은 칠하지 않는다.

따라서 대각선의 부분과 가장 아래에있는 부분은 색칠 되지 않는다.

 

오른쪽상단의 0,0 도트는 왼쪽 변과 오른쪽 변의 양쪽을 공유하고 있다.

이 경우 채택하지 않는다.


    한편 빨간 셀은 오른쪽 상단의 폴리곤에 의해 칠해지는 셀이다. 여기에는 Top, Left, Right 변이 있다.

오른쪽 변은 채택되지않기때문에 오른쪽 끝이 (4,4)도트가 칠해지지 않았고,  

왼쪽 변( 대각선을 말함) 은 칠해진다.

 

이것에 의해 Right-Bottom 폴리곤과의 경계선이 여러번 칠해지는 문제도 해결된다. 

사각형의 크기도 생각한대로 4X4이다

  

 기본적으로는 이 룰에 따라 칠해지나, 예외도 있다



③ Top-Left Filling Convention가 적용되지 않는 경우


 그런데 이 룰이 적용되지 않는 경우가 있다. 예를들면 아래와같은 경우이다:

 

방금전과 같은 크기의 사각 폴리곤이 조금 왼쪽 상단으로 이동했다.

이 경우 TLFC 룰(Top-Left Filling Convention)을 적용하면, 오른쪽이 불필요하게 비어있다.

DirectX는 이럴 경우 TLFC룰을 적용하지 않는다.

이것을 위에 그림에서 대각선의 크로스한 부분에서 판별한다


 이곳이 픽셀의 경계선에 들어있지 않은 경우등, 특정 조건을 만족할 경우, TLFC룰은 사용되지 않는다

이렇게 각 규칙에 따라 잘 움직이고 있으며 외관상으로 모순없는 렌더링이 가능한 것이다



④ 또 다른 문제「픽셀에서 벗어나는 문제」


 2D의 HUD등을 렌더링할때에는 가능하면 Dot by Dot 형태로 렌더링 하고 싶을 것이다.

(Dot by Dot:화면의 1도트에 텍스처 1픽셀이 렌더링 된 상태)

하지만 DirectX에서는 보이지 않는 룰에 의해 의도되지 않게 되는 경우가 있다


    매우 간단한 예로 재현해보자.

2X2의 텍스처가 있다고 했을대 이것과 같은 크기의 사각 폴리곤도 있다고 하자.

이것을 아래와 같이 스크린에 렌더링 한다고 하자

 

이때, 실제 화상은 어떻게 될까? 아마 이렇게 될것이다


 

뭔가 칙칙해졌다. 이것은 혼색(混色)이 되버렸기 때문이다. 왜 이렇게 된것일까? 

이것은 텍스처로부터 샘플링 하는 UV가 관계하고있다.


   래스터라이즈가 수행되면, 스크린의 유효 도트에 대해서 UV가 계산된다. 구체적으로는 각 도트의 중심점(오렌지색의 점)에 대응한 값이 보간되어 계산된다. UV를 적어보면 아래와 같이 된다

 


 

UV에 있는 색은 위의 그림과 같다. 각 UV 샘플링 점이 변 및 교점에 있는 것에 주목하도록.

 

이 경우 샘플러의 설정에 의한 것도 있지만, 주변의 색 정보를 활용해서 중간색이 나오게 된다.

그렇기 때문에 결과 화면같이 혼색된 색이 나와버리게 된다


  3D 모델을 렌더링 할때에는 애초에 Dot by Dot 가 되는것은 보통 없기 때문에, 이러한 것에 신경쓸 필요는 거의 없지만, 예를들어 포스트 이펙트를 셰이더에서 만들때 같은 경우에는 이 영향에 직격탄을 맞을 것이다.


  혼색되면 안되는 건 당연하다. 그럼 어떻게 막을까? 위의 그림에 답이 있지만 원래의 폴리곤의 좌표를 Top-Left로 0.5 이동시킨다. 그러면 원래의 색을 칠하고 싶은 위치와 폴리곤이 입혀지는 위치가 외관상 맞아 떨어진다



이 UV에서 샘플링 하면, 정확히 텍스처의 색이 반영된다.

원래의 폴리곤 좌표를 ( -0.5, -0.5) 오프셋 처리 하지 않으면 이론상 Dot by Dot가 되지 않는다.

또한, 이것은 원래 폴리곤 좌표가 정수가 아니면 성립하지 않기 때문에 주의 하도록..



⑤ 어디서-0.5를 이동 시킬 것인가?

 

   이론은 알았지만 어디서 -0.5를 이동시키면 될 것인가? 사각 폴리곤을 좌표변환이 끝난 버텍스에서 작성하고있는 사람이라면 직접 버텍스 좌표를 오프셋 처리를 하면 된다.

그렇지 않고 사각 폴리곤을 좌표변환이 끝난 버텍스를 사용하지 않고 3D 공간상의 폴리곤으로써 취급할 경우, 위치를 이동시킬 기회는 두번이 있는데....

   

    첫번째는 월드 행렬 변환이다. 이곳에 스크린에서 봤을때 (-0.5, -0.5)이동시키는 오프셋을 추가한다. 단 일반적으로 이건 꽤 어렵다.


   또 다른 방법은 셰이더 내에서 처리하는 것이다. 사각형 폴리곤 렌더링용 셰이더가 있다는 전제이지만, WVP행렬을 곱한 후의 버텍스에 대해서 직접 계산을 수행한다



 VS_OUT vs_main( VS_IN In )

{

    VS_OUT Out = (VS_OUT)0;

    Out.pos = mul( In.pos, WVPMatrix );  // 투영공간으로 이동

    // 스크린 좌표에 대해서(-0.5, -0.5)의 오프셋
    Out.pos /= Out.pos.w;

    // 투영공간의 좌표를 한번 스크린 좌표로 해서、
    // 0.5씩 오프셋 처리를 하고 원래대로 돌아온다
    // 아래와 같이 작성해도 컴파일러가 최적화를 시켜준다
    Out.pos.x = (Out.pos.x * screenW - 0.5f) / screenW;
    Out.pos.y = (Out.pos.y * screenH + 0.5f) / screenH;

    return Out;
}


WVPMatrix(월드 X 뷰 X 프로젝션)를 로컬 좌표로 곱한 후에 각 성분을 w성분으로 나누면 

버텍스 좌표는 (-1, -1, 0) ~ (1,1,1)이라는 작은 영역으로 제한된다. 

이것이 늘어나 스크린좌표가 되는 것이다. 


지금은 스크린 좌표 베이스에서 0.5 오프셋을 넣는것이기에 한번 스크린 의 폭과 높이를 좌표에 곱해 스크린 좌표로 변환해서 0.5 오프셋을 넣고 다시 스크린의 폭과 높이로 나누어 작은 영역으로 되돌린다. 


y 성분은 스크린의 축과 투영공간의 축의 방향이 반대이기 때문에 덧셈을 하는것에 주의 한다



  Dot By Dot 표시는 2D 시대에는 당연한(애초에 그것밖에 없음)것 이었지만 3D가 베이스가 되는 DirectX에 있어서는 의외로 어려운 것이다. 하지만 래스터라이제이션 룰과 버텍스 보간의 내부를 역수로 취하면 가능 할 것이다


MSDN에서 설명하는 래스터라이즈 규칙

반응형

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

밉맵 디테일 높이기  (0) 2013.06.10
Early Z  (0) 2013.06.08
x파일에 대한 pdf  (0) 2013.03.11
NormalMapGenerator  (0) 2013.02.23
x파일 뷰어  (0) 2013.02.17

+ Recent posts