[Game Jams] [Snow Footprint] 01. Deformer
- -
12월 공부 리스트인 중 하나인 Snow Footprint 프로젝트 분석을 위한 기초 공부 자료입니다.
본 포스팅은 http://developer.download.nvidia.com/books/HTML/gpugems/gpugems_ch42.html 의 내용을 번역 및 실습하며 이루어집니다.
1. 디포머란?
A. 명시적 정의 : 정점들의 집합을 연산했을 때 이 기존 정점들의 집합이 새로운 좌표를 가질 수 있도록 하는 연산자를 Deformer라고 한다.
i. 조건 :
1. Deformer에 의해 새로운 Vertex나 Edge가 생기면 안됩니다.
2. Deformer에 의해 변형된 정점은 다른 정점의 변화과정을 통해 영향을 받으면 안됩니다.
A. 위 규칙을 어기는 예 :
i. Vertex Averaging :
주어진 Vertice의 중심 값을 의미합니다.
ii.
Vertex Smoothing (Laplacian
Smoothing) :
폴리곤 매쉬를 부드럽게 만드는 알고리즘으로,
N = 노드 i에 연결된 인접 노드의 개수, x’j는 j번째 인접 노드의 좌표, x’i 는 새로 생긴 좌표입니다.
3. 같은 Defomer를 통해 위치 벡터를 변환시키면 벡터장에 상관없이 같은 결과가 나와야 합니다. (선형성 성립)
B. 수학적 정의
i.
일반적으로, 우리는 deformer를
vector 함수, f(x,y,z)라
생각합니다. 하지만 다음과
같이도
표현이
가능합니다. (fx(x,y,z), fy(x,y,z), fz(x,y,z))
두
번째
표현
같은
경우엔 기존 (x, y, z) 좌표를
각각의
컴포넌트
함수 fx, fy, fz를 사용해
새로운
벡터를
만드는
것을
의미합니다.
ii. Wave와 같이 공간에 의존하는 Deformer는 각 좌표계에서 각기 다른 결과를 도출 할 것 입니다.
iii. 회전, 닮음, 대칭, 이동과 같은 선형 변환은 모든 Deformer의 가장 간단한 하위 집합입니다. 이런 선형변환은 좌표 집합을 입력으로 받고 새로운 좌표 집합을 행렬 곱 형태로 출력합니다.
B. Controls
i.
deform 연산은
deformer의 컨트롤에
의존하며, 이 컨트롤이란
deformer 연산에 영향을
미치는 parameter입니다.
예를
들어, wave deformer의 결과는
wave의 진동수에
의존하며
이를
기술적으로
해석하면, 함수 f는
freq 변수에 의존한다고도
볼
수
있습니다.
그러나
우린
f(x, y, z, freq) 와
같이
표현하진
않을
겁니다. 대신 freq를 deformation을 위해
주어진
상수라고
생각할
것
입니다.
(freq는
정점들이
deformer에 의해
변형돼도
변하지
않습니다. 따라서 freq는
함수
f의 구성함수
중
적어도
하나에
상수로써
사용
될
것
입니다.)
변형
연산을
animate하기 위해
사용되는
time parameter도
마찬가지로
상수가
될
것
입니다.
(time parameter t는 x, y, z와
의존관계가
없음으로, f의 상수로
사용될
것
입니다.)
2. GPU에서의 Deforming
A. Deformer를 공식화하기
i. Deformer 연산을
우리의
수학적
정의와
맞게
공식화하면
법선
벡터(Normal) 을 계산하는데
용이
합니다.
(만약 y 축으로 2만큼
증가
시키는
deformer가 있다면
이를
함수
f형태로 표현하면, f(x,y,z) = (fx ,fy ,fz ) = (x,y + 2,z)
로 표현 할 수 있습니다. )
만약
우리가
방사형의
wave deformer를
구현한다면,
위와 같이 l 가 위상제어 parameter인 함수 f를 만들게 될 것 입니다.
B. Vertex Shader 작성해보기
i. 위 과정에서 deformer에 대한 함수를 작성했다면, 이 함수를 통해 정점을 수정하는 프로그램을 짜야 합니다.
Direct3D를 통한 그래픽스 작업에서 폴리곤은 아래 자료와 같은 Stage를 거쳐 처리됩니다.
(출처 : http://www.realtimerendering.com)
여기서 우리가 관심을 가져야 할 것은 처음에 있는 Vertex Stage입니다. 여기서 정점에 대한 연산을 하기에, 앞서
만든 Deformer Function을 이 곳에서 구현해야 합니다.
이런 그래픽 파이프라인에 관여 가능한 소스코드를 작성하기 위해, 각 그래픽 라이브러리는 다양한 언어를 지원합니다.
대표적 으로 Direct3D는 HLSL, OpenGL은 GLSL, 그리고 Cg가 있으며,
여기선 Unity Engine을 사용 할 것이기Cg Programming Language를 사용 합니다.
ii. Shader 작성
1. Property
A. _Amplitude : Wave의 높이 상수입니다.
B. _Frequency : Wave의 발생 빈도를 나타내는 상수입니다.
C. _Speed : Animate 속도에 곱해지는 계수입니다.
D. _Anchor : 이번 예제에선 정점의 월드 좌표계를 이용하기 때문에, 상대좌표를 얻기 위해 방사형의 시점이 될 월드좌표가 여기 저장됩니다.
E. _Cover : 사용되는 Mesh의 월드 사이즈를 담습니다.
2. DisplaceFunc
Mesh의 정점을 가공하는데 필요한 리소스를 계산하는 역할의 함수입니다.
본 함수에선 정점의 월드좌표
worldPos와 방사 시점과의 상대 좌표 relativePos를 얻습니다.
3. WaveFunc
앞서 공식화 했던 f를 코드화한 부분입니다.
A. dist : 방사형의 시점에서부터 정점까지의 거리를 저장하는 변수입니다.
B. 월드 좌표 pos를 수정하는 기본 과정은 다음과 같습니다.
i. 새로운 좌표에서의 pos.y = 기존 pos.y + _Amplitude * sin (_Frequency * dist - _Time.y * _Speed) / dist
ii. 마지막에 나눈 dist는 방사의 원점에서 멀어질수록 물결이 약해지는 효과를 줍니다. 하지만 dist가 0에 가까워질수록 한 없이 강한 물결이 만들어지기에, dist에 제한을 두어 제한을 넘길시 dist로 나누는 대신 _Cover * 2를 곱해 일정 높이를 유지하게 만들었습니다.
4. 결과
5. 정점의 Deforming은 간단하게 해결됐습니다. 하지만 변경된 정점의 법선 벡터 (Normal)는 어떻게 구할 수 있을까요?
A. Normal 이란?
i. 선형 변환은 매트릭스로 표현이 가능합니다. 우리는 이 매트릭스(M)의 역을 통해 Normal을 구할 수 있었는데, Wave Deformer 같은 경우엔 대게 비선형 변환이라 매트릭스 표현이 불가능해집니다.
(이유는 homomorphism 키워드를 통해 공부 하실 수 있습니다.)
따라서 우리는 이 비선형 변환에서도 Normal을 구할 수 있는 새 방법이 필요합니다.
B. 근사 수치 기법
i. deformed 된 normal을 얻기 위한 방법 중 하나며, 모든 입력 정점에 대해 세 정점을 deforming 함으로써 근사한 normal 값을 구 합니다. 세 점 중 하나는 입력 정점이며, 나머지 두 정점은 각각 입력정점을 tangent 방향으로, binormal (bitangent) 방향으로 매우 약간 이동시킴으로써 얻을 수 있습니다. 이렇게 만든 세 정점은 2개의 벡터를 만들며, 이 두 벡터를 외적하면 Normal 벡터를 얻을 수 있습니다. 이를 이용해서, 세 정점을 Deforming 하고 얻은 Deformed 된 정점들로 Normal을 구할 수 있습니다. 이 방법은 세 정점이 가까이 모여있을수록 더 정확한 값을 얻을 수 있습니다.
C. The Jacobian Matrix
i. 만약 deformer f(x, y, z) = (fx, fy, fz)가 연속인 1차 편미분을 갖는다면 우리는 Jacobian Matrix (called J)를 사용 할 수 있습니다. 우리는, f(x)가 끊김 없이 부드럽게 이어진다면 이 함수는 근사적으로 직선으로 간주 할 수 있다는 점을 이용해서 f(x) ~ f'(a)(x - a) + f(a)를 J를 이용해서 f(x) ~ J(a)(x - a) + f(a) 와 같이 표현 할 수 있습니다. 이는 ‘테일러 정리’에 의해 밝혀진 부분이니 궁금하신 내용은 추가적으로 공부하시면 됩니다.
ii. J 선형변환 :
이제 위를 이용하여 원하는
position을 deform 할 수 있으며,
J * tangent, J * binormal 를 통해 deformed된 tangent와 binormal을 얻을 수 있습니다.
iii. J를 통한
Normal 계산 :
6.
근사 수치 기법을 이용한 프로그래밍
이 포스팅 이후 진행 할 프로젝트 분석(Tessellator)에선 근사 수치 기법으로 normal을 구했기 때문에 원문과는 다르게 근사 수치 기법으로
normal를 구해보겠습니다.
7.
수정된 DisplaceFunc
한 개의 입력 정점의 월드 좌표와 두 개의 가상 정점을 만드는 과정이 추가됐습니다.
과정에서 bitangent가 필요해 최 상단에 bitangent를 추가로 구했습니다.
Anchor와의 상대좌표를 얻습니다.
이는 방사의 시점에서부터 정점까지의 거리를 측정하는데 사용됩니다.
세 정점을 모두 Deforming 합니다.
Deformed 된 정점으로부터 구한 두 Vector를 통해 deformed normal을 구합니다.
8.
Normal을 추가한 효과를 보기 위해 Light를 추가해봅시다.
9.
결과
'개발 > Shader' 카테고리의 다른 글
[Snow Footprint] 02.Tessellator - 02 (Tessellator and Domain Stage) (0) | 2017.12.16 |
---|---|
[Snow Footprint] 02.Tessellator - 01 (Hull-Shader) (0) | 2017.12.16 |
[Unity PBR] Standard Shader의 제질에 따른 Albedo Color (0) | 2017.12.08 |
<자료조사>[Water Foam] Gerstner Wave (0) | 2017.12.05 |
12월 목표 공부 커리큘럼 정리 (0) | 2017.11.25 |
소중한 공감 감사합니다