이 게시글에선 실제로 노말맵을 적용하는 수학적 연산은 설명하지 않을 것이다.
두 노말맵의 종류와 장단점에 대해선만 설명할 것..
우리는 3D 오브젝트의 표면 색상을 자연스럽게 결정짓기 위해 표면의 노말(법선)을 사용해 빛을 계산하여 색상을 결정짓곤 한다.
일반적으로 이 노말 벡터의 정보는 각 버텍스(정점)에 담겨져 있으며 버텍스 쉐이더의 Input으로 받아서 사용할 수 있다.
하지만, 버텍스에 저장된 노말 벡터를 사용하는 것은 다소 한계가 있다.
이러한 모델을 생각해 보자. 벽돌 사이 시멘트 부분은 움푹 파여있으므로 이 부분에 대해선 노말벡터가 벽돌의 평면과 다르게 적용되어야 한다. 이러한 노말 벡터의 값을 모든 정점이 보유하게 하려면 해당 모델의 정점 개수는 매우 많아질 것이고 이는 메모리 사용량과 쉐이더 연산량의 증가로 이어진다. 즉 최적화 측면에서 매우 손실을 보게 된다.
이러한 개념에서 시작된 것이 노말맵이다. 먼저, 위의 모델을 표현하기 위해 4각형 하나를 만들고, 그 위에 평면의 벽돌 색상의 디퓨즈(알베도) 텍스쳐를 입히는 것이다. 그리고 또 하나의 텍스쳐에는 의도에 맞게 노말 벡터를 저장하여, 버텍스에 저장된 노말 값이 아닌 해당 텍스쳐에 저장된 노말값을 사용하여 빛을 연산하는 것이다.
이렇게 되면, 정점별로 노말 벡터를 저장하기 위해 매우 많은 정점을 만들고 데이터를 보관할 필요 없이 하나의 텍스쳐만을 추가로 활용하여 음영을 디테일하게 연산할 수 있게 되는 것이다. (물체를 실제로 울퉁불퉁하게 만드는 것이 아니라, 실제로는 평면이지만 울퉁불퉁한 물체인 것처럼 노말 벡터를 저장하여 빛을 연산하여 속이는 것이다.)
그리고, 그 노말 벡터가 저장된 텍스쳐를 노말 맵(Normal Map)이라고 한다.
이러한 노말 맵에는 두 가지의 종류가 있다. 로컬 스페이스 노말 맵과 탄젠트 스페이스 노말 맵이다.
로컬 스페이스 노말 맵
로컬 스페이스 노말 맵이란, 3D 모델의 방향(회전이 적용되지 않은 상태)를 기준으로 노말을 계산하여 저장하는 것이다.
이렇게 구형의 물체가 있다고 가정해보자. 회색 네모가 칠해진 최상단의 버텍스의 UV좌표가 (0, 0)이라고 가정해보자.
하늘색 화살표는 해당 정점의 노말 벡터이다.
이 때, 물체가 회전하여 아래와 같이 된다면?
이 때, 노말 벡터는 아래 그림처럼 향하는 것이 우리가 의도한 방향일 것이다.
하지만 노말맵에서 매핑하여 사용하게 되면 아래 그림과 같이 되어있다.
노말 맵은 물체가 회전되지 않은 최초의 형태를 기준으로 값이 저장되어 있으므로, 노말맵의 값을 그대로 사용하면 이렇게 노말이 제대로 적용되지 않는다. 그러므로 물체의 회전 행렬을 노말 벡터에도 곱해주어 노말 벡터에 매번 회전을 적용해주어야 정상적으로 적용된다.
로컬 스페이스의 노말 맵은 이처럼 물체의 회전에 영향을 받지 않는 상태로 저장되어 있으므로 매번 회전을 적용하여 벡터의 방향을 갱신해야 한다.
탄젠트 스페이스 노말맵
탄젠트 스페이스 노말 맵은 버텍스의 탄젠트, 바이탄젠트, 노말 값을 축으로 사용하는 탄젠트 공간에서 저장된 노말 벡터를 사용하는 노말 맵이다. 이게 무슨말이냐면...
하나의 정점에는 노말 벡터가 존재하고, 그 노말 벡터에 수직인 탄젠트가 존재한다. 여기서 탄젠트란 해당 정점의 접선이라고 할 수 있다. 그리고 탄젠트 벡터와 노말 벡터에 대해 수직인 또 하나의 벡터(바이 탄젠트)도 존재할 것이다.
이 3개의 벡터를 X,Y,Z 축으로 활용해 T(탄젠트), B(바이 탄젠트), N(노말) 축을 만들 수 있고 이 축에 대해 노말 값을 저장하는 것이 탄젠트 스페이스 노말 맵이다.
그런데 왜 이렇게 복잡하게 노말 값을 저장하는 걸까?
로컬 스페이스 노말맵과 탄젠트스페이스 노말맵의 장단점
일반적으로 프로그래밍에서 어떠한 기법의 장점을 말한다면 항상 3가지 중 하나로 답이 나온다.
빠르거나, 메모리를 적게 사용하거나, 편하거나.
이 3개를 기준으로 두 노말맵을 비교해보겠다.
1. 누가 더 빠른가?
로컬 스페이스 노말맵은 매번 픽셀 쉐이더에서 회전행렬을 곱해주어야 한다.
하지만, 탄젠트 스페이스 노말맵은 회전행렬을 버텍스 쉐이더에서 곱해도 된다.
왜냐하면, 탄젠트 스페이스에서 정의된 노말 벡터의 경우, 노말 벡터에 회전을 적용하는 것이 아니라 정점의 탄젠트, 바이 탄젠트, 노말에 회전을 적용해야 하기 때문이다. 이 정보는 정점 단위로 주어지므로 버텍스 쉐이더에서 해결할 수 있다.
즉 회전 연산 자체는 탄젠트 스페이스가 일반적으로 더 적게 수행되는 편이다.
하지만, 빛을 적용하기 위해선 광원과 노말벡터의 좌표계를 맞춰주어야 한다. 광원을 탄젠트 스페이스로 옮기든가, 노말 벡터를 월드 스페이스로 옮기든가. 광원을 탄젠트 스페이스로 옮기는 것은 버텍스 쉐이더에서 수행할 수 있으므로 광원을 탄젠트 스페이스로 옮겨서 빛을 계산하는 것이 일반적으로 더 효율적일 것이다.
하지만, 로컬 스페이스 노말맵의 경우엔 이런 연산을 하지 않아도 된다. (이미 광원과 좌표계가 일치하므로)
그렇기 때문에 회전하지 않는 물체에 대해서 로컬 스페이스 노말맵은 회전도 좌표변환도 수행하지 않아도 되기 때문에 연산량이 상대적으로 매우 적지만, 탄젠트 스페이스 노말맵은 항상 좌표계를 맞춰주는 연산을 해야하기 때문에 회전하지 않는 물체에 대해서는 더 많은 연산이 수행될 것이다.
그러므로 일반적으로 생각했을 때, 회전하는 동적인 물체에 대해선 탄젠트 스페이스 노말 맵이 더 성능에 유리하지만 회전하지 않는 정적인 물체에 대해선 로컬 스페이스 노말 맵이 더 성능에 유리할 것이다.
2. 누가 더 메모리를 적게 사용하는가?
노말 맵에 저장된 노말 벡터는 일반적으로 정규화되어 저장된다. 정규화되었다는 뜻은 X^2 + Y^2 + Z^2의 값이 1이라는 뜻이다. 이 때, X, Y 를 알면 Z를 얼추 구할 수 있다. Z^2 = 1 - X^2 - Y^2 이기 때문이다.
하지만, X, Y를 알더라도 z를 정확히 구할 수는 없다. 왜냐하면 양수와 음수 두 가지가 존재하기 때문이다. 어느 것이 실제 값인지 유추할 수 없으므로 우리는 x,y,z를 모두 정확히 알아야만 한다.
하지만, 탄젠트 스페이스의 경우 조금 다르다. 탄젠트 스페이스는 정점을 기준으로 정의된 공간이다. 이 탄젠트 스페이스에서 정점의 노말은 항상 양의 방향을 향한다. (당연하지만 법선은 평면의 표면이 향하는 방향이다. 이 방향은 항상 양의 방향일 수 밖에 없다.)
그러므로 탄젠트 스페이스에서 정의된 노말 벡터는 x, y만 알더라도 z를 유추할 수 있게 된다. 그러므로 노말 맵에도 R,G,B 채널 모두 사용할 필요 없이 R,G 채널만 사용하여 값을 저장할 수 있게 된다. 이로 인해 탄젠트 스페이스 노말맵은 B, A 채널을 다른 목적(러프니스, 메탈릭 등)을 위해 사용할 수 있게 되고, 이로 인해 메모리를 절약할 수 있게 된다.
3. 누가 더 사용하기 편한가?
이건 사실 둘 다 또이또이 인 듯 하다. 둘 다 사용하기 어려운 것도 아니고, 누가 더 편하고 말고 할 건 크게 없는 듯 하다. 굳이 따지자면 탄젠트 스페이스의 경우 좌표계를 고려해야 하기 때문에 조금 더 복잡할 수는 있다.
결론
회전하지 않는 물체에 대해서 로컬 스페이스 노말맵을 사용하게 되면, 메모리를 조금 더 사용하는 대신 더 빠르게 연산을 수행할 수 있다.
회전하는 물체에 대해선 탄젠트 스페이스 노말맵이 성능, 메모리 두 측면에서 모두 유리하다.
'그래픽스' 카테고리의 다른 글
컴퓨터 그래픽스 - Forward / Deffered / Forward+ Rendering (1) | 2024.10.30 |
---|---|
컴퓨터 그래픽스 - 우버 쉐이더 (Uber Shader) (1) | 2024.10.09 |
컴퓨터 그래픽스 - 투명도 처리 (알파 테스팅, 알파 블렌딩, 알파 소팅) (0) | 2024.06.18 |
컴퓨터 그래픽스 - LOD (Level Of Detail) (0) | 2024.06.16 |
컴퓨터 그래픽스 - 드로우 콜(Draw Call)과 배칭(Batching) (1) | 2024.05.21 |