Phong reflection
3차원 공간에서 입체적인 물체를 바라볼 때 물체의 부분마다 조금씩 색의 차이를 보입니다. 빛이 많이 비치는 부분은 밝고, 덜 비치는 부분은 상대적으로 어둡습니다. 어떤 물체는 표면이 아주 매끄러워 반짝반짝 빛나기도 합니다. 이번 포스트에서는 물체의 색이 빛과의 관계에 따라, 물체 본연의 성질에 따라 색이 달라질 수 있도록 하는 쉐이딩 기법, Phong reflection 을 알아보겠습니다.
Phong reflection 은 ambient (주변광), diffuse (확산광), specular (반사광) 을 조합하는 기법입니다. 식으로 쓰면 아래와 같습니다.
- : ambient 빛의 세기
- : 번째 광원의 diffuse 빛의 세기
- : 번째 광원의 specular 빛의 세기
- : 물체의 ambient 반사 상수
- : 물체의 diffuse 반사 상수
- : 물체의 specular 반사 상수
- : 물체의 반짝이는 정도
위 상수들은 각각의 물체, 빛에 대한 속성을 나타낸 것으로 변하지 않는 값입니다. 속성들 중 는 스칼라이고 그 외 나머지는 RGB 삼요소를 가진 벡터로 각각의 색에 대해 0 ~ 1 로 정도를 표현합니다. 예를 들어 초록색에 가까운 색은 [0.0, 0.8, 0.0] 와 같이 표현합니다. 각각의 상수의 역할은 이후 ambient, diffuse, specular 에 관한 절에서 자세히 살펴보겠습니다.
상수들 외에 , , , 는 쉐이딩의 계산에 필요한 벡터들이며 아래 그림과 같습니다.
Ambient
공간에 광원이 없음에도 일정 세기의 빛이 항상 존재한다고 할 때 이를 ambient, 주변광이라 합니다. 집 안의 불을 전부 끈 상태에서 눈을 떠보면 처음엔 칠흑 같지만 이후 물체들의 윤곽이 조금씩 보이기 시작합니다. ambient 는 바로 이 때 보이는 물체의 희미한 색입니다.
Phong reflection 식에서 ambient 에 의한 물체의 색은 로 나타냅니다. 는 공간 안의 빛의 개수에 비례하여 설정할 수도 있고 개수에 상관없이 상수로 설정할 수도 있습니다. 중요한 것은 매우 어두운 공간에서 물체의 윤곽만을 쉐이딩하는 역할을 하므로 매우 작은 값으로 설정합니다. (e.g. [0.07, 0.07, 0.07])
각각의 물체의 ambient 반사 상수 와 의 곱을 이용하면 다음과 같은 렌더 결과를 얻을 수 있습니다.
Diffuse
diffuse 는 빛의 각도에 따라 물체의 어둡고 밝음을 표현하는 쉐이딩입니다. diffuse 에 의한 물체의 색은 로 나타냅니다. 이 때 는 광원의 diffuse 빛의 세기를 RGB 벡터로 나타낸 값이고 각각의 광원은 다른 값을 가질 수 있습니다. 예를 들어 광원이 푸른 빛을 띄도록 하려면 의 RGB 값 중 B 값을 높이 설정하면 됩니다.
diffuse 는 물체 표면과 광원의 위치 관계를 반영합니다. 빛을 정면에서 받는 물체는 비스듬히 받는 물체보다 더 밝을 것입니다. 여기서 정면과 비스듬히의 차이점을 좀 더 정량적으로 살펴 보겠습니다.
위 그림은 같은 면적이지만 그 각도에 따라 단면적당 받는 빛의 세기가 달라짐을 보여줍니다. 면적 1의 두 지점 A, B 가 빛을 받을 때 A 지점은 광원으로부터 빛이 수직으로 전달됩니다. 이 때 A 를 비추고 있는 광선의 가로 길이는 지점 A 의 길이와 같은 1입니다. 반면 B 를 비추는 광선의 가로 길이는 이고 임을 고려할 때 A 지점보다 빛을 덜 받고 있다는 것을 알 수 있습니다. diffuse 는 이처럼 물체 표면에서의 빛의 각도를 이용합니다.
위 그림에 벡터 과 를 추가해 보겠습니다. 은 물체 표면에서의 법선 벡터를, 은 광선의 진행 방향을 나타내는 벡터입니다. 과 은 모두 단위 벡터입니다.
그림에서 알 수 있듯 입니다. 이 성질을 diffuse 관련 상수와 조합해 다음과 같이 diffuse 쉐이딩 식을 이끌어 낼 수 있습니다.
주의할 점은 가 음수 일 때 즉, 일 때 입니다. 은 물체가 빛을 등지고 있다는 의미이며 아무 조건 없이 식을 계산하면 입니다. RGB 의 값은 음수가 될 수 없으므로 diffuse 의 값은 이라 할 수 있습니다.
이제 ambient 와 diffuse 를 동시에 적용해 렌더해 보겠습니다.
Specular
specular 는 광원의 색이 관찰자의 눈에 그대로 보여지는 효과를 줍니다. 때문에 specular 는 광원과 물체 뿐만 아니라 관찰자의 위치도 고려합니다.
specular 는 로 나타내며 이 때 각각의 벡터는 아래와 같습니다.
그림을 보면 로 쓸 수 있습니다. 는 반사된 빛의 방향 벡터 과 관찰자를 향하는 벡터 의 내적이고 길이가 1인 과 에 대해 입니다. 반사된 빛이 관찰자의 눈에 직접 향한다면 을 의미하므로 이 최대가 됩니다. 이 때 는 물체 표면의 반짝이는 정도를 나타냅니다. 아래 그림은 각 물체의 의 크기에 따라 달라지는 렌더 결과를 보여줍니다.
위 이미지는 diffuse 를 제외한 ambient 와 specular 값 만으로 렌더한 결과입니다. 사실 위 이미지들은 물체의 반짝이는 정도의 차이를 확연히 보여주지 못합니다. 왼쪽의 경우 값이 작은 것 치고 지나치게 밝은 느낌이 있습니다. Phong reflection 에서는 이와 같은 specular 의 왜곡 문제 때문에 물체의 specular 반사 상수 의 값을 에 맞춰 조절합니다. 아래는 물체의 값을 조절한 뒤 비교해본 결과입니다.
지금까지 Phong reflection 의 ambient, diffuse, specular 를 구하는 과정을 모두 알아보았습니다. 아래는 세 개의 쉐이딩을 모두 더한 결과 이미지 입니다.
Phong reflection 쉐이딩 식을 다시 한번 보면,
ambient 를 제외한 나머지 diffuse, specular 에 대해 가 존재합니다. 이는 diffuse, specular 는 공간을 비추고 있는 모든 광원에 대해 그 값을 합해야 함을 뜻합니다.
Phong reflection 반영한 레이 트레이싱을 의사 코드로 쓰면 아래와 같습니다.
def render_ray_tracing_image():
for y in range(0, height):
for x in range(0, width):
ray = # x, y 를 이용한 광선 객체
grid[y][x] = ray_trace(ray)
def ray_trace(ray):
obj = # 부딪힌 물체들 중 가장 가까운 물체
if obj is None:
return background_color
shade = # ambient 쉐이딩
for light in lights:
shade += # diffuse 쉐이딩
shade += # specular 쉐이딩
return shade
이제 Phong reflection 식을 적용해 물체를 렌더할 수 있게 되었습니다. 하지만 식을 완성하기 위한 하나의 미지수를 아직 구하지 못했습니다. 다음 포스트 에서는 Phone reflection 식과 이후 반사, 굴절을 위해 사용되는 법선 벡터 을 찾는 방법을 알아보겠습니다.