이전 포스팅에서 fragment shader 의 역할 중 첫 번째 역할인 texturing에 대해 배웠다.

이번 포스팅에서는 lighting에 대해 배워보자. 그중에서도 가장 기본이 되는 Lighting 모델인 Phong Lighting에 대해 배워보자.


Phong Lighting Model

Lighting은 물체와 빛 사이의 상호작용을 말한다. 사실적인 그래픽을 위해서는 lighting이 매우 중요하다.

그중에서도 유타대학 출신의 베트남 사람인 Phong 이 제안한 모델인 phong lighting model은 4개의 요소로 이루어져 있다.

Diffuse, Specular, Ambient, Emissive 이다.

 

네가지 요소의 설명에 앞서 광원에 대해 생각해보자. 광원은 여러가지 종류가 있다. 가장 간단하게는 두가지로 나눌 수 있는데 첫번째는 점광원, 두번째는 방향성 광원이다. 점 광원은 한 점에서 빛이 발산하는 것으로 그 빛을 중심으로 모든 방향으로 빛이 나아간다. 방향성 광원은 해라고 생각하면 된다. 빛이 매우 강하고 아주 멀리 떨어져 있다. 굉장히 멀리 있기 때문에 평행하게 빛이 들어온다. 즉, 모든 점에 입사하는 빛은 같은 방향을 가진다.


Diffuse Term (난반사)

이제 phong model 의 네가지 요소에 대해 알아보도록 하자.

diffuse 와 specular는 직접 조명을 다루는 반면 ambient는 간접 조명을 다루고, emissive는 스스로 빛을 내는 경우의 항이다.

 

diffuse항을 먼저 보도록 하자.

Diffuse

diffuse 항은 난반사를 의미한다. 빛은 파란색 방향으로, 한쪽 방향으로 들어오지만 주황색으로 보이는 것처럼 온갖 방향으로 다 반사가 된다. 우리가 어떤 물체의 색을 볼 때, 그 물체가 반사하는 색깔을 보는 것이다. 빛이 온갖 방향으로 반사가 될 때, 그래픽스에서 어떤 방향에서 보든 차이가 없을 것이다. 즉, 점 p의 색상은 어디서보나 동일할 것이다. 이게 난반사의 특징이다. 그리고 이러한 표면을 diffuse surfaces (Lambertian surfaces) 라고도 한다.

 

중요한 것은 얼마만큼 p점에 빛이 들어오는가 이다. 

빛이 들어오는 방향(파란색)을 light으로 해서 l 벡터라고 하고, p의 법선 벡터를 n(normal)로 표기한다. n과 l 사이의 각도가 p가 받는 빛의 양을 결정한다. 그런데 p가 언제 빛을 가장 많이 받을까를 생각하면 광원이 normal 방향 바로 위에 놓여있을 때이다. 물론 표면과 빛 사이의 각이 90도를 넘어가는경우는 빛이 표면에 도달하지 않으므로 고려되지 않는다. 즉, 각도가 90도가 되면 빛을 전혀 못 받는다. 그러면 각도가 커질수록 빛은 덜 받게 되는거고 반비례 관계를 갖게 된다.

 

이를 수식으로 나타내면 max(n dot l , 0)이다. (각도가 90도를 넘어가면 0을 취한다.)

p가 받는 빛의 양은 n dot l 로 표현할 수 있고, n과 l은 보통 normalize 해서 1이므로, p가 받는 빛의 양은 cos세타로 표현할 수 있다.

 

이는 빛의 강도만 생각한 것이고 실제로는 빛의 색상도 생각해야 한다.

 

 

이제 색상을 가진 실제 물체에 대해서 보자. 실제 빛과 물체에서는 빛의 색상과 물체의 색상도 고려해야 한다. RGB가 모두 1인 광원이 들어온다고 했을 때 흡수하고 싶은 광원만 흡수한다. 예로 정육점의 진열대에 파란색 물체를 놓으면 (1,0,0)의 광원을 (0,0,1)이 흡수하면 (0,0,0)으로 나와서 검정색으로 보인다.

 

diffuse term은 아래와 같다.

d = diffuse

S = source(광원의 색상)

m = material(물체 표면의 색상)

(x) = 쌍쌍으로 곱한다.

diffuse term

 


Specular Term (정반사)

다음으로 specular 항은 정반사를 의미한다. specular로 인한 빛은 매끈한 표면으로 특정한 방향으로 반사가 되어 하이라이트가 생성되는 방식이다. specualr term에는 시선벡터와 방향벡터가 필요하다.

 

빛이 들어오는 방향인 l 벡터가 있고, 빛이 들어오는 방향과 normal과의 각도를 세타(입사각)라고 하고, 입사각과 동일한 반사각을 이루면서 빛이 튕겨져 나가는 reflection 방향의 벡터를 r 벡터로 표기한다. 해당점과 카메라 위치(EYE)를 이어서 또 다른 벡터를 만들고 그것을 view 벡터 v로 표기한다.

 

reflection vector와 view vector가 같다면 정반사를 정확하게 캐치하는 것이다.

Specular

 

방향을 계산하는 부분을 보자.

reflection vector

둘 사이의 각도만 알면 r벡터를 계산할 수 있다. 그리고 reflection vector를 오로지 n과 l로 정의할 수 있다.

 

Specular term(정반사)로 인한 빛은 r과 매우 가까울때 최대가 된다. 극단적인 경우 (이상적으로 매끄러운 표면)에서는 r에서만 이러한 specular term이 검출된다. 하지만 어느정도 매끄러운 표면이라면 r에 가까운 방향이라면 이 speqular 항을 검출할 수 있게 되는데 이 r과 v 사이각로(p) 라고 하자.

 

specular term

위에서 본 바와 같이 로 값을 이용해 specular 항의 민감도를 결정하는것은 shininess(sh)값이 된다. sh 값은 얼마나 물체가 매끈한가를 나타낸다. 매끈할수록 반짝거리니까 이렇게 표현한다. 거울과 같이 매끈한 물체일수록 sh값이 커진다.

 

sh값이 너무 크면 로가 0에 가까울때만 보이고 너무 작으면 난반사와 유사한 상태(r과 v가 멀리있음에도 specular term이 너무 잘 관측)가 된다. 따라서 이 sh값을 결정하는것도 중요한 요소 중 하나이다.

 

그래서 정반사(Specular term)의 강도(intensity)는 (r dot v)^sh 로 표기가 가능하다.

여기에 난반사에서 색상을 고려한 것처럼 똑같이 색상을 고려해주면 된다.


Ambient and Emissive Term

방안의 불을 다 끄게되면 순간에는 광원이 없어서 아무것도 안보이지만 조금 있다가 보면 보인다. 왜냐면 문틈이라던지 어디선가로부터 빛이 들어오기 때문이다. ambient 항은 동일 계 내에서 다른 물체들로부터 반사된 빛을 말한다. ambient light는 장면의 모든 지점에서 반사된 빛이 합쳐진것으로 모든 방향을 따라 빛이 들어오고 반사된다.

 

ambient term

p점으로 온갖 방향에서 빛이 들어온다. 그렇기 때문에 물체 특성과는 무관하게 반사되는 빛 역시 온갖 방향으로 이루어진다. 이런 것을 ambient reflection이라고 하고 우리말로는 배경광 반사라고도 한다. 

 

빛이 온갖 방향에서 들어오기 때문에 특정한 l 벡터가 필요가 없다는 이야기이고, 빛이 반사되는 것을 결정하는 건 normal 벡터인데, 빛이 온갖 방향에서 들어오기 때문에 normal 벡터 의미가 없게 된다. 

 

마지막으로 emissive term은 자체 발산하는 경우에 고려되는 항이다. 즉 스스로 빛을 내는 물체이다.

emissive term

 

따라서 phong model은 이러한 빛들을 모두 합친 식이 된다.

Phong model


Per-fragment Lighting

이렇게 간단하게 모델링을 하고 Phong model을 통해 일정 정도 빛을 반사하는 것도 반영을 하였다. 이제 프로그램으로 구현을 해야 한다. Fragment shader가 lighting을 어떻게 구현하는 지 보자.

l, n, r, v가 중요하다. 곡면을 렌더링한다고 했을 때 두 점을 보자.

 

광원이 해라고 했을 때 두점에 들어오는 빛의 방향은 일정하다고 했다. 이러한 lighting을 Fragment shader가 수행을 할텐데, Fragment shader는 Rasterizer가 주는 입력과 더불어 uniform이라는 입력을 받는다고 하였다. vertex shader에서 world matrix가 uniform으로 들어오듯이. 마찬가지로 모든 Fragment shader는 동일한 light vector인 l 을 쓴다. 따라서 l은 위와 같이 uniform으로 들어온다.

 

n은 물체 표면마다 다르다. 그리고 polygon mesh마다 normal이 있었고, Rasterizer가 보간을 한다고 배웠다. 보간된 normal이 넘어온다. 

 

v는 eye에서 두 점을 보는 방향이 다르다. 각도 차이가 있다. 따라서 v 벡터도 fragment마다 다를 것이다. 그래서 n과 v는 Rasterizer가 줘야 한다.

 

r은 n과 l이 주어지면 얘내 둘을 이용해서 reflection vector인 r을 계산할 수 있다고 배웠으므로 r은 자체 계산을 해야 한다. 

 

그림 1

이렇게 Fragment shader가 l, n, r, v 를 가지고 Phong model을 수행한다.

 

input(Polygon mesh)

-> p1,p2의 normal (Object space의 vertex array)

-> Vertex shader (Object space에서 World space로 normal 변환)

-> Rasterizer (normal 보간 해줌)

-> l, n (보간된 normal), r, v (World space

-> Fragment shader

 

위 그림에서의 p1, p2의 normal을 bilinial interpolation을 통해서 보간을 하는 모습이다.

이렇게 보간된 normal을 Fragment shader로 넘겨준다.

Fragment shader는 l, fragment의 n, r(자체 계산), v 를 받는다.

 

그림 2

카메라는 World space에서 주어진다. 점은 아직 Object space의 점이다. 각각의 점을 World space로 변환을 하고, 변환된 World space의 점을 카메라랑 이어서 World space의 view vector를 만든다. World space의 v는 Rasterizer에게 넘겨진다. 그러면 오른쪽 그림의 v1, v2는 World space의 view vector이다. 그래서 두 fragment의 view vector를 할당을 한다. 이렇게 보간된 va vb는 Fragment shader로 넘어간다.

 

Fragment shader는 l, n, r, v를 받는데 다시 집고 넘어가자면, l 은 uniform으로 주어지고, n은 그림 1에서 받았고, 그림 2에서 v를 받으면 r을 계산할 수 있다. 그럼 다 주어졌다. 그러면 Phong model을 구현할 수 있다.

 

이것이 전체의 흐름이다.

 

지금까지 배운 것을 다시 정리해보자. 

Fragment shader가 Phong model을 구현하기 위해서는 l, n, r, v가 필요하다. l은 uniform으로 주어지고 두 fragment의 a, b의 l은 동일하게 주어진다. 근데 n(normal)과 v(view vector)는 각각 Vertex shader를 통해 World space로 변환한 다음 Rasterizer에 넘겨주면 Rasterizer가 fragment 마다 보간을 한다. 그래서 n과 v를 구할 수 있다. 남은 r은 r = 2n (n dot l) - l 으로 계산한다. 이제 4개가 다 주어졌으므로 Lighting을 수행할 수 있다.

 

위 그림에서 b는 r과 v가 같아서 정반사로 보이고, a는 r과 v의 각도(로)가 커서 정반사를 못 볼 것이다. 그래서 a와 b에서의 정반사는 굉장히 다를 것이다.


Ref.

Introduction to Computer Graphics with OpenGL ES (J. Han)

 

'☘️ Computer Graphics > Fundamental' 카테고리의 다른 글

CG - Euler Transforms and Quaternion  (0) 2022.07.21
CG - Output Merger  (0) 2022.07.20
CG - Image Texturing  (0) 2022.07.18
CG - Rasterizer  (0) 2022.07.16
CG - Vertex Processing  (0) 2022.07.15
복사했습니다!