일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- ASW(Application SpaceWarp)
- 가상 바이트
- 메모리 누수
- C언어
- OculusMotionVectorPass
- Windows Build
- VR
- URP로 변경
- Private Bytes
- Cell Look
- Toon Shader
- 3d
- Virtual Byte
- 개인 바이트
- Cell Shader
- 프로그래밍 기초
- 벡터
- ColorGradingLutPass
- Cartoon Rendering
- Rim Light
- working set
- URP
- 게임 수학
- AppSW
- 작업 집합
- Three(Two) Tone Shading
- Specular
- Today
- Total
WinCNT
Normal Mapping 본문
구현은 어렵지 않지만 원리는 어렵다
Normal, Light
노멀 "맵"
Map 자체는 텍스처이므로 Diffuse처럼 읽으면 된다
(SRV로 Shader로 보내면 됨)
노멀 맵 자체는 텍스처와 마찬가지로 RGB의 정보이다
Normal Map은 텍스쳐의 RGB 정보에 노말벡터 XYZ를 인코딩한 맵이다
하지만 그 노말 좌표들은 모두 접선 공간(Tangent Space)을 기준으로 작성된다
노멀 맵 쓰는 이유는 픽셀당 조명(Per-Pixel Lighting)을 구현하기 위해서이다
이러한 노말들을 객체공간으로 변환시키기 위해서는
정점마다 접선(Tangent)과 종법선(Binormal), 그리고 법선(Normal) 정보를 가지고 있어야 한다
정점 쉐이더에서 접선과 종법선, 법선을 픽셀로 넘긴 다음
픽셀 쉐이더에서는 그 정보를 가지고 적절히 보간한 다음 객체 공간으로 변환할 수 있다
Normal Mapping
노멀 매핑(Mapping)
노멀 값을 삼각형 표면에 바른다고 생각하면 됨
접선 공간(탄젠트 스페이스)
매 페이스(정점)마다 좌표계가 다름
Geomatry 자체는 바꿔주지 않음
(하이폴리곤으로 바뀌지 않음)
리토폴로지
하이폴리곤을 만든다
그걸 기반으로 로우폴리곤으로 만든다(리토폴로지)
하이폴리곤과 로우폴리곤의 차이를 에디터가 탄젠트 값을 계산한다
접선 공간(Tangent Space)
접선 공간 = 탄젠트 공간 = 표면 공간, 텍스처 공간 등등
접선 공간은 다음을 축으로 하는 공간이다
- 한 점(버텍스)의 노멀 벡터
- 한 점(버텍스)의 접선(탄젠트) 벡터
- 위의 둘을 외적한 바이노멀(혹은 바이탄젠트) 벡터
탄젠트 벡터는 노멀 벡터와 수직인 벡터이다
문제는 Tangent Vector가 한두 녀석이 아니라는 것이다
Normal 에 수직인 벡터는 사실상 Normal Vector가 만들어내는 평면 위의 모든 벡터들이 해당된다
따라서 그래픽스에서는 통상적으로 텍스쳐 좌표인 UV 좌표와 비교하여
U좌표와 일치하는 Vector를 Tangent, V 좌표와 일치하는 Vector를 BiTangent Vector라고 일컫는다
즉, 접선 공간은 텍스처 위에서의 좌표계이기도 하다
(텍스처 공간으로 불리는 이유)
탄젠트 스페이스(접공간) 구하기
사실 Vertext정보의 Normal, 그리고 Tangent 값이 있으면 구할 수 있다
(나머지 축은 외적으로 구함)
탄젠트 값이 없는 경우
포지션, 텍스처 좌표가 있어야함
거기서 TBN(?)을 계산한다
(N은 노멀)
T(탄젠트), B(바이노멀, 바이탄젠트)
기저벡터를 곱해서 간다
양은 UV차이 만큼?
탄젠트 값이 없을 때 T(탄젠트)와 B(바이탄젠트)를 구하는 법은
텍스처(UV) 자체의 좌표계와 월드 공간에서의 접선 공간 좌표계의
좌표계 변환 행렬을 구하는 것이다
내가 이해한 생각으로는 텍스처(UV) 자체의 좌표계가
월드 공간의 탄젠트 좌표계로 매핑된다는 것을 기반으로 한 것이다
텍스처의 U축은 탄젠트 좌표계의 T축, V축은 접선 공간 좌표계의 B축으로 매핑된다고 하자
아직 좌표계 변환 행렬
(Tx, Ty, Tz)
(Bx, By, Bz)는 모르는 상태이다
여기서 삼각형의 버텍스에서 e1 = p1 - p0, e2 = p2- p0이라 할 때,
UV 텍스처에서 매핑되는 벡터를 구할 수 있다
그리고 버텍스의 정보에서 e1, e2의 값과 텍스처의 좌표값도 알 수 있으므로
연립방정식을 풀면 좌표계 변환 행렬
(Tx, Ty, Tz)
(Bx, By, Bz)를 구할 수 있다
-1~1에서 0~1
기본이 0, 0, 1(그래서 보라색 기반?)
Z축 밀도가 압도적으로 높다
나머지는 약간씩 다름
X, Y, Z에서 2가지만 알아도 된다
오버워치는 (1, 0 , 1)로 저장하므로 노멀맵이 노란색이다?
(DXT5NM 포맷)
공간상의 이득이 생긴다
Tangent 공간 <=> Object 공간 변환
노말맵에 저장된 값은 tangent 공간에 있고 Light 벡터등은 object나 world 공간에 있기 때문에
같은 공간상의 값으로 변환해야 한다
최적화를 위해서는 Tangent 공간으로 맞추는 편이 좋다
Light 벡터나 View 벡터 등을 tangent 공간으로 변환하기 위해서는 Vertex Shader에서 한 번만 변환시켜주면 되지만,
노말맵의 값을 object(혹은 world) 공간으로 변환시키기 위해서는 Pixel Shader에서 매픽셀마다 변환 연산이 수행되야 하기 때문이다
하지만 최근 하드웨어는 매우 좋아졌기 때문에 걍 무시하고 월드 공간에서 계산하는 것 같다(사실 월드 공간이 가독성이 좋기도 하구...)
object 공간을 tangent 공간으로 변환하는 행렬은
vertex에 저장된 normal, tangent, binormal 값으로 만들 수 있다.
object-to-tangent matrix =
(Tx Ty Tz)
(Bx By Bz)
(Nx Ny Nz)
float3x3 matObjectToTangent;
matObjectToTangent[0] = input.tangent;
matObjectToTangent[1] = input.binormal; //input.tangent 와 input.normal을 외적하여 직접 계산할 수도 있다.
matObjectToTangent[2] = input.normal;
float3 vTangentSpace_Light = mul(matObjectToTangent, vObjectSpace_Light );
행렬의 곱은 교환 법칙이 성립하지 않으니 행렬과 벡터를 곱하는 순서가 중요하다
보통은 tangent 공간을 사용하지만
deferred 시스템과 같은 경우는 object 공간을 사용하기도 한다
obejct 공간을 사용하기 위해서는 노말맵의 값을
tangent 공간에서 object 공간으로 변환시켜야 하므로
object 공간을 tangent 공간으로 변환하는 행렬의 역행렬이 필요하다
하지만! 역행렬을 계산할 필요는 없다!
왜냐하면 object 공간을 tangent 공간으로 변환하는 행렬은 직교 행렬이므로
역행렬 계산을 하지 않아도 전치를 시키면 된다!
게다가! 사실 전치 행렬도 구할 필요가 없다!
단순히 벡터와 행렬의 곱의 순서를 바꾸면 된다
float3 vTangentSpace_Normal = normalize( tex2D(NormalMap, input.texcoord).xyz *2.0f -1.0f );
vTangentSpace_Normal.y = -vTangentSpace_Normal.y; //tangent 공간은 y축이 반대이다.
float3x3 matTangentToObject;
matTangentToObject[0] = input.tangent;
matTangentToObject[1] = input.binormal; //input.tangent 와 input.normal을 외적하여 직접 계산할 수도 있다.
matTangentToObject[2] = input.normal;
float3 vObjectSpace_Normal = mul(vTangentSpace_Normal , matTangentToObject);
https://blog.daum.net/rockeracer/56
기타
카메라 뷰 스페이스
동차 좌표계, w로 나누는 거
탄젠트 스페이스 만드는 것
왜 보라색인가?
오버워치 특) 왜 노란색?
SSS
'게임 프로그래밍(학습 내용 정리) > 3D Game Programming' 카테고리의 다른 글
Post Processing (0) | 2022.05.19 |
---|---|
깊이 버퍼(Depth Buffer) (0) | 2022.05.18 |
Picking (0) | 2022.05.06 |
Skinning (0) | 2022.04.29 |
Animation2 (0) | 2022.04.27 |