ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [22] - Viewport and clip space
    Graphics 2021. 7. 23. 21:51

    이제 삼각형 정도는 어렵게 출력할 수 있게 되었습니다. 다시 배경 지식을 떠올릴 차례입니다. 가장 최신의 GPU Rendering Pipeline은 D3D9과 조금 차이가 있을 수 있습니다. 설계된 목적도 서로 상이합니다.

    OpenGL Wiki에서 가져온 Rendering Pipeline은 다음과 같습니다. Rendering Pipeline Overview - OpenGL Wiki (khronos.org)

    다음은 Microsoft의 MSDN 홈페이지에서 갖고 온 Rendering pipeline입니다.Graphics Pipeline - Win32 apps | Microsoft Docs

    둘이 약간의 차이는 있으나 개념은 비슷합니다. Tessellator의 경우엔 Hull Shader + Tessellator + Domain Shader 를 통틀어 Tessellation이라고도 합니다. 그러면 OpenGL의 Vertex Specification은 IA Stage의 과정에 해당하는 것으로 추측할 수 있습니다. Rasterization 단계는 동일하지만 그 이후의 처리에서 약간의 차이를 보이고 있습니다. 이전에 Viewport에 대한 내용이 방대해서 따로 한다고 했습니다. 지금이 바로 그 때인가 봅니다. 왜냐하면 OpenGL ES에서 Viewport라는 개념이 Vertex Post-processing에서 등장하기 때문입니다. 

    OpenGL에서는 Vertex Shader를 거쳐서 Rasterizer Stage에 이르면 Primitive Clipping, Perspective Division 그리고 Viewport Transform이 행해집니다. 이들이 무엇인지 하나씩 살펴보면 추후에 Hardware 3D D3D를 공부하다가 마주쳐도 당황하지 않을 것입니다.

    Clipping

     저번에 했던 내용이긴 합니다.

    Clip space에서 설명하면 좋겠으나 눈으로 보기 편하게 Viewfrustum(Camera Space)에서 보기로 합니다. t1삼각형은 Frustum 밖에 존재하고 t2는 온전히 안에 존재, t3는 반만 온전히 들어와 있습니다. 이때, t1은 완전히 밖에 나가 처리를 할 필요가 없는데 이 과정은 Culling이라고 하며 t3와 같이 일부만 처리해야 할 경우를 Clipping이라고 합니다.

    그런데 어떻게 처리를 해야야할 지 의문입니다. 어떤 물체가 Render되어 있는 건 vertex를 이어서 나온 것인데 임의로 vertex를 잘라버리는 건 이상합니다. 여기서 하는 일은 새로운 vertex를 두 개 만들어서 t3 내에 새로운 삼각형을 만드는 일입니다.

    그런데 구태여 새로운 삼각형을 만드는 이유가 궁금합니다. Opengl Rendering Pipeline을 보시면 끝에 Fragment Shader라는 것이 존재합니다. 이 단계에서는 각 vertex로 둘러 싸인 공간을 작은 픽셀로 Sampling을 합니다. 따라서 Clipping을 하면서 기존의 t3에서 새로운 삼각형을 만들면 당장은 귀찮겠으나 이후 따라오는 단계에서 연산해야 할 양이 줄어든다는 장점이 있습니다. 그러면서 이 Clipping은 primitive에 따라서 수행되는 방식이 약간 다르지만 새로운 Vertex를 찍어서 새로운 Primitive를 만든다는 점은 똑같습니다.

    Perspective Division

    이전에 Projection Matrix를 구하는 과정을 공부했습니다. 그 결과 다음과 같은 변환 행렬을 얻을 수 있었습니다.

    f = far / n = near

    그래서 Camera space 상의 어떤 Object가 다음과 같이 변환 행렬을 거치면 Clip Space로 오게 될 것입니다.

    어떤 Vector [x, y, z, 1]이 변환되었습니다

    그런데 Vertex를 정의할 때 Cartesian Coordinates에서 했습니다. 보면 변환한 벡터의 끝이 -z로 되어 있는 것을 확인할 수 있습니다. 따라서 각 요소를 -z로 나누어 줍니다. 그러면 끝 성분이 1이 될 겁니다.

    여기서 염두에 두어야 할 것은 z는 Camera의 xy-plane으로부터 떨어진 거리를 나타낸다는 점입니다. -z로 나누는 행위가 멀리 있는 object를 작게 만들어주는 효과를 가집니다. 그리고 이 행위를 Perspective Division이라고 합니다. 예시를 한 번 보겠습니다. 다음과 같은 view frustum을 projection matrix로 clip space로 만들었다고 가정합니다.

    이런 view frustum을 변환하면 밑의 그림과 같습니다
    We can clearly see the difference between p1 and p'1

    다음과 같은 가정을 하면 더 명확하게 알 수 있습니다.

    Cubic View Volume은 NDC[Nomalised Device Coordinates]라고도 합니다.

    Viewport Transform

    이제 NDC 상의 Clip space로 모든 것을 가져왔습니다. 그런데 여기서 그치는 것이 아니고 실제 Window 화면에 보여질 window space 또는 Screen space로 가져와야 합니다. 그것을 Viewport라고 하고 NDC space에서 Viewport로 가져오는 것을 Viewport transform이라고 합니다. 그런데 게임을 하다보면 창모드를 쓸 수도 있고 기계에 따라 폭과 넓이가 다를 수 있습니다. 그림을 참고하며 진행합니다.

    Viewport에는 몇 가지  Parameter가 있고 이를 통해 삼차원 공간을 정의합니다.

    minX, minY, width, height, minZ, maxZ

    화면 상의 Viewport을 정의할 때, 무조건 원점(0, 0)을 기준으로 할 필요가 없고 그래서도 안됩니다. 따라서 위의 그림처럼 minX와 minY, Viewport의 폭과 높이, minZ와 maxZ를 통해 삼차원 공간(특히, 큐브와 비슷한 공간)을 정의하는 겁니다. 그렇다면 NDC 공간이 2x2x2 Cube공간이라고 했으니 이를 width와 height로 표현하려면 공간 자체에 약간의 변환이 필요할 것입니다.

    원점이 O(0, 0, 0)인 큐브를 변환해서 Screen space 상의 어떤 물체로 만드는 겁니다. 적당한 Scaling과 translation을 하면 NDC 공간 상의 space 공간 그 자체가 변화할 것입니다.

    그러면 확인을 해보면 됩니다. NDC 상의 큐브는 원점을 기준으로 2x2x2이기 때문에 어떤 한 Vertex의 벡터는 [-1, -1, -1]일 것입니다. 이를 계산을 위해 [-1, -1, -1, 1]로 변환하여 각 변환 행렬에 곱하면 Viewport의 가장 좌측 하단의 벡터를 얻을 수 있습니다.

    추가로 이 두 변환 행렬은 Affine Matrix이므로 합쳐서 표현할 수 있습니다.

    Primitive Assembly

    Vertex Shader에서 vertices의 위치 정보를 받았습니다. 그리고 각종 변환을 통해 마침내 screen까지 왔습니다. (OpenGL의 설명이 기준입니다. D3D가 아닌) 그러면 이 Primitive assembly 단계에서 해당 vertex들을 알맞게 조립하기 시작합니다. 즉, 개별의 vertex들을 이어서 면을 만들기 시작합니다. 그런데 D3D에서 이와 비슷한 일을 하는 단계를 봤습니다. 바로 IA Stage입니다. D3D는 여기서 각 vertices의 Buffer를 정의하고 이 vertex들이 어떻게 쓰일 것인지를 정의했습니다. Primitive Topology까지 등장했었는데 이는 Enumerated types로써 vertices가 어떻게 해석되고 파이프 라인에서 처리될 지를 결정한다고 했습니다. OpenGL에서는 primitive Assembly 단계에서 Face Culling이라는 것을 함께 수행하는데 한 번 살펴보겠습니다.

    C는 카메라로 향하는 vector입니다.

    어려운 개념은 아닙니다. 어떤 표면의 정면은 Norm이 향하는 방향입니다. 그런데 n1의 경우엔 카메라(눈)에서는 보이지 않는 부분입니다. 이 Primitive Assembly 다음에 Sampling을 한다고 했는데 보이지도 않는 면을 채우는데 연산능력을 할당할 이유가 없습니다. 

    'Graphics' 카테고리의 다른 글

    [24] - Constant Buffer  (0) 2021.07.30
    [23] - Pipeline experiments  (0) 2021.07.30
    [21] - My First Triangle - 2  (0) 2021.07.22
    [20] - My First Triangle - 1  (0) 2021.07.22
    [19] - ComPtr and Smart Pointer  (0) 2021.07.21
Designed by Tistory.