텍셀 해상도가 달라져도 같은 속도로 흐르게 하려면

DistanceWeight의 상대 거리 보정과 실제 이동 속도를 구분하고, 전달량과 해상도 사이의 관계를 살펴본다.

표면 시뮬레이션(surface simulation)에서 공간 해상도(spatial resolution)를 높이면 더 작은 텍셀(texel)로 같은 표면을 표현하게 된다.

이때 기대하는 변화는 보통 계산의 정밀도다.
같은 재질과 같은 표면 조건이라면 해상도를 바꿔도 물질이 흐르는 실제 속도는 비슷하게 유지되기를 기대한다.

하지만 이웃 텍셀 사이의 전달량을 계산하는 방식에 따라, 해상도를 높였는데 오히려 흐름이 느려질 수 있다.

이미 전달 계산에 거리를 반영하고 있더라도 이 문제가 남을 수 있다.

여기서는 거리를 고려하는 것과 해상도에 맞춰 실제 이동을 보정하는 것이 어떻게 다른지 살펴본다.

시간에 따라 오른쪽으로 이동하는 일차원 물질 분포와 특성선

일정한 속도의 이류(advection)에서는 분포가 시간에 따라 같은 실제 거리만큼 이동한다. 검은 특성선의 기울기는 이동 속도를 나타내며, 격자 해상도와 별개로 유지하려는 물리적 기준이 된다.


DistanceWeight는 무엇을 보정하고 있는가?

현재 Solver의 DistanceWeight는 다음과 같은 형태다.

$$ W_{ij}^{\mathrm{distance}} = \operatorname{clamp} \left( \frac{d_{\mathrm{ref}}(i,j)}{d(i,j)}, 0,1 \right) $$

각 항은 다음과 같이 생각할 수 있다.

  • $d(i,j)$: 두 이웃 텍셀 사이의 실제 거리
  • $d_{\mathrm{ref}}(i,j)$: 양쪽 텍셀의 평균 이웃 간격을 이용한 기준 거리
  • $W_{ij}^{\mathrm{distance}}$: 전달량에 곱하는 거리 가중치(distance weight)

예를 들어 주변의 평균 간격이 1cm인데, 특정 이웃이 2cm 떨어져 있다고 하자.

$$ W^{\mathrm{distance}} = \frac{1}{2} = 0.5 $$

이 이웃에게는 전달량을 줄인다.

즉, 이 식은 다음과 같은 규칙을 표현한다.

주변의 일반적인 이웃보다 멀리 연결된 이웃에게는 덜 보낸다.

절대 거리만 사용하는 대신 주변 간격과의 비율을 사용하므로, 모델의 전체 크기나 텍셀 간격이 함께 변해도 가중치를 비슷하게 유지할 수 있다.


해상도를 높이면 이 가중치는 어떻게 되는가?

해상도를 높여 텍셀 간격이 절반이 되었다고 하자.

주변 평균 간격과 특정 이웃까지의 거리가 모두 절반이 된다면,

$$ d_{\mathrm{ref}}' = \frac{d_{\mathrm{ref}}}{2}, \qquad d' = \frac{d}{2} $$

이다.

그러면 새로운 거리 가중치는 다음과 같다.

$$ W' = \operatorname{clamp} \left( \frac{d_{\mathrm{ref}}/2}{d/2}, 0,1 \right) = \operatorname{clamp} \left( \frac{d_{\mathrm{ref}}}{d}, 0,1 \right) = W $$

가중치가 그대로 유지된다.

이것은 현재 DistanceWeight의 의도에 맞는 동작이다.
이웃의 상대적인 거리 관계가 바뀌지 않았기 때문이다.

하지만 이것만으로 실제 이동 속도가 유지되는 것은 아니다.

이웃 사이의 상대적인 거리 관계가 같다는 것과, 같은 시간에 같은 실제 거리를 이동한다는 것은 다른 조건이다.


한 시간 단계(time step)에서 한 텍셀까지 보낸다는 것은 무엇인가?

현재의 인접 전달 방식(neighbor transfer)에서는 새로 받은 양을 같은 step 안에서 다시 다음 이웃으로 보내지 않는다.

새로운 유입은 다음 step부터 전달된다.

여기서 주의할 점은 다음 두 문장이 서로 다르다는 것이다.

  • 한 step에서 이웃 한 칸까지 보낼 수 있다.
  • 한 step마다 보유량 전체가 한 칸 이동한다.

한 칸으로 보낼 수 있어도, 실제로 얼마를 보내는지는 전달량에 따라 달라진다.

이를 보기 위해 동일한 크기의 칸들이 한 방향으로 연결된 단순한 경우를 생각해보자.

  • $m$: 현재 보유량
  • $Q$: 한 step에서 이웃에게 보내는 양
  • $r$: 보내는 비율
  • $h$: 이웃 칸 사이의 간격
  • $\Delta t$: 한 시간 단계(time step)의 시간 간격

보내는 비율은 다음과 같다.

$$ r=\frac{Q}{m} $$

보유량의 $r$만큼이 거리 $h$만큼 이동하므로, 전체 양의 중심은 다음 거리만큼 이동한다.

$$ \Delta x_{\mathrm{center}}=rh $$

따라서 평균 이동 속도는 다음과 같다.

$$ v_{\mathrm{avg}} = \frac{rh}{\Delta t} = \frac{Q}{m}\frac{h}{\Delta t} $$

여기서 말하는 속도는 양의 중심이 움직이는 평균 속도다.
아주 작은 값이 처음 도달하는 위치나, 화면에서 무늬의 가장자리가 움직이는 속도와는 구분해야 한다.


같은 비율을 보내면 같은 속도로 이동하는가?

0.1초마다 보유량의 20%를 이웃에게 보낸다고 하자.

텍셀 간격이 1cm라면 평균 속도는 다음과 같다.

$$ v_{\mathrm{avg}} = \frac{0.2\times1}{0.1} = 2\ \mathrm{cm/s} $$

이번에는 해상도를 높여 텍셀 간격이 0.5cm가 되었다고 하자.

같은 비율을 보내면,

$$ v_{\mathrm{avg}}' = \frac{0.2\times0.5}{0.1} = 1\ \mathrm{cm/s} $$

이다.

보내는 비율은 같지만 실제 이동 속도는 절반이 되었다.

텍셀 간격 0.1초마다 보내는 비율 평균 이동 속도
1cm 20% 2cm/s
0.5cm 20% 1cm/s
0.5cm 40% 2cm/s

따라서 같은 실제 속도를 유지하려면, 텍셀 간격이 줄어든 만큼 보내는 비율을 높여야 한다.

이 표는 관계를 설명하기 위한 단순한 예시다.
현재 엔진의 전체 Transport가 정확히 이 비율로 동작한다는 실험 결과는 아니다.


목표 속도로부터 전달량을 계산하기

앞에서는 보내는 비율을 알고 평균 속도를 구했다.

$$ v=\frac{rh}{\Delta t} $$

이번에는 원하는 속도 $v_*$가 주어졌다고 하자.

이 속도를 만들기 위해 필요한 비율은 다음과 같다.

$$ r=\frac{v_*\Delta t}{h} $$

그리고 전달량은 다음과 같다.

$$ Q=mr = m\frac{v_*\Delta t}{h} $$

두 식은 서로 다른 현상을 설명하는 것이 아니다.
같은 관계에서 무엇을 입력으로 두고 무엇을 계산할지 바꾼 것이다.

  • 전달량을 알고 실제 이동 속도를 구할 수 있다.
  • 목표 이동 속도를 알고 필요한 전달량을 구할 수 있다.

물질의 이동에서 흐름과 속도가 연결되는 기본 관계는 Clawpack의 보존형 이동 설명에서도 확인할 수 있다.

이 관점에서 목표 속도는 새로운 저장 변수일 필요가 없다.
재질 파라미터(material parameter)와 표면 조건으로부터 계산하는 중간값일 수도 있다.

조금 더 추상적으로 표현하면 다음과 같다.

$$ \text{목표 속도} = f(\text{재질 파라미터},\text{표면 조건}) $$
$$ \text{전달량} = g(\text{목표 속도},\text{현재 상태},\text{텍셀 간격},\Delta t) $$

해상도가 바뀌면 전달량 계산은 달라지지만, 같은 조건에서 목표로 하는 실제 이동 속도는 유지하는 구조다.


기존 전달량을 보정 기준으로 사용할 수 있는가?

목표 속도를 반드시 처음부터 별도의 숫자로 지정해야 하는 것은 아니다.

특정 기준 해상도에서 원하는 흐름이 나왔다면, 그 결과를 보정 기준으로 삼을 수도 있다.

다만 두 경우를 구분해야 한다.

1. 같은 조건에서 환산했다가 되돌리는 경우

기존 전달량 $Q$를 속도로 환산하면,

$$ v=\frac{Q}{m}\frac{h}{\Delta t} $$

이다.

이 속도를 같은 간격과 시간으로 다시 전달량에 넣으면,

$$ Q' = m\frac{v\Delta t}{h} = m \frac{ \left( \frac{Q}{m}\frac{h}{\Delta t} \right) \Delta t }{h} = Q $$

원래 전달량으로 돌아온다.

같은 값을 다른 단위로 표현했다가 되돌렸기 때문에 보정이 일어나지 않는다.

2. 기준 해상도의 결과를 다른 해상도에 적용하는 경우

기준 간격 $h_{\mathrm{ref}}$에서 전달 비율이 $r_{\mathrm{ref}}$였다고 하자.

같은 시간 간격에서 평균 속도를 유지하려면,

$$ r_{\mathrm{ref}}h_{\mathrm{ref}} = r_{\mathrm{new}}h_{\mathrm{new}} $$

이어야 한다.

따라서,

$$ r_{\mathrm{new}} = r_{\mathrm{ref}} \frac{h_{\mathrm{ref}}}{h_{\mathrm{new}}} $$

이다.

기준 텍셀 간격이 1cm이고 전달 비율이 20%였다면, 새 간격이 0.5cm일 때 필요한 비율은 40%다.

이 경우에는 해상도를 바꿔 적용했으므로 값이 달라진다.

시간 간격도 바뀐다면 다음과 같이 쓸 수 있다.

$$ r_{\mathrm{new}} = r_{\mathrm{ref}} \frac{h_{\mathrm{ref}}}{h_{\mathrm{new}}} \frac{\Delta t_{\mathrm{new}}}{\Delta t_{\mathrm{ref}}} $$

중요한 것은 기준을 유지하는 것이다.

해상도를 바꿀 때마다 기존 계산 결과에서 새로운 목표 속도를 정하면, 원래의 해상도 의존성이 기준 속도에도 그대로 들어갈 수 있다.


두 Transport Factor를 바꿔야 하는가?

현재 SRProfile에는 다음 두 파라미터가 있다.

"saturationTransferFactor": 0.2,
"geometryTransferFactor": 0.5

두 Factor는 서로 다른 이동 원인을 조절한다.

  • saturationTransferFactor: 포화도(saturation) 차이에 따른 전달
  • geometryTransferFactor: 높이(height)와 중력(gravity) 방향에 따른 전달

현재도 이 두 성분은 합쳐져 하나의 Transport 전달량을 만든다.

$$ Q_{ij} = \left( D_{ij}^{\mathrm{saturation}}k_i^{\mathrm{saturation}} + D_{ij}^{\mathrm{geometry}}k_i^{\mathrm{geometry}} \right) W_{ij}\Delta t $$

여기서 $k$는 Factor에 기준 Rate를 곱한 값이고, $W$는 TransferWeight다.
이 식의 $Q$는 source의 유출 제한을 적용하기 전 RawFlux에 해당한다.

해상도 보정을 검토한다고 해서 두 Factor를 없애거나, 두 성분을 별도 패스(pass)로 계산해야 하는 것은 아니다.

Factor는 재질의 전달 성향을 표현하는 입력으로 계속 사용할 수 있다.

다만 그 Factor가 어떤 단위의 기준값에 곱해지고, 어떤 공간 수식으로 전달량이 되는지는 다시 검토해야 한다.

예를 들어 중력에 따른 이동을 목표 속도로 표현할 수 있다. 포화도 차이에 따른 퍼짐을 확산 모델(diffusion model)로 표현하는 방법도 검토할 수 있다.

하지만 이는 새로운 모델의 선택이다.
현재 수식이 이미 그 모델을 구현하고 있다는 뜻도 아니고, 두 성분 모두에 같은 거리 보정을 곱하면 된다는 뜻도 아니다.

특히 현재 GeometryDrive에는 절대 높이차가 들어 있다. 여기에 거리의 역수를 추가하면 높이차의 거리 비례를 상쇄할 수는 있지만, 그것만으로 전체 이동 속도가 일정해지는 것은 아니다.


보내는 비율이 100%를 넘으면 어떻게 되는가?

단순한 한 방향 전달에서 보내는 비율은 다음과 같다.

$$ r=\frac{v_*\Delta t}{h} $$

목표 속도가 크거나, 시간 간격이 길거나, 텍셀 간격이 작으면 $r$이 1보다 커질 수 있다.

이는 현재 보유량보다 많은 양을 한 번에 보내려 한다는 뜻이다.

현재의 source 유출 제한으로 없는 양을 보내는 것은 막을 수 있다.
하지만 전달량을 줄여버리면 의도한 이동 속도까지 유지되는 것은 아니다.

이 경우에는 진행할 시간을 작은 시간 단계로 나누는 방법(substepping)을 사용할 수 있다.

$$ \Delta t = \Delta t_1+\Delta t_2+\cdots+\Delta t_n $$

각 구간마다 상태를 갱신하고, 받은 양을 다음 작은 step에서 다시 전달한다.

단순한 한 방향 예시에서는 각 step이

$$ \frac{v_*\Delta t_{\mathrm{sub}}}{h}\leq1 $$

을 만족하도록 시간을 나눌 수 있다.

한 작은 step이 정확히 한 텍셀을 이동해야 한다는 뜻은 아니다.
0.2칸이나 0.5칸에 해당하는 전달을 여러 번 계산할 수도 있다.

실제 여러 이웃으로 보내는 Solver에서는 개별 간선뿐 아니라 전체 유출과 다른 전달 성분도 함께 고려해야 한다.

또한 작은 step의 수가 늘어나면 계산 비용도 증가한다.


월드 면적(world-space area)이 다른 텍셀에서도 같은 계산을 사용할 수 있는가?

앞의 예시는 동일한 크기의 칸에서 한 방향으로 전달하는 경우였다.

실제 Surface에서는 UV 배치(UV mapping)와 인스턴스 스케일(instance scale)에 따라 텍셀의 월드 공간 면적(world-space area)이 달라질 수 있다.

이때 State가 무엇을 저장하는지도 중요하다.

  • 텍셀에 들어 있는 총량
  • 텍셀의 면적당 양

두 표현은 다음 관계로 연결된다.

$$ m_i=A_i s_i $$
  • $m_i$: 텍셀의 총량
  • $A_i$: 텍셀의 면적
  • $s_i$: 면적당 양

면적당 값을 저장한다면, 전달된 총량을 자기 면적으로 나누어 상태를 갱신해야 한다.

따라서 총량 보존(conservation)을 확인할 때도 단순히 State를 더하는 것이 아니라,

$$ M=\sum_i A_i s_i $$

를 확인해야 한다.

총량 저장과 면적당 값 저장 중 어느 하나만 물리적으로 올바른 것은 아니다.
저장 표현과 전달량, Capacity, 입력의 단위가 서로 일치해야 한다.

현재 Solver의 거리 가중치와 렌더링용 면적 히트맵(heatmap)만으로 이 면적 장부가 이미 구현되어 있다고 볼 수는 없다.


다음에 확인할 것

해상도 보정의 목표는 128, 256, 512에서 모든 텍셀 값이 완전히 같아지는 것이 아니다.

같은 표면과 같은 월드 공간 초기조건(world-space initial condition)에서, 같은 시뮬레이션 시간 후 실제 이동 거리와 보존량이 비슷해지는지를 확인하는 것이다.

먼저 일정한 경사의 단순한 표면에서 다음 항목을 비교할 수 있다.

  • 해상도별 양의 중심 이동 거리
  • 같은 총 시간을 큰 step 한 번과 작은 step 여러 번으로 계산한 차이
  • source 유출 제한이 적용되는 빈도
  • State 합과 면적을 반영한 총량
  • 작은 step을 늘렸을 때의 GPU 비용

현재 논의는 이 실험을 위한 설계 검토다.

DistanceWeight가 이미 거리를 사용한다는 사실만으로 해상도 문제가 해결되었다고 판단할 수는 없다. 어떤 거리를 어떤 목적으로 반영하는지, 그 결과 같은 시간에 얼마만큼의 실제 이동을 만드는지를 함께 확인해야 한다.


참고 자료

  • David I. Ketcheson, Randall J. LeVeque, Mauricio J. del Razo, Advection, Riemann Problems and Jupyter Solutions. 일정한 속도로 이동하는 분포와 특성선 도식.