본문 바로가기
게임 공부/Computer graphics

4 - 프래그먼트 처리(Fragment processing)

by woohyeon 2020. 8. 10.
반응형

책을 보며 개인적으로 공부하는 내용이므로 틀린 부분이 있을 수 있습니다.

자료 및 내용 출처
<게임 프로그래밍을 위한 3차원 그래픽스> 

 

프래그먼트 처리

이전 단계인 래스터화 단계의 출력은 정점별 속성이 보간된 프래그먼트였다. 그리고 현재 단계인 프래그먼트 처리 단계는 프래그먼트 하나를 입력으로 받는다. 프래그먼트 처리는 프래그먼트 프로그램(셰이더)에 의해 수행되며, 다양한 처리를 통해 프래그먼트의 색상을 결정한다. 프래그먼트 처리 단계는 완전 프로그래밍 가능한 단계이기 때문에 우리가 직접 셰이더를 만든다. 셰이더의 출력은 색상을 나타내는 RGB값이다.

픽셀 셰이더는 프래그먼트 셰이더와 같은 의미로 사용되지만, 프래그먼트 셰이더가 더 정확한 단어이다.

프래그먼트 처리 단계에서 수행하는 중요한 2가지는 텍스쳐링(texturing)라이팅(lighting)이다. 텍스쳐링은 텍스쳐 매핑(mapping)이라고도 하며, 폴리곤 메쉬의 표면에 2D 이미지와 같은 텍스쳐를 입히는 작업을 한다. 라이팅은 조명을 의미하며 빛에 의한 물체의 색상 변화, 음영, 깊이감 등을 표현하는 것이다.

 

Texturing

아래와 같은 이미지(사진 파일)를 이미지 텍스쳐라 한다. 이미지 텍스쳐는 실제로 왼쪽과 같이 2차원 배열 형태로 구성되어 있다. 그리고 배열의 각 요소(element)들을 텍셀(texel)이라 한다. 화면의 구성 요소인 픽셀(pixel)과 구분하기 위한 단어이다.

image

위와 같은 이미지 텍스쳐를 아래와 같이 폴리곤 메쉬에 입힐 수 있다. 이러한 방식을 이미지 텍스쳐링이라하며, 이는 텍스쳐링 기법 중 하나이다.

image

이와 같이 텍스쳐가 메쉬에 입혀지기 위해선 메쉬의 각 정점에 대해 그에 대응되는 텍스쳐 좌표가 존재해야 한다. 즉 메쉬 위의 한 점 p가 존재할 때, p에 대응되는 텍스쳐의 좌표가 있을 것이다. 그 좌표를 q라 했을 때, 정점 pq라는 좌표를 가지고 있을 것이다. 그런데 이때 단순히 절대 좌표를 사용하게 되면 텍스처의 크기(해상도)가 달라졌을 때, 메쉬에 대한 대응점이 올바르지 않을 수 있다.

따라서 좌표의 범위를 정규화된 [0,1]로 설정해야 한다. 그러면 아래와 같이 한 정점이 자신에 대응하는 텍스쳐 좌표 (0.5, 0.5)를 가지고 있을 때 이미지 텍스쳐 크기와 상관없이 올바른 위치의 텍셀에 접근할 수 있다.

image

정점에 할당하는 텍스쳐 좌표계는 Direct3D와 OpenGL에서 서로 다르다. Direct3D에선 v축이 아래를 향하지만 OpenGL에선 위를 향한다. 위 좌표계는 Direct3D 기준이다.

image

위에서 간단하게 살펴본 이미지 텍스쳐링은 다음과 같은 단계들을 가진다.

  • 표면 파라미터화(surface parameterization)
  • 텍스쳐 좌표에서 텍셀 주소로의 매핑

 

표면 파라미터화(surface parameterization)

폴리곤 메쉬의 각 정점은 텍스쳐 좌표를 가지고 있다고 했다. 이처럼 폴리곤 메쉬의 각 정점에 텍스쳐 좌표를 할당하는 작업을 표면 파라미터화(surface parameterization)라고 한다. 이를 위해선 다음과 같이 폴리곤 메쉬를 2차원 평면에 펼쳐야 한다.

image

보통은 3차원 상태의 메쉬를 2차원에 펼쳤을 때, 메쉬를 구성하는 각 변의 길이가 유지되지 않아 왜곡 현상이 일어날 수 있다. 원통의 경우는 왜곡이 발생하지 않는 특수한 경우이다. 그러나 이러한 왜곡 현상을 최소화하는 연구가 활발히 진행되고 있고, 좋은 알고리즘들이 많기 때문에 걱정할 필요는 없다.

 

추가로 왜곡을 최대한 줄이기 위해 보통 폴리곤 메쉬의 영역을 부분별로 잘게 나눈다. 그리고 부분별로 나뉘어진 메쉬 위에 아티스트가 포토샵 등을 통해 그림을 그리곤 한다. 그 예가 아래의 (a)이며 이를 차트(chart)라고 한다. 그런데 이렇게 여러개로 나누어서 부분당 하나의 텍스쳐로 관리하게 되면 메모리를 많이 사용한다는 문제점이 있다. 예를 들어 1개의 메쉬에 5개의 부분이 존재한다면 텍스쳐를 저장하는 [0,1] 범위의 2차원 배열이 5개가 되며 관리도 힘들어진다. 또한 GPU는 여러개의 데이터를 병렬로 처리하는데 특화되어 있고, CPU와의 통신 속도는 느린 편이기 때문에 따로 처리하는 작업은 비효율적일 수 있다.

image

그래서 보통 (b)와 같이 여러 차트를 하나의 텍스쳐에 모아놓곤 한다. 이를 아틀라스(atlas)라고 하며 하나의 메쉬가 하나의 텍스쳐를 가지면서, 각 부분이 분할되어 있기 때문에 효율적으로 사용할 수 있다. (a)와 (b)의 u,v 범위는 모두 [0, 1]이다. 즉 (a)의 (0.5, 0.5) 좌표가 코를 가리킨다면, (b)에서 (0.5, 0.5) 좌표는 상의의 중앙을 가리킬 것이다.



텍스쳐 좌표에서 텍셀 주소로의 매핑

정점에 할당된 텍스쳐 좌표는 이전 단계인 래스터화 단계에서 스캔 변환을 할 때 다른 속성들과 함께 보간되어 프래그먼트에 할당되었을 것이다. 즉 정점의 컬러를 이용하여 변을 따라 보간하고 스캔 라인을 따라 보간하여 프래그먼트를 생성한 것처럼 텍스쳐 좌표도 보간될 것이다. 그러면 각 프래그먼트는 텍스쳐 좌표를 가지고 있을 것이다.

 

예를 들어 다음과 같은 폴리곤을 생각해보자. 첫 번째 정점 (1.5, 2.5)에서의 텍스쳐 좌표는 (0, 0)인데 폴리곤 한 변의 길이가 4이다. 텍스쳐 좌표는 정규화되어 있기 때문에 0부터 1까지의 범위를 가진다. 따라서 길이 1당 텍스쳐 좌표는 1/4씩 증가한다. 그러나 첫 번째 프래그먼트는 첫 정점으로부터 1이 아닌 0.5만큼 증가했으므로 1/8이 증가한다. y축으로도 0.5만큼 증가했기 때문에 (2,3)에서 첫 프래그먼트의 텍스쳐 좌표값은 (1/8, 1/8)이 된다. 이러한 텍스쳐 좌표들이 스캔 변환에서 정해졌을 것이다.

image

이러한 텍스쳐 좌표를 이용하여 메쉬에 이미지 텍스쳐를 입히는 방법은 다음과 같다. 아래와 같이 2차원 배열 형태의 텍스쳐가 존재할 때 각 구성 요소는 텍셀이며, 텍셀은 RGB값을 가지고 있다. 우리의 목표는 각 프래그먼트에 대응되는 텍셀을 찾아서 해당 텍셀이 가진 컬러를 프래그먼트에 입히는 것이다. 따라서 (1/8, 1/8)이라는 텍스쳐 좌표를 이용하여 실제 텍스쳐를 방문한다.

image

위 공식에서 u,v는 텍스쳐 좌표이며, Sx와 Sy는 텍스쳐의 해상도이다. 위 텍스쳐는 4x4의 해상도를 가지므로 tx = 1/8 x 4 - 0.5 = 0이 되며 ty도 동일하다. 따라서 (1/8, 1/8)에 대응되는 텍셀의 좌표는 (0, 0)이며, 해당 텍셀의 RGB 값을 가져다가 (1/8, 1/8) 위치의 프래그먼트에 입힌다. 모든 프래그먼트에 이러한 작업을 반복한다.



참고
<게임 프로그래밍을 위한 3차원 그래픽스>




댓글