Surfel: 공간이 아니라 표면에 빛을 저장한다면

빛이 필요한 표면에 조명 샘플을 붙이면 어떤 정보가 필요하고 어떤 문제가 남을까?

Series 빛을 어디에 저장할 것인가 — Real-Time GI와 Light Caching 4 / 7

3편의 probe는 공간의 한 위치에서 빛을 측정하고, 그 값을 주변 표면에 옮겨 적용했다. 이번에는 샘플을 실제 표면 위에 둬보자.

Surfel은 표면 요소(surface element), 즉 표면의 작은 영역을 대표하는 요소다. 조명 캐시로 사용하면 표면 위치와 방향에 대응하는 빛을 저장할 수 있다. 다만 surfel이라는 표현 자체가 GI 알고리즘을 뜻하는 것은 아니다. 빛을 계산하고 갱신하는 방법은 별도로 필요하다.

점 하나가 아니라 작은 표면 영역이다

같은 벽을 probe와 surfel로 표현하면 배치가 달라진다.

Spatial probes

       o               o
              o
-------------------------------- surface

Surface samples

----(o)--------(o)--------(o)----- surface

Surfel은 흔히 다음 세 가지 기하 정보(geometric attributes)로 설명한다.

$$ s_i=(P_i,n_i,r_i) $$
  • $P_i$: 대표 표면 위치
  • $n_i$: 그 표면의 단위 법선(unit normal)
  • $r_i$: 샘플이 대표하는 주변 영역의 크기

EA GIBS도 위치, 법선, 반지름으로 surfel을 정의한다. SIGGRAPH 2021 발표 PDF의 13쪽에서 이 정의를 확인할 수 있다.

위치 P, 반지름 r, 법선 N으로 정의되는 Surfel과 표면 샘플 분포

Surfel은 위치 P, 반지름 r, 법선 N으로 작은 표면 영역을 대표한다. 배경의 원판들은 이 샘플이 빈 공간보다 실제 표면을 따라 배치된다는 것을 보여준다.

                    normal n
                       ^
                       |
                <------o------>  radius r
                   tangent plane

-------------------- surface --------------------

평평한 벽에서는 작은 원판으로 근사하기 쉽다. 곡면에서는 반지름이 커질수록 실제 표면과 접평면(tangent plane) 사이의 차이가 커진다. 따라서 반지름은 보간 범위를 정하는 동시에 표면 근사의 해상도를 정한다.

원판은 대표 영역을 이해하기 위한 모델이다. 실제 구현이 반드시 원판 mesh를 생성해야 한다는 뜻은 아니다. 디버그 화면에서 원이나 스플랫(splat)으로 그려도 GPU의 데이터 구조에는 위치와 반지름 같은 값만 있을 수 있다.

조명(lighting) 데이터와 기하(geometry) 데이터를 함께 둔다

가장 단순한 diffuse 조명 캐시라면 surfel에 간접 복사조도(indirect irradiance) $E_i$를 추가한다.

// 개념을 설명하기 위한 구조이며 실제 엔진의 메모리 배치는 아니다.
struct LightingSurfel
{
    float3 position;
    float3 normal;
    float  radius;
    float3 indirectIrradiance;
};

이 샘플은 “이 위치에서 이 법선을 가진 표면이 받는 빛”을 대표한다. 법선이 고정되어 있으므로, 하나의 RGB irradiance만으로도 해당 확산 반사(diffuse reflection) 표면의 기본 조명을 나타낼 수 있다.

반면 공중의 probe는 여러 방향을 향한 표면에서 읽을 수 있도록 방향 정보를 유지하는 경우가 많다. 이 차이 때문에 surfel과 probe의 샘플 개수를 직접 비교하는 것만으로 메모리 효율을 판단할 수는 없다. 샘플당 데이터와 필요한 밀도가 다르다.

또 irradiance 하나로 모든 셰이딩(shading)을 처리할 수는 없다. 노멀 맵(normal map)이 만드는 법선 변화까지 정확하게 대응하려면 방향 정보나 추가 근사가 필요하고, 날카로운 정반사(specular reflection)는 다른 표현이 필요하다. 표면에 붙었다는 사실이 방향 정보의 손실을 되돌려주지는 않는다.

표면 커버리지(surface coverage): 표면이 얼마나 잘 덮였는가?

Surfel의 수보다 먼저 확인할 것은 표면 커버리지(surface coverage)다. 현재 표면점에 조명을 제공할 만한 샘플이 충분한지 보는 것이다.

충분한 coverage

--(-----o-----)(-----o-----)(-----o-----)--

부족한 coverage

--(--o--)------------gap------------(--o--)--

반지름이 너무 작고 샘플 간격이 넓으면 빈 영역이 생긴다. 반지름을 크게 하면 적은 샘플로 덮을 수 있지만, 서로 다른 조명을 평균하는 범위도 넓어진다. 기둥, 모서리, 좁은 틈에서는 단순히 원판이 겹치는 것만으로 충분하지 않다. 위치와 법선이 현재 표면에 맞아야 한다.

샘플을 촘촘하게 늘리는 비용도 있다. Ray로 각 샘플을 갱신하고, 조회할 때 주변 샘플을 찾아야 한다. 대표 영역의 크기와 조명 변화의 크기를 맞추는 것이 중요하다.

픽셀은 주변 surfel에서 빛을 재구성(reconstruction)한다

화면 픽셀이 가리키는 표면점을 $x$, 법선을 $n$이라고 하자. 가까운 surfel의 조명을 가중 평균(weighted average)하는 개념적 모델은 다음과 같다.

$$ \widetilde E(x,n)=\frac{\sum_i w_i(x,n)E_i}{\sum_i w_i(x,n)} $$

이것만 보면 probe 보간과 같다. 차이는 가중치(weight)에 쓸 기하 정보다. Surfel에는 이미 대표 표면의 법선과 반지름이 있다.

다음처럼 접평면 방향의 거리와 평면으로부터의 거리를 분리할 수 있다.

$$ \Delta_i=x-P_i,\qquad d_{\mathrm{plane},i}=|\Delta_i\cdot n_i|,\qquad d_{\mathrm{tangent},i}=\|\Delta_i-(\Delta_i\cdot n_i)n_i\| $$

설명용 필터는 이런 기준을 함께 고려할 수 있다.

  1. 접평면 방향의 거리가 대표 반지름에 비해 얼마나 큰가?
  2. 현재 위치가 surfel의 표면 평면에서 얼마나 떨어져 있는가?
  3. 현재 법선과 surfel 법선이 얼마나 비슷한가?
  4. 두 위치가 조명을 공유할 수 있는 가시성 관계인가?

가령 법선 항으로 $\max(0,n\cdot n_i)^k$를 사용할 수 있다. $k$를 높이면 다른 방향의 표면 값을 더 강하게 억제한다. 이는 원리를 설명하기 위한 예이며, 특정 엔진의 필터를 그대로 옮긴 식은 아니다. 유효한 가중치 합이 작으면 그에 맞는 fallback도 필요하다.

표면에 붙여도 빛 누출(light leaking)은 남는다

서로 반대 방향을 향한 벽 양쪽은 법선으로 구분하기 쉽다. 하지만 법선만으로 모든 표면을 구분할 수는 없다.

top view: two parallel walls

wall A     o --> normal
               |
               | small gap
               |
wall B     x --> normal

위치가 가깝고 법선도 비슷하지만 서로 다른 표면이다.

반지름이 큰 surfel이 틈이나 가림 구조를 넘어 영향을 주면 여전히 빛이 샐 수 있다. Coverage는 “이 위치를 덮는 샘플이 있는가”를 묻고, visibility는 “그 샘플의 조명을 이 위치에 적용해도 되는가”를 묻는다. 둘은 별개다.

실제 GIBS 발표도 surfel의 light bleeding과 이를 줄이는 깊이 정보를 다룬다. 따라서 surfel의 장점은 표면 정보를 활용해 적절한 공유 관계를 만들기 좋다는 것이지, 표현만 바꾸면 누출이 사라진다는 보장은 아니다. 이 구현의 구체적인 처리는 다음 편에서 살펴본다.

Lightmap과는 어떤 관계일까?

Surfel과 lightmap은 둘 다 표면의 조명을 저장할 수 있다. 가장 큰 차이는 표면에 주소를 붙이는 방식이다.

Lightmap texel Lighting surfel
표면과의 대응 UV mapping 위치·법선·대표 반지름
조회 방식 텍스처 샘플링 주변 표면 샘플 검색과 필터
해상도 조절 Texel density와 atlas 샘플 밀도와 반지름
대표적인 관리 과제 UV chart, seam, padding Coverage, 샘플 추적, 재활용

UV가 이미 잘 마련된 정적 환경에서는 lightmap의 직접적인 주소 지정이 유용하다. 실행 중 표면에 샘플을 생성하려면 UV와 독립적인 surfel 표현이 유용할 수 있다. 어느 쪽이든 동적으로 조명을 계산하고 갱신하는 시스템은 따로 필요하다.

Surfel은 표현이고, GI는 그 위에서 동작하는 시스템이다

이제 표면에 작은 조명 저장소를 놓는 발상은 이해했다. 아직 답하지 않은 질문들이 있다. 샘플을 어디서 생성할까? 표면이 움직이면 무엇을 따라갈까? 새 샘플의 빛은 어떻게 구할까? 메모리가 가득 차면 무엇을 지울까?

이 질문에 대한 구체적인 답 중 하나가 EA의 GIBS다. 다음 글 「Surfel GI는 어떻게 동작하는가 — EA GIBS 뜯어보기」에서는 G-buffer에서 surfel을 생성하고 ray tracing으로 조명을 갱신하는 흐름을 따라간다.


References