s
강좌를 보기 전에...
Cygwin 설치방법
REYES
Shader 강좌 1
Shader 강좌 2
Shader 강좌 3
Shader 강좌 4
Shader 강좌 5
Shader 강좌 6
Shader 강좌 7
Shader 강좌 8
안녕하세요. 김대현입니다.

오늘은 렌더맨 기본 쉐이더인 matte.sl를 통해 렌더맨의 기본 라이팅에 관해 알아보겠습니다.

Pasted Graphic 1

라이팅을 이해하기 위해서는 먼저 이해해야할 중요한 수학이 있습니다. 말이 수학이지 정말 쉬운 내용입니다.

~ 들어가 보죠~!

라이팅 공식을 이해하기 위해서는 벡터와 벡터의 연산인 내적에 관해 알고 있어야 합니다.

벡터의 경우 거의 아시리라 생각하지만, 간단히 알아본다면, 위치가 아닌 방향만을 나타내기 위한 값이라고 생각하시면 됩니다.

보통 (1,1,1) 좌표와 벡터 (1,1,1) 있을때, (1,1,1) 위치값을 나타내지만, 벡터(1,1,1) 0에서 (1,1,1) 수선을 그어 방향을 나타내는 값입니다. 그렇기 때문에 벡터(1,1,1) 사실 (1,1,1)이란 값은 의미가 없습니다. 방향만 같다면 어떤 값이라도 들어갈 있습니다.

그림을 보시면 각각 다른 길이와 시작 위치를 가지고 있지만 같은 방향을 가리킨다면 같은 벡터입니다. 보통 3D 프로그램에서는 시작점을 0으로 하는 벡터를 주로 사용합니다.



그럼 내적이란 무엇일까요?

내적은 dot product 혹은 inner product라고 불리우는데, 보통 벡터사이에 각을 알아내는데 유용하게 사용됩니다.

내적의 계산은 벡터를 성분끼리 곱해서 합을 내는 것으로 하나의 스칼라 값이 나오게 됩니다.

간단히 공식으로 보자면,

V1 = (x1, y1, z1)
V2 = (x2, y2, z2)

V1.V2 = (x1*x2) + (y1*y2) + (z1*z2)




사실 내용을 자세히 알자면 끝이 없는 법이고, 라이팅을 사용하기 위해 간단한 사용법만을 알아보겠습니다.

V1.V2 > 0 : 90 이하
V1.V2 = 0 : 90

V1.V2 < 0 : 90
이상



라이팅을 위해 알아야 내적에 관한 사항은 이것이 입니다. 벡터를 내적해서 나온 값이 0보다 큰지, 작은지에 따라 각도의 범위를 있습니다.

그럼 내적이 라이팅 계산과 어떤 관계가 있을까요 ?







~ 출발해 봅시다~!!

1. REYES
알고리즘을 설명할때, micropolygon vertex마다 Shader 코드가 불린다고 말씀드렸습니다.

렌더러에서 현재 처리하고 있는 micropolygon vertex 점위치를 P라는 전역 변수에 넣어주고, 노말 벡터 역시 N이라는 전역 변수에 넣어준 다음 Shader 코드를 호출합니다.



2. Shader
에서는 렌더러에서 넣어준 노말 벡터를 가지고 재미있는 작업을 있습니다.



3.
표면에서 빛을 받는 부분을 어떻게 구분할까요 ?

빛을 직접 받는 부분은 밝을 것이고, 빛과 반대 방향에 있는 부분은 빛을 받지 못할 것입니다.

우리가 알고 있는 것은 라이트의 벡터와 현재 처리 중인 점의 노말 벡터입니다. 답이 보이지 않습니까 ?
Pasted Graphic 2


그렇습니다. 우리가 방금 공부한 내적에 의해 라이트 벡터와 노말 벡터의 각이 90 미만일때 바로 바로~~빛을 받는 부분이라고 있는 것입니다.

내적한 값이 0보다 크면 부분은 빛을 받는 부분입니다. 0보다 작으면 ? 그렇죠~ 그림자 부분이라고 있습니다.



4.
일단 정리하고 넘어갑시다.

라이트 벡터와 포인트 노말의 벡터를 내적한 값이 0보다 크면 부분은 라이트의 영향을 받는 부분입니다.



5.
~ 그럼 구한 내적의 값은 어디에 사용되는 걸까요 ?

우리가 구하고자 하는 것은 현재 포인트의 색상입니다. 렌더러에서 Cs 전역 변수에 우리가 사용할 색상을 입력하여 주었습니다. 우리는 색상을 적절히 조작하여 물체에 볼륨감을 주도록 색상을 조절해야 합니다.

그렇다면, 어렵게 구해 놓은 내적을 적절히 이용하지 않고 내버려 둔다면 그건 죄악이죠 ^^

보통 내적의 범위는 -1 <= 내적 <= 1입니다. -1~1 사이에 값이란 뜻입니다.

1.0
하면 떠오르는 것이 없나요 ?

시간에 자주 볼거라고 말씀드렸는데.....

맞습니다. opacity 색상의 블랜딩하는 웨이트값으로 쓰였듯이, 내적값도 현재 색상과 라이트간의 웨이트값으로 사용될 있는 것입니다.



6.
렌더맨에서 제공하는 matte.sl 파일을 열어 봅시다.

matte.sl
-------------------------------------------------------------------------------------------------

surface matte( float Ka=1, Kd=1 )
{
        normal Nf;

        Nf = faceforward(normalize(N),I);

        Oi = Os;
        Ci = Os * Cs * ( Ka*ambient() + Kd*diffuse(Nf) ) ;
}


-------------------------------------------------------------------------------------------------



7.
보니 diffuse()라는 함수가 눈에 띄는군요.

놈이 갖고 가는 Nf 바로 포인트의 노말 벡터입니다. ( faceforward 노말 벡터가 뒷면에 있더라도 벡터 방향을 적절히 변경하여 뒷면도 렌더링할 있게 하는 함수구나... 정도만 우선 알고 있으면 됩니다. 우선 Nf 현재 포인트의 노말 벡터라는 것이 중요합니다. )

diffuse
놈이 포인트의 노말 벡트를 물고 들어가는 것이 보니, 아주 의심스럽지 않습니까 ?

맞습니다. 이놈이 바로 바로 바로~~~~~~ 우리 대신 라이트와 현재 포인트의 노말 벡터의 내적을 구해주는 놈입니다. ( 내부적으로는 다수의 라이트들을 일주하면서 현재 포인트에 적용할 최종 내적값을 구합니다. )

그럼 diffuse 리턴하는 값은 어떤 값일까요 ?

그렇습니다. 바로 0~1 사이에 값입니다. ( -1~0 뒷면인거 기억하시죠 ? 물론 faceforward 통해 뒤를 가리키는 놈들도 모두 뒤집어줘서 -1~0 값은 없을 겁니다. )

빛이 똑바로 표면에 꽂치면 바로 이값이 1이고 가장 밝은 부분이 됩니다. 0이면 바로 빛과 어둠을 가르는 엣지 부분이 되겠네요. 나중에 비실사 렌더링을 하실때, 엣지 드로잉을 한다면 바로 0 값에 가까운 놈들만 골라 그려 주면 되겠네요. ~ 좋구나~~!!



8.
그렇다면, 일직선으로 꽂치는 부분이 1이므로 소스로 보자면 Cs 값을 그대로 유지하는게 되겠네요. 색상에 1 곱해봐야 그냥 색상 값이니...

그렇다는 것은 0 가까워 질수록 색상값을 깍아 먹게 되겠네요. ~~ 뭔가 닺지 않습니까 ?

맞습니다. 우리가 쉐이딩을 한다는 것은 빛을 입히는 것이 아니라 어둠을 입히는 것입니다.

, 원래 색상에서 값을 깍아서 점점 어두운 색을 만드는 것이지요.



9.
그렇다면 Kd값은 ?

기본 값이 1인거 봐서는 기본적으로는 연산에 영향을 주지 않고 있습니다. 하지만, 1보다 작은 값을 넣는다면 ?

바로 제살 깍아먹기가 되겠군요~! 빛이 똑바로 꽂혀봐야 1 안되는 상황이 되는 것이죠.

이놈을 적절히 이용하면 가장 밝은 곳과 어두운 곳의 영역을 조절하는 역활을 하게 되겠네요.



10.
~ 얼추 디퓨즈에 의한 색상 변화는 만들어 냈습니다.

그런데, 문제가 있군요. 빛이 닿지 않는 부분은 그냥 검정색이라는 것입니다. 실세계에서도 빛이 닿지 않는다고 해도 완전히 검은 색은 없죠. 바로 반사광때문입니다.



11.
반사광을 물리적으로 계산하려면 100 뒤에 태어나길 기도하는게 나을 겁니다.

그렇다면, 우린 꽁수를 내야 겠군요. 인생이 그렇지 않습니까 ? ^^



12.
바로 꽁수~~ ambient() 놈이 등장할 시간이군요.

이놈이 하는 일은 너무 너무 너무 너무 너무~~~~~~간단해서 솔직히 말하기도 두렵습니다.

직접 확인해 보죠.

렌더맨 기본 shader ambientlight.sl 파일을 열어 봅니다.

ambientlight.sl
-------------------------------------------------------------------------------------------------

light ambientlight(    float intensity=1;    color lightcolor=1; )
{
        L  = (0,0,0);
        Cl = intensity * lightcolor;
}


-------------------------------------------------------------------------------------------------

함수로 만들기에도 부끄러운 소스군요.

그냥 라이트 색상과 intensity 곱한 값을 넘겨줍니다.



13.
이로서 Kd*diffuse(Nf)값이 0으로 완전히 검은색 부분이라도 ambient() 함수를 통해 어두운 부분에도 적당히 색상을 더해 줌으로서 완전히 어두운 부분을 제거할 있습니다.



14.
ambient()함수를 통해 반사광 효과를 아주 적절히 있습니다.

물리적인 반사 모델은 아니지만, 적은 연산으로 사실에 가까운 라이트 효과를 만들어 냈습니다.

바로 우리가 원하는 것이죠~!



15.
무지하게 힘들게 달려 왔습니다. 도대체 이런 알아야 ~? 하고 질문하실지도 모르겠습니다.

하지만, 렌더맨에서 제공해 주는 라이팅은 사실 너무나도 부족합니다. 우리는 과정을 통해 기본적인 라이팅 알고리즘을 배우고, 나중에 이것을 바탕으로 우리 자신만의 라이팅 모델을 만드는 것이 목표입니다.

, 우리만의 diffuse함수와 ambient함수를 만들어야 한다는 것입니다.

힘들게 달려 왔지만 가치있는 일입니다. 힘내세요~ 파이팅~!!!!



16.
다음 시간에는 금속 재질에서 반드시 필요한 specular 알고리즘에 관해 알아보아 보도록 하죠.