오돌토돌한 표면을 렌더링하기 위해 고해상도 메시의 불규칙한 노멀을 사용한다.
(a)에 (b)의 텍스처를 입혀 (c)의 결과를 얻은 것을 확대한 것이 (d)이다.
점 b의 경우 n과 l사이 각도가 커서 빛을 적게 받고 어두워 보인다.
빠른 연산을 위해 다음 그림에서는 삼각형 두 개로 구성된 메시를 사용했다. 하지만 저해상도 메시로는 오돌토돌한 표면이 잘 표현되지 않는다. a에서 b를 거쳐 c로 갈 때 n과 l 사이 각도는 서서히 작아져서 점차 밝아보인다.
위 문제를 해결하기 위한 방법은 고해상도 메시의 노멀을 미리 계산 후, 노멀맵이라고 하는 특수한 텍스처에 저장한 후, 런타임에는 그림 (a)의 저해상도 메시를 처리하되 노멀맵으로부터 노멀을 읽어 라이팅에 사용한다. 이러한 특수한 텍스처링 기법을 노멀 매핑 혹은 범프 매핑이라고 부름.
하이트맵
하이트맵은 균일하게 샘플된 (x, y)좌표에 높이 값이 저장되며, 회색조 이미지로 가시화할 수 있다.
(a)를 보면 일정한 간격의 (x, y) 좌표에서 샘플된 하이트 필드를 보여주는데, 이러한 높이 값을 저장한 2차원 텍스처를 하이트맵이라고 한다.
이번 장에서는 노멀 매핑을 위해 하이트맵이 어떻게 사용되는지 기술한다.
하이트맵은 지형을 표현하는 대표적인 기법이며, 물과 같은 유체의 표면 표현에도 자주 사용된다.
하이트맵으로부터 폴리곤 메시를 생성하는 방법은 매우 간단한데, (c)를 보면 직관적인 이해가 가능하다.
노멀맵 만들기 - 하이트맵 이용
하이트맵의 한 점에서의 노멀은 그 이웃 점들의 높이를 이용해 계산한다.
위 그림에서는 하이트맵 텍셀 9개를 이용해 사각형 메시를 만든 모습을 볼 수 있다. (x,y,h(x,y))의 노멀은 벡터곱으로 (x,y)에 저장된다.
(c)를 보면 RGB 색상 대신 노멀 벡터들을 저장하고 있는 노멀맵을 개념적으로 그렸는데, 모든 노멀은 (0, 0, 1) 방향의 벡터를 ‘흔들어 놓은’ 것으로 묘사된다.
보다 복잡한 알고리즘을 사용해 노멀맵을 계산하는 경우, 네 개 이상의 이웃 점들을 사용하기도 한다.
정규화된 노멀 (nx, ny, nz)의 각 좌표는 모두 [-1, 1] 범위의 실수값이다.
반면, 이런 노멀을 저장할 텍스처의 RGB 채널은 모두 [0, 1] 범위에 있다.
따라서 다음과 같은 범위 전환이 필요하다.
노멀맵은 (0, 0, 1)을 조금씩 흔들어 놓은 노멀들의 집합으로 이해할 수 있다. 따라서 nz가 nx와 ny에 비해 상대적으로 클 것이고. 위 수식에서 계산된 R, G, B중 B값이 크게 된다.
→ 그림 속 (c)처럼 전체적으로 파란 색조를 띨 것.
노멀 매핑 쉐이더
기초 표면: 노멀 매핑에 입력으로 제공되는 폴리곤 메시
기초 표면은 래스터라이저에 의해 프래그먼트로 분해되고, 각 프래그먼트의 라이팅을 담당하는 프래그먼트 쉐이더는 노멀맵으로부터 노멀을 얻게 된다.
노멀 매핑을 위한 정점 쉐이더.
정점 노멀 입력이 없음에 주목한다. texCoord는 v_texCoord에 그대로 복사된다.
프래그먼트 쉐이더는 보간된 텍스처 좌표 v_texCoord를 입력으로 받아 이를 이용해 노멀맵으로부터 노멀맵으로부터 노멀을 얻어 라이팅에 사용할 것이다.
노멀 매핑을 위한 프래그먼트 쉐이더
위 코드는 퐁 라이팅을 구현한 9.2절의 코드를 수정한 것이다. 5번 줄에는 이미지 텍스처(colorMap) 말고도 노멀맵(normalMap)이 정의되었다. 이는 18번째 줄에서 v_texCoord를 사용해 필터링되는데, 내장 함수 texture는 RGB 색상을 출력한다. RGB 각 채널은 [0, 1] 범위에 있으므로, 이를 [-1, 1] 범위로 전환해야 하는데, 이는 위 범위 전환 수식이 했던 일을 되돌리는 것과 같다.
노멀맵이 겹선형보간을 통해 필터링되면 위에서 얻은 (nx, ny, nz)는 대개의 경우 그 길이가 1이 아니다. 따라서 18번 줄은 내장 함수인 normalize를 호출했고, 그 결과 정규화된 벡터 normal은 디퓨즈 항 계산(25번째 줄) 및 스페큘러 항의 반사 벡터 계산(28번째 줄)에 사용됐다.
위 그림은 ‘이미지 텍스처링’과 ‘노멀 매핑이 결합된 이미지 텍스처링’을 비교한 것이다.
이 예에서 사각형이 좌표계 xy 평면에 놓여 있다고 가정한다.
노멀 매핑을 사용하지 않을 경우, 모든 프래그먼트의 노멀은 z축을 향하는 단위 벡터인 (0, 0, 1)로 고정된다. 반면, 노멀 매핑을 사용하는 경우, 프래그먼트의 노멀은 모두 노멀맵에서 읽어오는데, 이 노멀은 (0, 0, 1)을 이쪽저쪽으로 조금씩 흔들어 놓은 벡터일 것이다.
탄젠트 공간 노멀 매핑
노멀 매핑. (a)는 노멀맵을 가시화 한 모습이고, (b)는 다양한 표면에 입혀진 노멀맵이다.
텍스처링은 물체 표면에 벽지 바르듯이 텍스처를 입히는 것으로 이해하면 된다. 노멀 매핑을 위해서는 이미지 텍스처링에서는 불필요했던 한 가지 작업을 더 수행해야 한다.
물체 표면의 어떤 점에 노멀 매핑을 적용하건, 노멀맵에서 읽어온 노멀은 바로 그 점의 탄젠트 공간에서 정의된 벡터로 보면 된다. 이 때 탄젠트 공간 노멀맵이라는 용어를 쓴다.
아까 살펴봤던 프레그먼트 쉐이더는 25번 줄에서 dot(normal, light)를 호출했다. 하지만 이는 우연히 성공했을 뿐이다.
normal은 탄젠트 공간 벡터인 반면 light는 월드 공간 벡터이다. 서로 다른 공간에서 정의된 벡터들에 대해 내적 연산을 수행할 수는 없다.
위 그림과 같이 특별한 경우에서는, 사각형 표면의 어느 점을 고르던 그 점에서의 탄젠트 공간 기저는 월드 공간 기저와 동일하다.
문제를 해결하는 방법은 두 가지가 있다.
- normal을 월드 공간으로 변환하는 것
- light를 탄젠트 공간으로 변환하는 것.
후자를 통해 문제를 해결해보자.
물체 표면의 각 점은 자신만의 탄젠트 공간 기저를 가질 수 있으므로, light를 탄젠트 공간으로 변환하는 행렬은 각 프래그먼트마다 새로 계산되어야 한다.
오브젝트 공간에서 정의된 벡터들 T, B, N이다.
정점 쉐이더는 여기에 먼저 월드 변환을 적용하여 이들을 월드 공간으로 옮긴다.
그 다음 월드 공간 벡터 T, B, N을 행으로 가지는 3*3 회전 행렬을 구성한다.
이는 바로 월드 공간 벡터를 탄젠트 공간으로 변환하는 기저 이전 행렬이다.
위는 탄젠트 공간 노멀 매핑을 위한 정점 쉐이더이고,
이 부분은 탄젠트 공간 노멀 매핑을 위한 프래크먼트 쉐이더 코드이다.
이미지 텍스처와 노멀맵 한 쌍이 공, 원통, 도넛에 적용된 모습을 볼 수 있다.
탄젠트 공간 계산은 다음과 같이 이루어진다.
(c)는 삼각형 <p0, p1, p2>와 함께 T와 B축을 보여주는데, 여기에서 T와 B축은 아직 결정되지 않은 상태이다. p0와 p1을 연결하는 벡터를 q1으로, p0와 p2를 연결하는 벡터를 q2로 표기하면, q1과 q2는 다음과 같이 정의된다. (14.4 수식)
아래와 같이 고쳐 쓸 수도 있다.
노멀맵 제작
평면이나 곡률이 낮은 곡면에 입혀질 노멀맵은 2차원 그래픽스 패키지를 사용해 만들 수 있다. 하지만 복잡한 곡면을 위한 노멀맵은 2차원 그래픽스 패키지로 제작하기 어려우므로 Pixologic사가 개발한 지브러쉬와 같은 조각 도구를 사용한다.
위 그림은 저해상도 모델을 오돌토돌한 표면을 가진 고해상도 모델로 바꾸는 과정을 보여준다.
(a)는 입력으로 주어진 저해상도 모델이고,
(b)는 (a)를 자동으로 세분화하여 얻은 고해상도 모델인데 이는 수작업을 통해 (c)와 (d)를 거쳐 (e)의 오돌토돌한 모델로 변환된다.
지브러쉬는 우선 기초 표면을 파라미터화 한다. 이 결과, 기초 표면의 모든 정점은 정규화된 텍스처 좌표 (s, t)를 가지게 된다. 우리가 만들고자 하는 노멀맵의 해상도가 rx * ry라 하자. 그러면 좌표 s와 t에 각각 rx와 ry를 곱해서 새로운 좌표 (rxs, ryt)를 정의한다. 그림 (b)는 이렇게 파라미터화 된 후 rx * ry 크기를 가지게 된 기초 표면을 보여준다.
이제 기초 표면의 각 삼각형은 (b)의 오른쪽 상자에 보인 것처럼 스캔 전환되어 다수의 텍셀을 포함하게 된다. 각 텍셀에 노멀을 할당하면 해상도가 rx * ry인 노멀맵이 완성되는 것이다.
이제까지 기술한 알고리즘은 오브젝트 공간에서 노멀을 계산했다.
이러한 노멀을 저장한 텍스처를 오브젝트 공간 노멀맵이라 부른다. 이는 (e)에 RGB 색상으로 가시화되었다.
오브젝트 공간의 노멀을 탄젠트 공간으로 변환해야 한다. (c)를 보면
탄젠트 공간의 기저를 계산 후 p의 무게중심 좌표를 사용하여 정점별 기저를 보간하면 p의 탄젠트 공간 기저를 얻을 수 있다. 그렇게 얻은 p의 T, B, N으로 행렬을 구성하면 그것이 오브젝트 공간 노멀 n을 탄젠트 공간으로 변환하는 기저 이전 행렬이 된다. 이렇게 생성된 탄젠트 공간 노멀맵은 (f)에 가시화되었다. (g)에서는 노멀 매핑을 적용한 모델, 하지 않은 모델을 비교한다.
이미지 출처: [OpenGL ES를 이용한 3차원 컴퓨터 그래픽스 입문]
위 서적을 보고 공부한 내용을 정리함
'컴퓨터 그래픽스' 카테고리의 다른 글
2024.7.31(수) - 16장 전역 조명과 텍스처링 (1) | 2024.08.11 |
---|---|
2024.7.26(금) - 15장 쉐도우 매핑 (0) | 2024.08.11 |
2024.7.21(일) - 13장 캐릭터 애니메이션 (0) | 2024.07.21 |
2024.7.20(토) - 12장 스크린 물체 조작 (0) | 2024.07.21 |
2024.7.20(토) - 11장 오일러 변환 및 쿼터니언 (0) | 2024.07.21 |