- 3D 그래픽스에서 관성처럼 쓰이던 4x4 행렬 대신 Euclidean PGA를 glTF 호환 포워드 렌더러에 끝까지 적용해 보는 실험임
- 회전과 이동은 8개 float의 PGA motor로 표현되며, 일반 motor 합성은 4x4 행렬 곱의 64곱셈·48덧셈보다 적은 48곱셈·40덧셈으로 처리됨
- 점 변환은 단순 전개하면 행렬보다 비싸지만, 정규화 조건을 이용한 sandwich product로 21곱셈·18덧셈까지 줄어들고 방향·기저 방향 변환은 더 저렴함
- tangent space normal mapping에서는 normal과 tangent를 tangentRotor로 대체해 정점 데이터를 12 float에서 9 float로 줄이면서, world-space 변환 비용도 행렬 방식과 비슷한 47곱셈·38덧셈 수준에 맞춤
- 실제 glTF 콘텐츠와 맞물리려면 로드 시 행렬을 motor로 바꾸고 uniform scale을 별도 float로 추적해야 하며, non-uniform scale은 제한 처리나 4x4 행렬 대체 경로가 필요함
PGA로 만든 행렬 없는 포워드 렌더러
- 프로젝트는 Look, Ma, No Matrices로, 행렬 없는 포워드 렌더러 구현을 목표로 함
- 2019년 SIGGRAPH 이후 Geometric Algebra, 특히 Euclidean PGA가 그래픽스와 머신러닝 커뮤니티에서 관심을 얻었지만, 전통적인 3D 그래픽스에서는 dual quaternion을 PGA motor로 다시 부르는 수준에 머문 경우가 많았음
- 이 구현은 glTF 호환 3D 엔진에 PGA algebra를 통합해, 단순한 대수 이름 바꾸기가 아니라 그래픽스 파이프라인의 여러 부분을 PGA 방식으로 다시 구성함
- 기준 구현은 Khronos glTF viewer이며, 최적 성능 구현이라기보다 행렬을 타협 없이 대체하는 실험에 가까움
- 최종적으로는 hybrid solution이 더 나은 선택일 가능성이 높음
4x4 행렬을 의심하는 이유
- 4x4 행렬은 그래픽스 API와 GPU 고정 기능 파이프라인에서 오랫동안 중심 역할을 했고, 여전히 일반적인 포워드 렌더링의 기본 도구임
- 현대 GPU는 고정 기능 파이프라인보다 프로그래머블 스칼라 프로세서에 가까워져, 행렬 중심 표현이 반드시 필요하지는 않음
- 실제 3D 엔진에서 많은 행렬은 회전과 이동만 담는 직교 행렬임
- PGA motor manifold는 Euclidean motion 전체를 더 낮은 계산·메모리 비용으로 표현하며, quaternion과 dual quaternion도 변환 없이 포함할 수 있음
PGA 데이터 표현과 기본 연산
- PGA algebra는 네 기저 벡터
e0~e3에서 생성됨e1,e2,e3는 각각x=0,y=0,z=0평면에 대응함- 특수한 degenerate vector
e0는 무한원 평면을 나타냄
- 셰이더에서는 GLSL 내장 타입을 사용해 연산자 오버로딩 없이 덧셈, 뺄셈, 스칼라 곱을 활용함
motor mat2x4line mat2x3point vec3direction vec3
- 일반 PGA motor 합성은 geometric product로 수행됨
- 4x4 행렬 곱: 64 곱셈, 48 덧셈
- 일반 motor 합성
gp_mm: 48 곱셈, 40 덧셈
- 특수한 변환 조합에서는 더 싼 연산이 가능함
gp_rr: 16 곱셈, 12 덧셈gp_tt: 0 곱셈, 3 덧셈gp_rt/gp_tr: 12 곱셈, 8 덧셈gp_rm/gp_mr: 32 곱셈, 24 덧셈gp_tm/gp_mt: 12 곱셈, 12 덧셈
점·방향 변환 최적화
- PGA에서 motor
M으로 점p를 변환할 때는 sandwich productM p M̃를 사용함 - 단순 전개는 33 곱셈, 29 덧셈으로, 행렬-벡터 곱의 16 곱셈, 12 덧셈보다 큼
- 정규화된 motor가
M M̃ = 1을 만족한다는 점을 이용해 식을 바꾸면 점 변환을 21 곱셈, 18 덧셈으로 줄일 수 있음 - 방향, 즉 무한원 점은 implied
e123계수가 0이므로 더 저렴함- 일반 방향 변환: 18 곱셈, 12 덧셈
- basis direction 변환은 예를 들어 x축 변환을 6 곱셈, 4 덧셈까지 낮출 수 있음
- 이 basis direction 최적화는 이후 tangent frame 처리에서 행렬이 항상 가장 빠르다는 통념을 흔드는 근거가 됨
정규화, 제곱근, 지수·로그 맵
- PGA motor의 squared pseudonorm은
M M̃ = a + b e0123형태의 Study Number임 - 정규화는 단순 벡터 정규화가 아니라, 결과 motor가 orthonormal transformation이 되도록 보장하는 절차임
- 일반 motor 정규화 구현 비용: 21 곱셈, 5 덧셈
- 순수 translation이나 rotation에서는 더 효율적인 버전을 사용할 수 있음
- 두 점·두 선·두 평면
a,b사이의 rigid transformation은M = sqrt(b / a)로 표현됨- 같은 종류의 두 원소에 대한 geometric product
ba는a에서b로 가는 변환의 두 배에 해당하는 motor를 만듦 sqrt M = normalize(1 + M)형태로 계산 가능함
- 같은 종류의 두 원소에 대한 geometric product
- PGA motor의 logarithm은 scaled line이고, scaled line은 exponentiation으로 회전 motor를 만들 수 있음
- 일반 4x4 행렬의 exponential map은 수치적으로 비싸지만, PGA motor manifold에서는 효율적인 closed form이 가능함
역원과 motor factorization
- Geometric Algebra는 정규화된 객체의 역원을 효율적으로 계산할 수 있음
- plane inverse: 자기 자신
- line inverse: 부호 반전
- point inverse: 부호 반전
- motor inverse: reversion
- 일반 bivector가 Plücker condition을 만족하지 않아 단일 line을 나타내지 않을 때는 Study Number inverse를 이용해 역원을 계산함
- 렌더링 구현에는 두 가지 factorization이 쓰임
- Euclidean factorization: motor를 origin 주변 rotation 뒤 translation으로 분해함
- Invariant factorization: motor를 서로 commuting하는 translation과 rotation으로 분해하며, 3D에서는 Mozzi-Chasles theorem으로 알려진 형태임
- tangent frame과 object-to-world motor를 합성할 때는 translation에 invariant한 frame 특성 때문에 Euclidean factorization이 유용함
glTF 행렬과 scale 처리
- 기존 glTF 콘텐츠와 상호 운용하려면 로드 시점에 행렬을 PGA motor로 변환해야 함
- 4x4 orthogonal matrix는 quaternion과의 동형성을 이용해 motor로 변환함
- import된 모든 matrix와 transformation은 load time에 변환됨
- PGA motor는 rigid body transformation을 다루므로 scaling을 포함하지 않음
- uniform scaling은 rotation과 translation에 invariant하므로 각 노드당 float 하나로 추적함
- 각 요소의 total scale은 자기 scale과 parent scale의 곱으로 계산함
- vertex에는 load time 또는 vertex shader 첫 단계에서 total scale을 적용함
- translation에는 parent scale을 load time과 animation update 시 적용함
- 약 400개의 무작위 glTF 파일 샘플에서 scale animation이 있는 경우는 0.5% 미만이었고, fixed uniform scale은 꽤 많았음
- non-uniform scaling은 rotation에 invariant하지 않아 더 까다로움
- 일반적인 non-uniform scale 처리는 4x4 matrix 대체 경로가 불가피함
- 샘플 glTF에서는 non-uniform scale이 leaf node에만 적용된 사례를 찾았고, 이 경우 animation key에 영향 없이 나머지 변환 전에 별도로 scale을 적용함
Model-View-Projection 대체
- 포워드 렌더러는 object space의 mesh geometry를 screen space로 변환하고, 각 triangle이 덮는 pixel을 결정함
- 일반적인 파이프라인의 model, view, projection matrix 중 model과 view를 PGA motor로 대체함
- vertex position은
sw_mp - normal과 tangent 방향은
sw_md
- vertex position은
- projection matrix는 일반적으로 non-zero entry가 5개뿐이므로, PGA로 억지로 바꾸지 않고 직접 projection expression을 사용함
- CPU 쪽 scene graph hierarchy update는 matrix composition 대신 motor composition을 쓰면서 계산량이 줄어듦
- GPU 쪽 vertex 변환은 단순 비교만 하면 motor가 불리해 보이지만, tangent frame 표현을 바꾸면 결과가 달라짐
tangent space normal mapping 최적화
- 일반 tangent space normal-mapped mesh의 vertex shader는 position, normal, tangent를 변환해야 함
- normal, tangent, bitangent는 orthonormal frame을 이루므로, PGA에서는 canonical basis frame에서 원하는 tangent frame으로 가는 tangentRotor로 표현할 수 있음
- 이 방식은 vertex descriptor를 줄임
- 기존: position 3 + normal 3 + tangent 4 + uv 2 = 12 floats
- PGA 방식: position 3 + tangentRotor 4 + uv 2 = 9 floats
- 정점당 float 수가 25% 감소함
- tangentRotor는 double cover를 가지며, scalar coefficient의 sign을 classical handedness flag와 맞춰 even/odd k-reflection을 구분함
- signed zero에 의존하며, vertex shader에서
sign(1/tangentRotor.x)로 handedness를 추출함
- signed zero에 의존하며, vertex shader에서
- position, normal, tangent를 4x4 matrix로 변환하면 총 48 곱셈, 36 덧셈이 필요함
- PGA 방식은 전체 tangent frame을 한 번에 변환한 뒤 normal과 tangent를 추출함
- tangent frame 합성: 16 곱셈, 12 덧셈
- normal/tangent 추출: 9 곱셈, 8 덧셈
- position 변환: 21 곱셈, 18 덧셈
- handedness 추출용 곱셈 1개
- 총 47 곱셈, 38 덧셈
- 정점 변환 비용은 행렬 방식과 거의 같고, transform 저장은 32 floats에서 8 floats로 줄어듦
fragment shader와 baked texture 제약
- 기존 콘텐츠를 로드하려면 fragment shader 단계에서는 다시 TBN matrix가 필요함
- baking tool은 high-detail mesh를 low-detail mesh에 굽는 과정에서 vertex normal과 tangent를 triangle face 위에서 보간하고, 각 fragment에서 orthogonal TBN matrix를 구성해 tangent space normal texture를 만듦
- basis vector 보간은 행렬 방식의 전형적인 오차를 만들고, 그 오차가 texture에 이미 baked되어 있음
- 그래서 이 구현은 tangentRotor에서 normal과 tangent vector를 명시적으로 추출함
- baking tool까지 제어할 수 있다면 tangentRotor를 fragment shader로 그대로 넘겨 정규화 후 sampled normal 변환에 사용할 수 있음
- TBN matrix를 만들 필요가 없음
- vertex shader의 normal/tangent 추출이 불필요함
- varying parameter 하나를 줄일 수 있음
- fragment shader의 expensive orthogonalization도 제거할 수 있음
motor skinning과 animation blending
- PGA motor는 dual quaternion과 동형이므로 skinning에 자연스럽게 적용됨
- inverse bind matrix를 motor로 변환한 뒤, dual quaternion skinning과 같은 패턴으로 bone motor를 blend함
- blend되는 transformation은 shortest arc를 따르도록 부호를 맞추고, 결과 transformation을 다시 정규화함
- animation blending도 같은 방식으로 CPU에서 PGA motor를 직접 blend한 뒤 정규화함
행렬 대체 실험의 결과
- glTF 호환 포워드 렌더러에서 PGA만으로 행렬을 대체하는 구현은 가능함
- 변환 비용이 더 비쌀 것이라는 예상은 tangent frame 표현과 sandwich product 최적화를 적용하면 단순하지 않음
- tangent space normal mapping의 일반적인 경우, PGA motor 방식은 vertex shader 비용을 행렬 방식과 거의 같게 유지하면서 vertex memory footprint를 크게 줄임
- 같은 storage에 약 33% 더 많은 vertices를 담을 수 있는 메모리 개선이 특히 큼
- 이 기법은 vertex shader 비용을 거의 늘리지 않고, 파이프라인 나머지 부분을 수정하지 않는 drop-in replacement로 기존 3D 엔진에 적용 가능함