DirectX 11

DirectX 11 - Rasterization

tita 2024. 5. 31. 14:54

정점을 처리하는 단계를 지난 정점은 레스터라이제시션 단계로 넘어갑니다.

우선 정점들은 삼각형으로 묶여있는데 이 시점부터는 하나의 독자적 도형으로 처리가 됩니다. 

우선 화면에 그려질 2차원 삼각형의 세 정점이 결정되면 다음과 같은 일이 일어납니다.

  1. 이 삼각형이 포함하는 모든 픽셀마다 Pixel Shader(fragment shader)가 실행된다.
  2. 삼각형의 세 정점에 할당 되었던 여러 데이터(pos, uv, normal, color)가 보간되어 삼각형 내부에 각 픽셀셰이더로 넘어옵니다.

DirectX에서 이러한 일련의 과정을 레스터라이제이션이라고 부르고 고정 파이프라인 단계로 프로그래머가 이러한 로직들을 임의 바꿀수 없는 파이프라인 단계이다. 자체 알고리즘으로 알아서 동작을 합니다.

 

 

[레스터라이제이션 알고리즘]

자체 알고리즘(레스터라이제이션 알고리즘)에 대해 알아보겠습니다.

// rasterization algorithm
for(each triangle in scene) {
    // Step 1 : 삼각형의 세 꼭지점을 투사
    Vec2f v0 = perspectiveProject(triangle[i].v0);
    Vec2f v0 = perspectiveProject(triangle[i].v1);
    Vec2f v0 = perspectiveProject(triangle[i].v2);

    for(each pixel in image) {  // canvas의 모든 pixel에 대해
        // Step 2 : 이 pixel(x,y)이 삼각형안에 있는지 확인
        if(pixelContainedIn2DTriangle(v0, v1, v2, x, y)) {
            image(x,y = triangle[i].color;
        }  
    }
}

 

삼각형이 포함하는 모든 픽셀마다 Pixel Shader가 실행된다고 했는데, 모든 픽셀에 대해 다 체크하면 시간이 너무 오래 걸립니다.

이 경우에 Bounding Box를 이용한 최적화가 일어납니다.

 

Bounding Box 는 세 꼭지점의 투사 점에 대한 최소값과 최대값을 구해서 박스의 범위를 설정합니다.

 

특정 픽셀이 삼각형의 내부에 있는지 외부에 있는지 확인하는 방법은 pixelContainedIn2DTriangle() 에서 일어납니다.

 

Edge() 함수를 사용해서 알아낼 수 있습니다.

Edge() 함수는 삼각형의 두 점 사이의 선분을 기준으로 왼쪽이면 -, 오른쪽이면 +를 반환하는 함수입니다.

 

만약 삼각형을 이루는 3개의 선분에 대해 Edge() 함수가 모두 + 를 반환하면 해당 포인트는 삼각형의 안에 있습니다.

 

Edge() 함수는 2차원 포인트 P를 v0(시작점), v1(끝점)으로 이루어진 선분을 테스트하는 함수입니다.

(v1-v0) 벡터와 (p-v0) 벡터의 외적(cross product)의 부호를 확인하는 함수입니다.

E(P) > 0 => 선의 오른쪽에 점이 존재
E(P) = 0 => 정확히 선 위에 점이 존재
E(P) < 0 => 선의 왼쪽에 점이 존재

 

이제 삼각형을 이루는 3개의 선분(edge)를 구하는 방법을 알아야 합니다.

단순하게 점과 점을 빼면 될 거 같지만 순서가 중요합니다.

 

위와 같이 CW의 경우에는 삼각형 내부가 양수, CCW의 경우에는 삼각형 내부가 음수가 되기 떄문입니다.

 

 

삼각형 내부의 점의 좌표와 속성을 구할때는 Barycentric Coordinates 를 사용하면 됩니다.

 

 

 

[대표적인 레스터라이제이션의 역할]

  1. 클리핑
  2. 원근 나눗셈(perpective division)
  3. 뒷면 제거(backface culling)
  4. 스캔 변환(ndc scan transform)
  5. 뷰포트 변환

 

<클리핑>

클리핑은 투영변환 이후의 클립공간 볼륨 바깥에 놓인 폴리곤들을 잘라내는 작업을 말합니다. 

 

 

<원근 나눗셈>

현재 단계에서 투영변환을 통해 원근법이 적용된 3차원 물체들을 직육면체 클리핑 공간에서 정의되어 있습니다.

3차원에서 2차원으로 차원을 줄이면 됩니다. 바로 Z좌표로 모든 성분을 나눠버리면 됩니다.

투영변환을 마친 정점데이터는 (x, y, z, w = z 값 저장)에서 원근 나눗셈이 적용 된 이후에는 (x, y, z, w) -> (x, y, z) 의 좌표계로 변환되는데 이를 NDC(normailize device coordinate) 공간이라고 부릅니다.

여기서 정규화라는 이름이 붙는 이유는 이 좌표의 xy 범위는 [-1 ~ 1] z의 범위는 [0~1]이기 때문입니다.

 

 

<뒷면 제거>

카메라가 바라보고 있는 방향에 물체에 가려진 면적은 굳이 연산을 할 필요가 없습니. 외적(Cross product) 삼각형의 바라보고있는 면의 방향을 구하여 뒷면일 경우에 연산을 하지 않습니다.

 

 

<뷰포트 변환>

컴퓨터 화면상의 윈도우 스크린 공간을 갖는데 이 스크린 공간 내에 2차원 이미지가 그려질 뷰포트가 정의되는데 NDC공간의 물체들을 스크린 공간으로 이전시키는변환을 뷰포트 변환이라고 합니다.

 

 

<스캔 변환>

이전의 변환들은 자세한 사항을 몰라도 프로그래밍하는데 문제가 없었지만 이 스캔 변환은 렌더링 프로그램에서 직접적인 영향을 미치기 떄문에 꽤 중요합니다. 삼각형 하나가 내부에 차지하는 모든픽셀(fragment)들을 생성하는 작업이고, 이때 정점데이터에 들어온 데이터들은 보간(선형 보간)되어서 픽셀셰이더로 넘어갑니다.