꽃미남 프로그래머 김포프가 창립한 탑 프로그래머 양성 교육 기관 POCU 아카데미 오픈!
절찬리에 수강생 모집 중!
프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 대마왕J

어서와

 

 

 

아 두 달 만에 쓰니까 막 게을러 질라구 그래 ㅋㅋㅋ

하여간 정~~~~말 오래 기다리셨습니다. 제가 슬슬 게을러지는 데다가 몸도 말을 안들어서 (... 위로 댓글 달기만 해봐라) 막 매일 밤새서 글 작성 그런거 못해요. 회사 프로젝트도 바빠지고 있구요. 게다가 줄여나가려 노력하고 있는데 자꾸 거절할 수 없는 강의 / 강연 요청이 들어와서요 ...

삼X지를 품X는 잘 오픈한 것 같은데... 저는 지금 거기 없어요. 제가 보는 프로젝트가 하나가 아니랍니다 (...) 
삼품 팀원들은 다들 미쳐가고 있는 모양이지만요. 모바일 연동게임 만드는거 보통 어려운 일이 아니거든요.
모바일 프로젝트 손대고 싶은거 한 두 개가 아닌데 더 못챙기고 올라온게 못내 아쉽...

 

열심히 코딩중인 프로그래머 아이맥 군

자 그럼 오늘 하던 거나 해 봅시다.

제 강의 스타일은 '반복' 이예요.
어차피 새로운 내용 공부할 때 한 번만에 다 이해하는 사람은 거의 없거든요. 저도 그래요. 제 학생들도 다 그랬구요 후후후 . 그래서 저는 계속 같은 내용으로 응용해서 반복시켜요.

그러다가 아하! 하고 뿅 전구가 들어오는 학생들이 생기면 기쁘죠.

유레카!

그 친구들은 갑자기 머릿속이 환해지는 거구요. 대충 살아가지만 나름 강의할때 학생들이 이해하는 기전(메카니즘)을 연구해서 노력하고 있답니다. 뭐 이런 얘기를 왜 하는지는 앞으로 보시면 잘 아실테고...

 

 

 

0. 오늘은 일단 지난 시간 얘기 잠깐

지난 번에 하프 램버트라는게 있었습니다. 먼 옛날 옛적에요. 네에 그런게 있었어요. 호랑이 담배피던 때 말이죠.

 

그랬어요.


어쨌거나 지난 번 시간은 이런 결과물을 만드는 거였습니다.

이게 최종 결과물이구요. 원래 원본은 ...

이게 그러니까.. 지금 저 0.5 라고 되어 있던 부분이 사실 0이었죠.


지금 0이라고 되어 있던 부분은 사실 -1 이었구요.

거기다가 마법의 공식인 *0.5+0.5 라고 하는 '매직 넘버' 를 넣어서 저렇게 만든거구요.

이 매직 넘버를 넣기 전의 그림은 아세요?  기억하시죠?

이게 원본이었잖아요.

Dot 공식인가 뭔가에다가 조명벡터와 노말벡터(서피스 벡터)를  넣으면.. 코사인 그래프에 따라서 저런 값이 나오게 되어서.. 빛이 비추는 것처럼 보이게 된다는게 기본이었죠.

이게 중요한 그림이란 말입니다.

 

그래요.우리는 지난 시간에 이걸 가지고 하프-램버트 (Half-Lambert) 라고 하는 빛 계산 공식으로 살짝 바꿔 봤어요.
어렵지 않고 쉬웠죠? 네 그래요. 쉬운게 당연하죠. 이거 진짜 쉬운 공식이거든요.

 

 

1. 그래서 이번 시간에는 다시 여기서부터 시작합니다 .

 

짜잔

반복이당

 

흔한 반도의 램버트.jpg

자자 좋아요. 자꾸 반복하니까 그림 안만들어도 되고 좋네...

이제 저건 아시겠죠? 중요해요!!! 조명 벡터와 노말벡터로 dot 연산해서 음영만드는거요!!! 중요하고 중요하고 또 중요해요!! 앞으로 2강 정도는 저것만 가지고 놀거라고요!!!

 

하나가지고 계속 울궈먹는건 정말 멋져요!

 

 

자 그럼 잘 생각해 보죠.

흐음. 조명 벡터[각주:1]노말 벡터[각주:2]를 ... 그래.. 둘 가지고 닷인지 뭔지 계산하는거...  알겠구나..

근데 말이죠. 잘 생각해 보세요. 이렇게 한번 생각해 보세요.

내가 말이죠. 내가... 만약에....

 

저 조명을 들고 있는거야 .

이렇게.

 

 

 

그럼 내가 조명을 들고 있으니까... 내가 볼 때는 저 주전자가 어떻게 보이겠어요?

 

 

어떻게 보이기는요. 이렇게 보이죠.

내가 조명이니까 , 내가 보는 방향에서 조명이 나간다고 치고 계산하는 거니까 이렇게 보이죠.

 

... 어라..

잠깐 재미있는 생각이 났습니다.

뭐냐면.

 

dot (조명벡터 , 노말벡터) 의 연산을

dot (카메라 벡터[각주:3], 노말벡터) 로 바꾼다면??

 

분명히 카메라에서 조명이 나오는 건 아니지만, dot연산으로 빛이 들어오는 음영을 '그리고' 있는 거니까... 사실 컴퓨터가 조명벡터일지 카메라 벡터일지 압니까. 그냥 float3만 들어오면 걍 dot 연산해주고 그러는 거지....

그래요 위에 보인 저 그림처럼, 내가 "굳이 카메라를 돌려서 라이트와 같은 방향으로 맞춰서 볼 필요도 없이" 자동으로 위와 같은 그림이 나올 겁니다.

일단 해보지요. 이해 안되시는 분도 따라해 보세요.

 

우선 이것부터 시작해야겠지요. 이거 모르시는 분은 저번 시간으로 돌아가서 다시 공부하고 오세요.
앞에 설명한거 이해 못한 채 뒤에것 공부할 수 있는 그런 단계 아닙니다 이제.

자 여기에서 아까 말한대로, 조명벡터(Light Vector) 를 카메라 벡터(CameraVector) 로 바꿔줘 볼께요.

 

어디 찾아 봅시다... 이 벡터는 있는걸 받아오는 거니까 Input에 있을테고...
어라? 여기에서의 이름은 카메라 벡터가 아니고 시선벡터 (Eye Vector) 네요.
어차피 다 같은 뜻이니까 당황하지 말도록 합시다.

 

와우 시선벡터 (Eye Vector)가 나왔군요.
역시나 아이콘 짱 좋아 ㅋㅋㅋㅋ 아이콘만 보면 카메라 벡터인줄 누구라도 알 수 있겠죠?

특히나 여기에 쓰는 벡터들은 기본적으로 정규화 (Normalize : 노말라이즈) 되어서 들어오기 때문에 아무 생각 없이 쓰기 짱 좋습니다.[각주:4]

이제 간단합니다. 시선벡터를 조명벡터 대신에 사용해 봅시다.

자아... 마치 카메라 (= 지금 당신이 보고 있는 눈) 이 조명인 것 처럼 연산이 됩니다. 당연하죠. 원래 조명 연산이라는게 그냥 벡터끼리의 연산이었으니까 ,굳이 조명을 안넣고 이렇게 아무 벡터나 넣어도 연산되는게 당연하잖아요.

어쨌건 당신의 눈은 이제 조명이 되었습니다.

 

대충 이렇게 된 느낌일까나.

 

 

 

그리고 이왕 하는거, LightColor 를 받아오던 것을 일반 Color로 바꿔 보았습니다. 더 이상 조명과는 이제 인연이 없어요.
조명 지워 버려도 됩니다 저거. 조명 안쓰니까요 안써. [각주:5]

자 , 카메라를 빙글빙글 돌려보세요. 그래도 조명에는 변화가 없습니다. 나를 바라보는 쪽이 언제나 밝아요.
신기하지 않습니까?

 

 

자... 뭐... 그래요. 알겠는데. 이거 가지고 이제 뭘 할 수 있을까요???

 

 

2. 림라이트를 만들어 봅시다.

 

응? 림라이트?

림라이트라고 하는 것은 요즘 게임에서 개나소나 많이들 쓰고 있는, 외각선이 빛나는 후광(後光) 효과입니다.
구현이 간단한데다가 배경과 캐릭터를 분리해 주어서 디테일을 살려주는 등 좋은 점이 많이 있습니다.

림라이트에 대한 이론적 설명은 여기 퐁퐁퐁 아저씨의 블로그 글을 참고해 주세요.

http://blog.naver.com/sorkelf?Redirect=Log&logNo=40135726372

자 솔직히 림라이트는 ... 다 만들었습니다! 위에 이미 설명 다 했어요 !!! ㅋㅋㅋ
조명벡터를 카메라 벡터로 바꾸는게 전부 다 거든요!!!

그럼 이제 이렇게 생각하시는 분들이 있겠죠.

그냥 조명이 카메라로 바뀐건데 뭐가 림라이트라는거야?

 장난하냐

자 과연 그럴까요. 해 봅시다.

 

일단 공식을 적용할 곳은 아직 float3 가 되기 전, 그냥 float 인 저 부분을 공략할 겁니다. float3는 이미 color가 적용되어 있어서 곤란. 그냥 순수하게 float 연산만 나오는 부분이 필요해요. 가끔 저기 Color가 적용된 후에다가 하시는 분들 계신데, 아니예요. 칼라가 적용되기 전에 순수하게 float 데이터가 나올 때 적용하는 겁니다 !!! 잘 생각해 보세요! 당연해요!!

 저 부분을 끊고, 뭔가 공식을 적용합시다 [각주:6]

 

 간만에 꺼내는 NegateOneMinus예요. 기억하시는 분?

 그냥 꺼내기만 해서는 - 만 나오죠. 이건 들어오는 값을 - 로 반전시켜주는 기능이예요.
우리가 여기서 필요한건 1- (One Minus) 입니다.

그걸 저 dot 값에 적용해 보죠.

 

 

 

 

 

 

 

 

 

짜잔.[각주:7]

오오오! 뭔지 알 것 같습니다!

그쵸... 조명을 1- 해줘서 뒤집어 주면... 저렇게 나와야지요!


그리고 흔히 보던 림라이트가 눈에 보이기 시작합니다! 그게 조명에서 시작한 것이었다니! 그냥 조명을 1- 로 뒤집어 주면 되는 것이었습니다! 생각해 보면 일목요연하죠. 조명이 카메라로 바뀌어서, 나를 바라보고 있는 노말벡터 부분의 값이 1이 되어 버리고, 나의 시선과 90도로 꺾인 부분은 0이 되어 버리는건데, 그걸 뒤집어 버리니까 저렇게 결과가 나온 것이었지요. 즉 노말벡터가 내 시선과 90도가 되면 될수록 밝아진다는...

이거 이해하고 넘어가야 합니다. 매우 중요하고 응용도 많이 되어요.

 

좋아요 그럼 이제 끝인가요?

뭔가 좀 부족하죠?

부족한건 일단 저겁니다. 저 림라이트의 두께... 너무 두꺼워요. 좀 얇게 만들어 봅시다.

 

 

 

3. 두께를 조절해 봅시다.

두께를 조절한다... 밝게 있는 부분의 면적을 늘이거나 줄이는 거지요.
음.. 어떻게 하면 될까요?

여기서 추가로 필요한게 pow (x,y) 라고 하는 함수입니다 .
pow(x,y)는 x의 y승이예요.

노드로 꺼내보면 이렇게 꺼낼 수 있죠.

 

shader FX의 노드로는... Raise to a Power 라는 이름으로 되어 있군요. [각주:8]
꺼내봅시다.

 

역시나 모양도 아주 이쁘게 X의 Y승이라고 씌여 있습니다 ㅋ 제가 shaderFX를 교육자료로 쓰는 이유가 저 아이콘 때문이라고 해도 과언이 아니예요 ㅋㅋ

좋아요. 그럼 X의 Y승을 하면 무슨 일이 일어나는건가요?

 

 

수학따위는 개나 줘 버린 우리 머리로 간단히 생각해 봐서 .. 2제곱한다고 생각해 봅시다.

0을 2제곱하면? 0이죠?
1을 2제곱하면? 1이네요?

일단 0과 1은 안변한다는걸 알 수 있습니다. 그 중간이 변하는 거겠죠.

0.5를 2제곱하면? 얼마가 나와요? 0.5 * 0.5 가 얼마냐공.

 

 

... 이러면 가끔 2.5 라고 하시는 분 계시는데요. 아닙니다. 0.25예요 -_-;;;
소숫점은 서로 곱하면 곱할수록 수가 줄어듭니다.

괜찮아요 어린이여러분. 그 나이 때에는 모를 수도 있죠.

 

 

넹 0.5를 2제곱하면 0.25가 된다는걸 알았습니다.

즉 0~1 사이에 있는 모든 수 들은 모두 소수점이니까, 
정수로 제곱하면 제곱할 수록 값이 더 작아진다는걸 알 수 있지요.

좋아요. 그럼 이걸 본격적으로 그래프로 그려보죠. 그럼 이렇게 된다는 말입니다.

 

..이렇게 노가다로 말고 공식으로 그리는 법 없나..

올 ㅋ노가다다 ㅋㅋㅋ  

보시면 알겠지만, 그냥 코사인 공식은 밝기 (1.0 ~0.0) 가 부드럽게 줄어드는데,
3제곱 하고 5제곱 하니까 밝은 부분의 영역이 줄어드는 것을 알 수 있습니다 . 내가 이거하려고 엑셀을 꺼내다니

그래프가 더 날카로워진다는 거죠! 그 말은... 어두운 부분이 늘어난다는 거예요! 그러니까 .. 밝은 부분이 좁아진다는 것!
그렇다면...!!! 그렇습니다. 외각선 두께를 조절할 수 있습니다!!!
[각주:9]

백문이 불여일견. 해봅시다.

 

요걸 하는 거예요.

 

제곱은 한 3제곱을 줘 보도록 하지요. 이렇게 하면 결과는...

 

이게 원래 제곱 안했을때

 

이게 3제곱 한 결과

넵 확실히 얇아졌습니다! 3제곱 해서 얇아졌으니, 5제곱 하면 더 얇아지겠지요. [각주:10]

 

이렇게 만든걸 기존의 라이트의 결과물에 더해(+) 주기만 하면 게임에서 흔히 볼 수 있는 림라이트가 되는 겁니다!
한 번 해 볼까요?

여기서 만든 공식이 프레넬 반사(Fresnel Reflection) 공식의 핵심입니다. 즉 이 공식을 아시면 프레넬 효과를 만드실 수 있다는 말씀이지요. 자세한 프레넬 리플렉션에 대해서는 퐁포퐁 퐁퐁 의  http://blog.naver.com/sorkelf?Redirect=Log&logNo=40157708229 에서 보도록 합니다. 말이 좀 어렵긴 하지만 잘 보다 보면 위 공식이 나옵니다.

좀 더 재미있는 글을 보시려면 실버치매님의 이 글을 보시는 것도 좋습니다 .
http://gamedevforever.com/35

 

4. 응용해 봅시다.

뭐 다 아시는 거니까 이건 하나하나 설명 안할께요.
일단 뭐 아까 지웠던 라이트를 다시 만들어 놔야겠고.. (안지우셨으면 그냥 두시면 되겠죠. 이럴때 쓰려고 지우지 말라고 한것임 ㅋ)

기본 램버트 라이트 공식에 림라이트 공식을 더하는 겁니다.
아참 이건 최종 계산된 칼라값 (float3) 를 더하는 거라는게 중요해요. 
왜 그러는지 이해 안되면 고민해 보세요. 이건 숙제.

 

이거 한 번 해보세요. 우왕 뭔가 많아 보인다.  

결과는 이렇게 되면 성공.

 

사실 저 림라이트는 일종의 '역광' 으로. 빛을 등지고 있어야 보이는 효과이긴 합니다. 지금은 빛을 등지는지 아닌지 신경도 안쓰고 그냥 만들어서 더해 봤지요. 제대로 역광을 만드려면  라이트 디렉션과 내 시선 벡터를 dot 연산해서 90도가 넘어가는 시점에서부터 림라이트가 나타나게 만들면 될 것입니다.

이 힌트만 가지고 해 보실 수 있으신 분이라면, 이 강의는 더이상 듣지 않으셔도 됩니다. 당장 포프님 책으로 렌더몽키를 공부하세요 !!!!

 

뭐 혹은 이렇게 응용할 수도 있습니다.

림라이트 연산이 색상 더하기 전에는 float 이라는 것을 이용해서 , 그걸 알파에 넣어 버린다면..?

 

 요렇게 말이죠. 이렇게 한다면

 

뿅. 크하하하 외각만 남았습니다.
음... 근데 빛 안받는 부분이 검은 외각이 남는게 좀 불만이시면  

 

이렇게 렘버트 연산을 아예 날려 버리시고 그냥 단색으로 처리해 보리는 수도 있지요. 이러면 외각만 빛나는 유령 (Ghost) 효과가 나올 겁니다.

 

 

스타크래프트 2에 나오는 맹스크의 홀로그램도 이걸 응용한 거지요.

 

 

또 다른 응용도 가능합니다. 1- 했던 공식을 없애버리면, 저런 효과가 나와요. 외각 엷어지는 효과 말이죠.
이건 적절한 블렌딩과 함께 이용하면 강화 이펙트 같은데 쓸 수도 있는 효과를 만들 수 있습니다 .

 

5. 결론

넹 오늘은 프레넬 반사 구현을 위한 공식의 핵심을 배워 봤습니다. 사실 이 공식의 장점은 이것 뿐만이 아니예요. 응용은 훨씬 더 많이 할 수 있습니다. 반사와 굴절을 적절하게 섞어서 물 효과를 낸다던가... 외각으로 갈 수록 다른 텍스쳐가 나타날 수 있게 한다던가.. 등등 말이죠. 기본적인 dot 공식에서 시작한 공식이 이렇게 발전한다는것 .. 꽤 매력적이죠?

아직 안끝났습니다. 다음 시간에도 또 이 dot 공식 가지고 놀아보도록 하죠 후후후

그럼 여러분 다음 달 까지 안뇽 >_<  

안뇽안뇽

 

jp16강.SFX


 

ps. 출판사와 shaderFX 책을 내 볼까 하고 회의를 했었습니다만... 아시다시피 최근에 이 shaderFX 제작자가 오토데스크 입사했다고 다운로드 경로 막아놓고 잠수 타 버렸습니다. (...) 덕분에 지금 이 내용으로 책을 쓰려는 기획은 무기한 연기중이예요... ㅠㅠ 혹시 오토데스크 본사에 아시는 분 있으면 연락좀 해주세요 ㅠㅠ 게다가 이 사람이 업그레이드 안하면 2013 버전도 안나오잖아요.. 맥스 2014에는 기본으로 포함된다면 얼마나 좋을까요 ... ㅠㅠ

그래서 제작자와 연락이 되기 전에는 책이 나오기 힘들 것 같습니다. ㅠㅠ 다른 툴을 써 볼까 했는데 솔직히 이것만큼 쉽게 배울 수 있을 만큼 쓸만한 녀석도 없구요.

 

  1. 라이트 벡터(Light Vector) 라고도 불러요 [본문으로]
  2. 서피스 벡터 (surface vector) 라고도 부르더라고요. 이거 원 용어가 많아서.. 일본 번역서에서는 '법선' 이라고도 하지요 [본문으로]
  3. 다른이름으로는 뷰벡터(View Vector) , 시선벡터 라고도 부릅니다. 다 같은 말이예요 [본문으로]
  4. 벡터끼리의 연산을 할 때에는 서로 길이가 다르면 연산에서 잘못된 값이 나오기 때문에 길이를 맞춰주는 작업이 필요합니다. 그래서 길이를 1로 맞춰주는 작업을 정규화 (Normalize) 라고 하죠. 또한 벡터의 길이를 1로 맞추면 연산이 무척 간단해 지기도 합니다. 여기서야 자동으로 해 주지만... 실제로 코딩으로 shader을 짤 때에는 이 Normalize 때문에 이상한 결과가 나오는 경우가 꽤 있습니다. [본문으로]
  5. 지금은 기본 구현을 위해 과감히 라이트를 안씁니다만.... 나중에 쓸 데가 있을 겁니다 .. 아마도... 그러니 굳이 안 지워 놓으셔도 돼요.. [본문으로]
  6. 하지만 여러분들이 벌써 해 본 거라는거. [본문으로]
  7. 가끔 '맞게 했는데 저렇게 안보인다!' 라고 하시는 학생분들 계신데, 혹시 User 뷰로 해놓으신거 아닙니까? Perspective 로 하지 않으면 저 효과가 보이지 않습니다. [본문으로]
  8. 이런 노드의 이름은 보통 hlsl에서 쓰이는 함수의 이름과 '비슷' 하게 되어 있는 경우가 많이 있습니다. 툴마다 조금씩 이름은 틀릴 수 있지만, 어쨌거나 함수명인 'power' 는 꼭 들어가곤 한다는 거죠. 그래서 하나 배워 놓으면 다른 툴도 대충 적응이 가능함. [본문으로]
  9. 이전 시간에 숙제로 내드렸던 pow가 이겁니다 . 실제로 액셀에서도 POWER(x,y) 예요. 숙제 해 오신분 계신지?? [본문으로]
  10. 반대로 0.5제곱 하면 넓어집니다 잇힝 [본문으로]
반응형
,