표면하 산란
고친 사람 github-actions[bot]
표면하 산란은 물체 속으로 스며든 빛이 안에서 흩어지다가 다른 곳으로 빠져나오는 일입니다. 사람 피부가 은은하게 밝아 보이는 까닭이 이 빛입니다. 그래픽스에서 이 빛을 빼고 그리면 피부가 플라스틱처럼 딱딱해 보입니다. 계산이 많아서 게임 화면에서는 대개 어림으로 대신합니다.
쉽고 빠른 이해
표면하 산란은 빛이 물체 속을 한 바퀴 돌아 나오는 일입니다. 손전등을 손가락 끝에 대고 켜면 손가락이 붉게 비치는 것이 그 모습입니다.
이 빛을 빼면 빛이 닿은 곳만 밝습니다. 그림자 경계도 칼로 자른 듯 날카롭습니다. 사람 얼굴이 석고상이나 플라스틱 인형처럼 보입니다.
어떻게 도는가:
- 빛이 표면에 닿으면 일부는 겉에서 튕기고 나머지는 속으로 들어갑니다
- 속으로 든 빛은 작은 알갱이에 부딪힐 때마다 방향이 바뀝니다. 그 사이 일부는 먹힙니다
- 남은 빛이 들어온 곳 주변의 다른 곳에서 빠져나옵니다
- 피부에서는 빨간빛이 가장 멀리 갑니다. 그림자 경계와 얇은 곳에 붉은 기가 돕니다
대가는 계산량입니다. 한 점의 밝기를 정하려면 그 주변으로 들어온 빛까지 모아야 합니다. 게임은 이미 그린 화면을 살짝 번지게 해서 비슷한 모습을 냅니다.
상세
어두운 방에서 손전등을 손가락 끝에 대고 켜 보면 손가락 전체가 붉게 빛납니다. 손끝으로 들어간 빛이 살 속에서 퍼지다가 옆과 뒤로 새어 나온 것입니다. 햇빛을 등지고 선 사람의 귀가 발갛게 비쳐 보이는 것도 같은 일입니다.
컴퓨터로 장면을 그림으로 만드는 일이 렌더링입니다. 렌더링은 화면의 점마다 무슨 색으로 얼마나 밝게 칠할지 정합니다.
표면하 산란은 물체 속을 돌아 나오는 빛 자체를 가리킵니다. 렌더링에서는 이 빛을 밝기 계산에 넣는 일도 같은 이름으로 부릅니다. 이 절은 빛이 속에서 어떻게 움직이는지, 그 움직임이 왜 계산을 어렵게 만드는지, 어떻게 어림하는지를 차례로 봅니다.
겉에서 튕기는 빛과 속으로 드는 빛
빛이 물체 표면에 닿으면 둘로 갈립니다. 한 몫은 겉에서 곧장 튕겨 나갑니다. 젖은 피부나 니스 칠한 나무에 맺히는 반짝이는 점이 이 빛입니다. 이렇게 겉에서 거울처럼 튕기는 반사가 정반사입니다.
나머지 몫은 표면을 뚫고 속으로 들어갑니다. 속에는 피부 세포나 우유의 지방 방울 같은 작은 알갱이가 가득합니다.
빛이 이런 알갱이에 부딪혀 방향을 바꾸는 일이 산란입니다. 속으로 든 빛은 여러 번 산란하며 이리저리 떠돕니다. 한 번 부딪힐 때마다 가는 방향이 새로 정해집니다.
떠도는 동안 빛의 일부는 물질에 먹혀 사라집니다. 이 일이 흡수입니다. 먹힌 빛은 다시 나오지 않으니 밝기에 보태지지 않습니다.
먹히지 않고 남은 빛은 결국 표면 밖으로 다시 나옵니다. 나오는 곳은 들어온 곳이 아니라 그 주변의 다른 곳입니다. 표면 아래에서 산란한다고 해서 표면하 산란이라는 이름이 붙었습니다.
이제부터 빛이 들어온 곳을 점 A, 빛이 나오는 곳을 점 B 라고 부르겠습니다. 아래 그림은 점 A에 닿은 빛이 어디로 가는지를 보여 줍니다.
flowchart TD
L["빛"] --> A["표면의 점 A에 닿는다"]
A -->|겉에서 튕김| E1["눈 · 반짝이는 점"]
A -->|속으로 들어감| S["속에서 여러 번 산란"]
S -->|일부| X["흡수되어 사라짐"]
S -->|나머지| B["점 A 주변의 점 B에서 나온다"]
B --> E2["눈 · 은은한 밝기"]
점 A에서 길이 둘로 갈립니다. 겉에서 튕긴 빛은 점 A에서 바로 눈으로 옵니다. 속으로 든 빛은 점 B까지 돌아서 옵니다. 눈에는 점 B가 스스로 은은하게 빛나는 것처럼 보입니다.
들어온 점과 나가는 점이 다르다
보통의 렌더링은 빛이 들어온 점에서 곧바로 나간다고 칩니다. 한 점의 밝기를 그 점에 들어온 빛만 보고 정합니다. 이 가정 덕분에 점마다 따로 계산할 수 있습니다.
이 가정을 함수로 적은 것이 BRDF(Bidirectional Reflectance Distribution Function, 양방향 반사 분포 함수)입니다. 빛이 들어온 방향과 나가는 방향을 넣으면 그중 얼마가 되튕기는지 알려 줍니다. 재질마다 이 함수의 모양이 다릅니다.
표면하 산란은 이 가정을 깹니다. 점 B의 밝기가 점 A로 들어온 빛에 달려 있습니다. 점 A 하나만이 아닙니다. 주변의 수많은 점에서 들어온 빛이 점 B로 모입니다.
이 경우까지 담으려고 함수에 입력을 둘 더한 것이 BSSRDF(Bidirectional Scattering-Surface Reflectance Distribution Function, 양방향 산란 표면 반사 분포 함수)입니다. 방향 둘에 더해 들어온 점과 나가는 점을 받습니다. 두 함수를 견주면 이렇습니다.
| BRDF | BSSRDF | |
|---|---|---|
| 받는 것 | 들어온 방향 · 나가는 방향 | 들어온 방향 · 나가는 방향 · 들어온 점 · 나가는 점 |
| 빛이 나오는 점 | 들어온 점과 같다 | 주변의 다른 점 |
| 한 점을 정할 때 보는 범위 | 그 점 하나 | 주변 영역 |
| 계산량 | 적다 | 많다 |
계산이 많아지는 까닭은 셋째 줄에 있습니다. 한 점마다 주변 영역을 훑어 들어온 빛을 모아야 합니다. 화면의 점은 수백만 개라서 점마다 주변을 다 훑기는 벅찹니다.
난반사와 갈리는 기준
종이나 무광 페인트는 빛을 사방으로 고르게 흩뿌립니다. 이런 반사가 난반사입니다. 난반사도 속으로 든 빛이 산란해 나오는 일입니다. 들어온 점에서 아주 가까운 곳으로 나온다는 점만 다릅니다.
빛이 들어온 점에서 나가는 점까지의 거리를 퍼지는 거리라고 부릅니다. 난반사는 퍼지는 거리가 아주 짧습니다. 표면하 산란은 그보다 깁니다.
화면의 한 점은 물체 겉의 작은 넓이 하나를 덮습니다. 빛이 그 넓이 안에서 들어갔다 나오면 눈에는 한 점 안에서 끝난 일로 보입니다.
그래서 빛이 그 넓이 안에서 다시 나올 만큼 퍼지는 거리가 짧으면 들어온 점에서 나왔다고 쳐도 그림이 같습니다. 이때는 BRDF 로 충분합니다. 그 거리가 눈에 띌 만큼 길 때 표면하 산란을 따로 계산합니다.
빛이 퍼지는 거리와 색
빛이 속에서 얼마나 멀리 퍼지는지는 재질이 정합니다. 알갱이가 성기고 흡수가 적을수록 멀리 갑니다. 흔한 재질을 퍼지는 거리로 나누면 이렇습니다.
| 재질 | 속으로 든 빛 | 보이는 모습 |
|---|---|---|
| 금속 | 표면 바로 아래에서 거의 다 먹힌다 | 표면하 산란이 없다고 본다 |
| 무광 페인트 · 종이 | 아주 가까운 곳에서 나온다 | 난반사로 다룬다 |
| 피부 · 대리석 · 밀랍 · 우유 · 나뭇잎 | 눈에 띄는 거리만큼 퍼진다 | 속까지 은은하게 밝고 얇은 곳이 비친다 |
빛에는 여러 색이 섞여 있습니다. 색마다 먹히는 정도가 다릅니다. 피부 속의 피는 파란빛과 초록빛을 많이 먹습니다. 빨간빛은 덜 먹습니다. 피부 속에서는 빨간빛이 가장 멀리 퍼집니다.
이 차이가 피부에 붉은 기를 남깁니다. 그림자 경계 바로 바깥이 살짝 붉어집니다. 손가락이나 귀처럼 얇은 곳은 뒤에서 오는 빛에 붉게 비칩니다.
계산을 어림하는 방법
BSSRDF 를 그대로 풀면 계산이 너무 많습니다. 그래서 어림하는 방법이 여럿 나왔습니다. 이 소절은 대표 방법의 이름과 하는 일, 포기하는 것을 짚습니다.
먼저 알아 둘 낱말이 광선입니다. 광선은 한 점에서 한 방향으로 곧게 그은 선입니다. 빛이 가는 길을 이 선으로 흉내 냅니다.
패스 트레이싱은 광선을 무작위 방향으로 튕기며 빛의 길을 따라가 밝기를 어림하는 방식입니다. 많이 따라갈수록 그림이 매끈해집니다. 대신 시간이 듭니다.
| 방법 | 하는 일 | 포기하는 것 |
|---|---|---|
| 패스 트레이싱 | 광선을 물체 속까지 들여보내 속에서 산란하는 길을 무작위로 골라 따라간다 | 시간. 산란이 잦은 재질일수록 길이 길어진다 |
| 확산 근사 | 여러 번 산란한 빛은 사방으로 고르게 퍼진다고 본다. 퍼지는 거리만으로 나오는 빛의 양을 정한다 | 얇은 곳과 모서리. 두께가 퍼지는 거리보다 얇으면 어긋난다 |
| 화면 공간 표면하 산란 | 이미 그린 화면에서 피부 부분의 밝기를 주변으로 번지게 한다. 빨강은 더 넓게 번지게 한다 | 두께. 뒤에서 비치는 빛은 따로 어림해야 한다 |
| 두께 맵 | 미리 계산한 두께를 그림 파일에 담아 둔다. 얇은 곳일수록 뒤쪽 빛을 더 비쳐 보이게 한다 | 움직임. 모양이 바뀌면 다시 계산해야 한다 |
| 랩 라이팅 | 빛이 닿는 범위를 그림자 쪽으로 조금 넘겨 칠해 경계를 무르게 한다 | 빛의 길. 겉모습만 흉내 낸다 |
셋째 줄 화면 공간 방식이 하는 일을 숫자 넷으로 줄여 보겠습니다. 그림자 경계를 가로지르는 점 넷이 있습니다. 밝기는 어둠에서 밝음으로 뚝 끊깁니다. 점마다 양옆과 자기를 더해 셋으로 나누면 이렇게 됩니다.
light = [0, 0, 1, 1] # 칼 같은 경계
def blur(xs, i): # 이웃 셋 평균
left = xs[max(i - 1, 0)]
right = xs[min(i + 1, len(xs) - 1)]
return (left + xs[i] + right) / 3
blur(light, 0) # 0.0
blur(light, 1) # 0.333…
blur(light, 2) # 0.666…
blur(light, 3) # 1.0
0 과 1 사이에 중간값 둘이 생겼습니다. 빛이 경계 너머로 조금 번져 나간 모습입니다. 빨강만 이웃을 더 넓게 잡아 번지게 하면 경계에 붉은 기가 돕니다.
방법을 고르는 기준은 한 장에 쓸 수 있는 시간입니다. 화면 한 장, 곧 프레임 하나에 몇 분을 써도 되는 오프라인 렌더링은 패스 트레이싱이나 확산 근사를 씁니다. 영화가 이쪽입니다.
1초에 프레임 수십 장을 그려야 하는 실시간 렌더링은 그럴 시간이 없습니다. 게임은 화면 공간 방식과 두께 맵, 랩 라이팅을 섞어 씁니다.
쓸 때와 안 쓸 때
표면하 산란을 계산하면 그만큼 시간이 듭니다. 빛이 퍼지는 거리가 눈에 띄는 재질에만 켭니다.
사람 얼굴은 거의 늘 켭니다. 피부가 조금만 딱딱해 보여도 얼굴은 금세 어색해 보입니다. 밀랍 초나 대리석 조각, 우유처럼 속이 비치는 물체도 켭니다.
카메라에서 멀리 있는 물체는 끄는 경우가 많습니다. 멀어지면 화면의 한 점이 덮는 넓이가 커집니다. 퍼지는 거리가 그 넓이 안에 들어갑니다. 그때는 난반사로 그려도 차이가 안 보입니다.
금속처럼 빛이 속으로 거의 안 드는 재질은 켜지 않습니다. 켜도 바뀌는 것 없이 계산만 늘어납니다.
관련 항목
표면하 산란을 이루는 빛의 움직임
산란 · 흡수 · 굴절 · 정반사 · 난반사 · 반투명 · 참여 매질
표면하 산란을 적는 함수와 식
BRDF · BSSRDF · BTDF · BSDF · 렌더링 방정식 · 복사 전달 방정식
표면하 산란을 계산하는 방법
패스 트레이싱 · 몬테카를로 방법 · 확산 근사 · 쌍극자 모델 · 화면 공간 표면하 산란 · 텍스처 공간 확산 · 두께 맵 · 랩 라이팅
표면하 산란이 속하는 상위 분류
전역 조명 · 물리 기반 셰이딩 · 셰이딩 · 렌더링 · 그래픽스
표면하 산란이 쓰이는 렌더링 방식
실시간 렌더링 · 오프라인 렌더링 · 레이 트레이싱 · 래스터화 · 디노이징
다른 이름: subsurface scattering · SSS · 서브서피스 스캐터링 · 피하 산란