센로그

4. Input Assembler & Vertex Processing(1) 본문

게임/그래픽 프로그래밍

4. Input Assembler & Vertex Processing(1)

seeyoun 2023. 5. 12. 11:32

◆ Direct3D 12 graphics Pipeline

GPU 처러 과정에는 특별한 파이프라인 구조가 존재함. 한 스테이지의 output이 다음 스테이지의 input이 됨~

앞으로 이 그래픽스 파이프라인을 하나하나 살펴볼 것임

 

< 의미 >


~ Shader : 프로그래밍 가능함
나머지는 하드웨어적으로 고정된 함수 사용
진한 초록색 : 무조건 있어야 함
연한 초록색 : 선택적으로 빼도 됨

 


◆ Input Assembler (IA)

GPU가 CPU로부터 Vertex 정보(VBV, IBV)를 받아서 읽고, 규칙에 따라 처리해서 primitive로 만들어줌.

이 부분은 우리가 코딩하는 부분이 아니고 하드웨어적 요소로 이미 만들어져 있는 부분임

 

< 용어 >

  • VBV(Vertex Buffer View) : CPU에서 만들어진 vertex 정보가 쭉 들어가있음에 대한 핸들러(포인터)
  • IBV(Index Buffer View) : CPU에서 만들어진 Index 정보가 쭉 들어가있음에 대한 핸들러(포인터)
  • primitive: 기본이 되는 모양 단위. 삼각형, 사각형, 포인트 등

 

//ID3D11DeviceContext.IASetPrimitiveTopology() 를 사용해 사용자가 primitive type을 지정할 수 있음
void IASetPrimitiveTopology(
  [in] D3D11_PRIMITIVE_TOPOLOGY Topology
);

 

// vertex 데이터 지정 (VBV)
struct CUSTOMVERTEX { 
        FLOAT x, y, z;      // The position
        FLOAT nx, ny, nz;   // The normal
        DWORD color;        // RGBA color
        FLOAT tu, tv;       // The texture coordinates. 
};
 

◆ Vertex Shader

Vertex Shader은 IA로 부터 받은 Vertex 정보들을 기반으로,
각각의 Vertex별로 연산을 처리해서, Vertex들의 final position(최종 포지션)을 결정하는 데 사용함.

이때,옆에있는 녀석의 정보는 참조할 수 없다는 점 기억.

왜냐면 한번의 clock cycle 내에서 병렬처리 되기 때문에,

오로지 자기 자신의 정보만을 갖고 처리해서 다음 스테이지로 넘어가야 함.

 


◇ Vertex Shader 특징

  • Shader라는 이름이 붙은 순간, Programmable한 스테이지이다.
    우리가 직접 코딩해서 어떻게 동작할지 결정할 수 있다는 뜻.
  • DirectX를 사용하는 Shader를 HLSL이라 하고, OpenGL을 사용하는 Shader를 GLSL이라고 함.
  • GPU는 코어가 많아서, 병렬 처리를 통해 엄청나게 빠르게 floating point 처리가 가능함.
    (CPU는 int 연산이 많은 데 반해, GPU는 벡터 연산이 많으므로 부동 소수점 기반의 float 처리에 특화)
  • 내부에서 어떤 처리를 하든 자유롭지만, Input 및 Output에 대한 규약은 엄격하게 지켜줘야 함
  • VS는 필수적인 Shader임!! 뺄 수 없음.

 


◆ Vertex Shader 처리 과정

그럼 Vertex Shader가 결정한다는 final position이 뭐냐?

 

final position까지의 변환 과정을 살펴보자.

Object space → World space →Camera space → Clip space


 

■ Object space

object의 좌표계.

object의 회전시 축이 함께 회전함 

 

■ World space

3D World의 좌표계.

3D World는 다양한 object들, 캐릭터들, 카메라들을 포함함

 

■ Camera space

카메라 중심에서의 좌표계.

결국 화면에 보이는 건 카메라 위치로부터 보는 것이기 때문!

3D World 좌표를 카메라 위치와 관련해서 재계산함.

 

■ Clip space

3D 화면을 2D 화면에 맞게 투영한 좌표계.
(실제 클리핑을 수행하는 것은 아님)

시야 범위 내에 들어오는 좌표를 -1에서 1 사이로 표준화 함.

 

※ Space 사이의 변환 과정(world/view/projection transform)은 모두 matrix 형태로 표현 가능하다.
따라서 이 셋을 합쳐서 M_wvp로 만들 수 있다. (Matrix - world view projection)

 


◆ Vertex Shader 처리 과정 예시

다음 과정을 per-vertex로 처리한다.

VS_OUTPUT main (VS_INPUT input)
{
    VS_OUTPUT Output;
    float4 pos = float4(input.vPos, 1.0f);	//input.vPos를 사용해 float4형식의 pos 정의

    pos = mul(pos, mWorld);  		// world transform (object -> world)
    pos = mul(pos, mView);		// view tranform (world -> camera)
    pos = mul(pos, mProjection);	// projection transform (camera -> clip)
    
    Output.Position = pos;	// 처리를 마친 최종 vertex들의 position
    Output.Color = float4(input.vColor, 1.00f);  // 최종 칼라 넣어줌
    
    return Output;	
}

float4 형식.. homogeneous coordinate

 


◆ Vertex Shader - World Transform 

각자의 object space에서 정의된 object들을 동일한 World space 가져옴.

처음에 object를 생성할 때 사용된 object space들은 다른 object space와 관련이 없음.

이들을 한 공간에 모아주는 게 world transform이다!

 

 

sclaing, rotation, translation 변환을 통해서 object들을 world space로 가지고 옴.

아핀 변환으로 구성된 World Matrix는 [L|t]로 표현 가능~

 


◇ Vertex Shader - World Transform - normal

triangle이 [L|t]에 의해 변환되었다면, triangle normal은 L-T로 변환하면 됨!

CPU가 GPU로 vertex 정보를 넘길 때 vertex들의 x,y,z 포지션과 함께 vertex normal xn, yn, zn도 같이 넘김.

(GPU는 병렬 처리를 해서 옆 vertex들을 참조할 수 없기 때문에, CPU에서 미리 vertex normal까지 계산해서 넘겨줌)

  

 

triangle에 대한 변환을 [L|t] 라고 하자. 이때 triangle normal의 변환은 어떻게 처리되어야 하는지 알아보자.

  • normal은 [L|t] 에서 L에만 영향을 받음.
  • 그런데 만약 Lnon-uniform scaling(비율이 다른 scaling)을 포함한다면, 이것은 normal에는 적용될 수 없음. 아래 그림을 보자.

n 벡터에 L변환을 적용한 벡터를 Ln, 이를 정규화한 벡터를 \(\tilde{L}\)n라 하자.

L이 non-uniform scaling인 경우, L에 의해 scaling된 normal은, 더이상 (L에 의해 scaling된) triangle직교하지 않음.

=> 따라서 우리는 inverse transpose of L,L-T를 사용함.

 

L-T 와 L는 magnitude는 다를 수 있지만 direction은 같음.

따라서 L-T를 사용해 변환하면 L이 non-uniform scaling을 포함하고 있든 아니든 간에 동일하게 연산됨!

결과적으로도 변환된 normal은 변환된 triangle과 직교함. 

그러고나서 최종적으로 다시 normalized 해주면 됨~

그러므로 우리는 앞으로 normal 계산시 L-T를 사용할 것이다~

[ 증명 ]

triangle의 각 vertex를 p,q,r이라 하고, triangle normal을 n이라 하자.
p-q를 잇는 벡터와 n벡터는 직교한다. 따라서 둘의 dot product 결과는 0이므로, 다음 식을 만족함

(p, q, n이 row vector라 했을 때 dot product 를 위해 n을 전치한 것.)




이제 p, q에 L변환을 한 pL = p`, qL = q`이라고 하자.
양 변에 L-1을 곱하면, p = p`L-1, q = q`L-1이라 할 수 있다.

이를 위 식에 대입하면, 다음과 같은 식이 나온다.

이 식을 다시 Transpose 해주면 다음 식을 만족함. (참고: (AB)T = (BT)(AT))

즉, nL-T 벡터와 (q`-p`) 벡터가 직교한다는 것을 알 수 있음.
풀어서 쓰면, L 변환된 (q`-p`)벡터와 L-T변환된 n 벡터는 직교한다~ 라는 말!

 


◆ Vertex Shader - View Transform

World space → Camera space로의 변환.

world space에서의 모든 객체들이 camera space 측면에서 새롭게 정의될 수 있다면, 렌더링 알고리즘을 개발하는 것이 훨씬 쉬워질 것~ 이라는 아이디어.

 

카메라 또한 object이기 때문에, world space에서 정의되었을 것임.

 

u, v, n은 DirectX 기준. OpenGL은 n이 반대방향

world space에서 카메라 포즈는 다음 요소들에 의해 설명됨

  • EYE : 카메라 포지션
  • AT : 카메라가 바라보고 있는 점
  • UP : 카메라의 윗 부분을 알려주는 벡터(포지션과 바라보는 방향이 같아도, 화면을 돌릴 수도 있으니까. 보통 y축이 UP)

 

EYE, AT, UP 이 주어지면, u, v, n 벡터를 다음과 같이 계산할 수 있다. (셋다 단위벡터)

  • n은 EYE에서 AT으로의 방향을 가진 벡터
  • u는 n과 UP 벡터의 외적 벡터
  • v는 n과 u벡터의 외적 벡터 (n과 u가 이루는 평행사변형의 넓이는 1이므로, v도 단위벡터)

 

이 벡터들을 자세히 보자.

어떤 두 벡터를 외적한 벡터는, 그 두 벡터와 각각 수직이라는 점을 기억하자.

u는 UP과 n의 외적으로 정의되어 있음. 

즉, u는 UP과도 수직이고 n과도 수직임.

같은 맥락에서, v는 n과도 수직이고 u와도 수직

...어!? u, v, n은 다 단위벡터고, 다 서로 수직이네? => u, v, n은 서로 orthonormal한 관계이다.

=> EYE를 원점으로 치면, 원점 하나와 orthonormal한 벡터 3개.. 새로운 하나의 좌표계를 정의할 수 있다!!

이를 camera space라고 함.

 

EYE, AT, UP을 가지고 camera space라는 새로운 좌표계를 정의한 것이다.

 

 

한 point는 각각의 space에서 개별적인 좌표를 가짐.

그림에서는 knight world space 좌표는 (0,2,10)이고, camera space 좌표는 (0,0,10)인 것~

 

우리는 결국 카메라 기준으로 볼 때를 렌더링 할 것이기 때문에, object들을 카메라 기준의 좌표로 정의한다면 렌더링 알고리즘이 훨씬 쉬워질 것이다. => world space에서 camera sapce로의 변환을 View Transform이라고 한다.

View Transform을 통해, world space의 {e1, e2, e3, O} camera space의 {u, v, n, EYE} 로 변환한다.

 

< 변환 방법 > 

{u, v, n, EYE}를 {e1, e2, e3, O}로 겹쳐줘야 함.(superimposing the camera space onto the world space)

(camera object의 object space에서 world space로 넘어온 과정을 (모든 object에 대해)반대로 해주는 느낌)

이를 위해 원점으로 translation하고, world space 기저 방향으로 rotation 해주면 됨.

 

 

1) T

우선, 카메라의 position인 EYE를 world space의 원점 position으로 겹쳐줌(translation. 그림에서는 row vector style이므로, 이전에 배웠던 column vector style에서의 Translation 행렬 전치한 것) 

이에따라, 오른쪽 그림에서 knight와 sphere의 원점도 -EYEx, -EYEy, -EYEz만큼 translation 된 것임

이제 오른쪽 그림에서 u, v, n을 e1, e2, e3에 일치하도록 회전만 시켜주면 됨!

 

2) R

그런 다음 기저 {u, v, n}을 {e1, e2, e3}으로 겹쳐줌. (기저변환(basic change) 해줌. 원래대로 돌려주면 됨(rotation. 얘도 그림에서는 row vector style이므로, 이전에 배웠던 column vector style에서의 Rotation 행렬 전치한 것)

우리는 e1, e2, e3를 회전시킨 u, v, n값을 알고 있을때, 이 과정에서 있었을 회전행렬 R을 구하는 방법을 알고있음. 

그냥 행벡터 형식으로 때려넣으면 됨. (column vector style이면 열벡터 형식으로 넣으면 됨. https://grace7040.tistory.com/68)

 

반대로 e1, e2, e3로 다시 돌려주고 싶으면, R의 inverse 구하면 된다고 했었음.(https://grace7040.tistory.com/68)

Rotation의 경우 R-1 = RT이므로, RT변환을 해주면 다시 {e1, e2, e3}로 변환시킬 수 있다!

 

이것이 바로 우리가 원하는 카메라 공간임. 그림처럼, 이 변환과정을 그대로 world space object들에게 적용시켜주면, 최종적으로 object들의 camera space에서의 좌표가 나올 것임

 

< 변환 행렬 M_view >

최종적으로 View Transform Matrix M_view는 다음과 같이 TR로 정의될 수 있다!

DirectX(row vector style) 기준

Translation → Rotation한 것!

'게임 > 그래픽 프로그래밍' 카테고리의 다른 글

6. Rasterization  (0) 2023.05.13
5. Input Assembler & Vertex Processing(2)  (0) 2023.05.12
3. Spaces and Transforms  (0) 2023.04.25
2. Vectors and Matrices  (0) 2023.03.31
1. Modeling  (0) 2023.03.14
Comments