그늘이 완전히 검지 않은 이유
방 안에서 스탠드를 켜고 책상 아래를 보면 어둡긴 해도 아무것도 안 보이지는 않습니다. 빛이 벽에 튀고 천장에 튀고 바닥에 튀어서 사방으로 퍼지기 때문입니다.
직접 쏜 빛만 계산하면 이게 재현되지 않습니다. 빛을 등진 면이 값 그대로 0이 되어 완전한 검은색이 됩니다.
제대로 하려면 비쌉니다
튀는 빛을 진짜로 계산하려면 광선이 표면에 맞을 때마다 거기서 다시 사방으로 광선을 쏘고, 그게 또 맞은 자리에서 다시 쏘는 식으로 따라가야 합니다. 한 픽셀의 색을 정하려고 장면 전체를 여러 번 훑는 셈입니다.
실시간으로 할 수 있는 계산이 아니었습니다. 그래서 나온 타협이 “어디든 최소 이만큼은 밝다” 는 상수를 하나 깔아 두는 것입니다.
계산이랄 게 없습니다
float3 ambient = ambientColor * albedo;
환경광 색에 재질 색을 곱해서 그냥 더합니다. 법선도 안 쓰고 시선도 안 쓰고 광원 위치도 안 씁니다. 표면이 어느 쪽을 보든, 카메라가 어디에 있든, 광원이 어디 있든 같은 값입니다.
조명 계산에서 가장 싼 항이고, 그래서 가장 먼저 생겼습니다.
꺼 보면 압니다
아래 구에서 Ambient 버튼을 눌러 껐다 켜 보세요.
꺼 두면 빛을 등진 쪽이 배경과 구분이 안 됩니다. 구가 아니라 초승달처럼 보입니다. 형태가 사라지는 것이 진짜 문제입니다. 어두운 것과 없는 것이 화면에서 같은 색이 되어 버립니다.
켜면 등진 쪽에도 바닥이 깔리면서 윤곽이 돌아옵니다. 오른쪽 막대에서 Ambient 칸은 빛이 아무리 돌아도 폭이 안 변합니다. 상수라서 그렇습니다.
값을 얼마로 잡나
낮게 잡으면 그림자가 새까매지고, 높게 잡으면 장면 전체가 뿌옇게 뜹니다. 빛을 등진 면과 받는 면의 차이가 줄어들어서 입체감이 사라집니다.
그래서 보통 0.05에서 0.2 사이입니다. 그리고 환경광 색을 흰색이 아니라 그 장면의 분위기 색으로 잡습니다. 낮이면 하늘색, 실내면 벽 색, 저녁이면 붉은색입니다. 튀어 들어오는 빛이 실제로 그 색을 띠기 때문입니다.
요즘은 상수가 아닙니다
상수 하나로 깔면 어디나 똑같이 밝아집니다. 좁은 틈새도 뻥 뚫린 벌판과 같은 값을 받습니다. 실제로는 틈새가 더 어두워야 합니다. 사방에서 오던 빛이 벽에 막히기 때문입니다.
그래서 이 항을 개선하는 방향으로 여러 가지가 나왔습니다.
| 무엇 | 어떻게 |
|---|---|
| 앰비언트 오클루전 | 주변이 얼마나 막혀 있는지를 재서 틈새의 Ambient 를 깎습니다 |
| 스카이박스 기반 환경광 | 하늘 텍스처를 흐리게 뭉갠 것을 법선 방향으로 읽어서 방향마다 다른 값을 줍니다 |
| 라이트 프로브 | 공간 여기저기에 점을 찍어 두고 그 자리의 간접광을 미리 구워 둡니다 |
전부 “상수를 조금 더 그럴듯한 값으로 바꾸는” 일입니다. 간접광을 실시간으로 다 계산하지 않는다는 타협 자체는 그대로입니다.
정리
- 현실에서 빛은 사방에 튀어서 직접광이 안 닿는 자리도 완전히 어둡지 않습니다.
- 그 튀는 빛을 다 계산하는 것은 비싸서, “어디든 최소 이만큼” 이라는 상수를 깔아 근사합니다.
- 법선도 시선도 광원 위치도 안 씁니다. 재질 색에 환경광 색을 곱해서 더하는 게 전부입니다.
- 없으면 빛을 등진 면이 완전한 검은색이 되어 형태가 안 보입니다. 어두운 것과 없는 것이 같은 색이 됩니다.
- 상수 하나라 틈새와 벌판을 구분 못 합니다. 앰비언트 오클루전, 환경광 맵, 라이트 프로브가 그 자리를 메웁니다.