본문 바로가기
Shader

ShaderFX를 이용한, 그래픽 디자이너를 위한 기초 쉐이더 강좌 13강

by 대마왕J 2012. 7. 9.

간만입니다. 그동안 각종 여행에, 발표에, 글 써야 할 일에, 업계에 다사다난한 사건에 -_-;;;
개인적인 환절기 몸살 등등 때문에 제대로 시간을 잡을 수가 없었네요.

그래서 뭐 ... 이번 시간에는 드디어 실습을 해 보도록 하겠습니다.
역시 이론만 쓰니까 리플이 안달리고 막 이래 제길

이론이고 나발이고 그래서 뭐가 어떻게 되는 건데!!! 라고 하시는 분들이 계신 것 같네요.
하긴 저도 그런 속성이긴 합니다만 후후후

그래서 이번 시간에는 드디어 조명을 실습해 보도록 하겠습니다.
여태까지는 조명? 그냥 불 켜주면 밝아지는 것 아냐? 라고 생각하셨을지도 모르겠지만...
이 수업을 들으시면 조명이 그냥 불켜주면 자연히 생기지는 않을거라는걸 감 잡으실 수 있으셨겠지요.
하물며 텍스쳐 하나 입히는데도 샘플러다 UV다 신경써야 하는데, 조명이라고 별 수 있겠습니까?

게다가 솔직히 조명은 제대로 하면 엄청 복잡하단 말이죠.
그래서 이번에도 이론따윗 엿바꿔먹어! 라는 생각으로 일단 실습부터 무작정 해보도록 하겠습니다.
하고 나서 필요할 때 이론 설명하는게 낫지요 여러분???

 

그쵸오? 때릴꺼야?

 

1. 그래도 조금 더 알아야 하는 지식 - 노말벡터

죄송합니다. 그래도 이론 조금 더 해야 하네요..
Normal 이라고 하는 녀석이 있습니다.

그래픽 하시는 분들은 노말맵이라는 이름으로 익숙할텐데요. 그렇다고 Normal이 뭐예요? 라고 갑자기 대놓고 물어본다면
에 ? 하시는 분들이 많지용.

 뭐 여기까지는 그냥 반짝반짝. 그냥 좀 에또... 그게... 라는 느낌. 알긴 아는데 뭐라 설명하지? 라는 그런 느낌 말예요.

에? 그, 그거 .. 그냥 노말맵이라고 울퉁불퉁하게 하는 거 말하는 건데요...

 그런데 거기다가 공돌이들이 쓰는 용어같은 '벡터' 라는 용어를 붙여서 , '노말벡터가 뭐예요?' 라고 물어본다면

"으, 으으으악 저리 치워!! 저리가!!" 라고 하시는 분들도 생깁니다.

공돌이다! 공돌이가 나타났다!!!  

뭐 이해합니다. 어떤 그래픽 책에서도 노말벡터를 "제대로" 노말벡터라는 이름으로 설명하지 않았으니까요.
하지만 지금 우리처럼 조명을 만지려면, 프로그래머만큼 알지는 못하더라도 개념은 대충 알고 있어야 합니다.

 

3D max를 좀 다뤄보신 분들은, 솔직히 다 알고 계세요. 그걸 노말벡터라고 부르지 않았을 뿐.
그럼 어디 한 번 볼까요.

3D max를 켜 봅시다. 공을 하나 만들까요.  

보기 편하게 하려고 폴리곤은 좀 적게 만들었어요.

이 공을 선택하고 모디파이어에서 Edit Normals 를 선택해 보시면 Normal을 보실 수 있으십니다. [각주:1]

 

흐, 흥! 못찾을까봐 사진 올려준거 아니라능!!!

그리고 이걸 선택하면, 옛날 유명한 공포영화인 헬레이져의 한 장면처럼 돋아난 가시를 보실 수 있게 되실 겁니다.

 

이게 누군지 알면 당신은 30 중반

 

저거예요 저거! 저게 노말이예요! 저게 그리고 바깥으로 향한 화살표 모양이면 그게 노말벡터라고요!!![각주:2]

저거는 그냥 노말을 보여주는 거고... 저게 노말벡터라고 불리려면 방향이 있어야 합니다.
그래서 화살표 모양이라고 한 거구요.

노말이라고 하는건, 그냥 이론 따지지 말고 대충 말하자면, 면이나 점의 수직방향, 즉 로컬의 Z 축이라고요.
평평한 책상의 노말벡터는 위로 솟아있겠죠 똑바로. 그렇게 수직되는 방향을 말하는 겁니다.

 

그리고, 심지어는 여러분도 모델링할때 많이 써 와서 이미 개념까지 알고 계세요. 다 아시는 겁니다. 

 

위의 그림 많이 익숙하시죠? Extrude 명령 줄 때 옵션에 심지어 Local Normal 방향이라는 옵션도 있잖아요?
이것 말고도 Normal 이란 용어는 심심치 않게 3D max 안에서도 사용되고 있습니다.

프로그래머들이 '그래픽 아티스트들은 노말이 뭔지 몰라' 라고 하는 것도 사실 틀린 말이라는 거지요.
그래픽 아티스트들은 이미 '몸으로 알고' 있었습니다. 그걸 말로 표현 못했을 뿐

뭐...  그러면 그동안 알고 계시고 심지어 잘 쓰시고 계시던 명령에 Normal이 흔하게 쓰이고 있었다는 것도 알게 되었습니다. 그러면 할 얘기는 더 많지만, 복잡하게 설명하지 말고 간편하게 그냥 한 가지만 더 얘기하죠.
아까 normal은 버텍스에 하나씩 존재했었습니다.

그쵸? 버텍스에 하나씩 있어요. 이걸 보통 버텍스 노말(vertex normal) 이라고 부르는데요.

그렇다면 픽셀노말 (pixel normal) 이라는건 뭔지 짐작 가능하신지요?

 

넹, 한 픽셀 픽셀마다 노말벡터를 하나씩 가지고 있다는 뜻일겁니다 짐작하신대로.

픽셀 노말은 max에서 볼 수 있는 방법은 없습니다. 상상해야 해요.
뭐 상상하면 뻔하겠죠. '털난 공' 같을 겁니다. 그쵸? 한 픽셀마다 저 선이 하나씩 나와있다고 생각해보면.. .으으..

 굳이 비슷하게 보자면 이런 느낌..?[각주:3]

이거... 보다도 몇 십배 더 빽빽하겠죠. 으으으 징그러워...

대충 이 정도까지 이해하시면 그래픽 아티스트로서는 무리없습니다.

이걸 네이버 백과사전 뒤져보면 이렇게 나오니 알아먹을 수가 있어야지...

http://www.scienceall.com/dictionary/dictionary.sca?todo=scienceTermsView&classid=&articleid=251322&bbsid=619&popissue=


 나한테 왜이러는 건데

 

이렇게 노말은 버텍스 노말과 픽셀노말이 있습니다. 그리고 이 노말벡터들은 조명을 계산할때 매우 중요하게 사용되지요.
버텍스 노말로 계산된 조명은 버텍스 라이트 (Vertex light) 라 불리고,

픽셀 노말로 계산된 조명은 픽셀라이트 (Pixel light) 라고 불리거든요. [각주:4]

 

왼쪽이 버텍스로 계산된 specular, 오른쪽이 pixel로 계산된 specular입니다. 확실히 다르죠. [각주:5]

꼬치꼬치 재미없는 얘기 또 해서 죄송합니다. 그럼 진짜로 조명계산을 한 번 해 볼께요.

 

2. 조명 계산하기 준비

일단 맥스를 켜셔야죠. 그리고 준비해야 할 것이 있습니다.

조명과 오브젝트죠.

아주 만만한 주전자를 하나 만들어 두고, 조명은 Standard light 에서 Target Directional Light를 하나 만들었습니다. [각주:6] [각주:7]

 준비가 끝났으면 shader FX를 열어야죠.
shader FX가 실행되면 기본으로 나오는 메터리얼이 있습니다. 선택하고 과감히 삭제합시다. 이번엔 이거 안써요.

삭제해주세요

 그리고 shader FX 의 빈 화면에서 오른쪽 클릭하고, Material / Advanced를 선택합니다.

 그러면 뿅 ... 하고

Advanced material이 나타납니다.

 

자.. 봅시다. 아래쪽 메뉴를요.  좀 더 자세히 말이죠.

 

일단 나머지는 신경 쓸 필요 없고, 이것만 보면 됩니다.

Ambient Pass (nolight)는 말그대로 라이트가 없는 결과물을 float3로 (녹색이니까요) 받습니다.

One Pass per Light는 한 개의 라이트당 한 패스[각주:8] 를 쓴다는 말입니다. 이건 다른 말로  포워드 렌더링 (Forward Rendering ) 이라고 해서, 가장 흔하게 쓰이는 전통적인 렌더링 방법입니다. [각주:9]

Alpha 는 float 이네요. 이건 말 그대로 알파 채널을 받는 것으로 보입니다. 따로 받네요? 싱기해라.

All Light in one Pass 는 아마도 모든 라이트를 모아서 맨 나중에 한번에 그린다는 것으로 보입니다. 이것은 최신 (지금은 좀 아니지만 그래도 상대적으로) 방식인 디퍼드 렌더링 (Deferred Rendering) 으로 보입니다만... [각주:10]

지금 우리가 쓸 방법은 뭘까요?
프로그래머들이 shader를 배울 때에도 맨 처음에 시작하는 방식인, One Pass per Light (Forward Rendering) 입니다.
그러므로 최종 출력된 결과물은 float3로 만들어서 거기다가 넣어주시면 되겠지요?

 

3. 조명 계산을 시작해 봅시다.

자 그럼 일단, 늘 하던 짓을 먼저 합시다.
메터리얼과 오브젝트를 같이 선택하고, Tools / Assign Material to Selection 을 해줘서, 메터리얼을 주전자에 입혀줍시다. 늘 그렇듯 하얗게 변합니다. 아무것도 없어서요.  

예전 메터리얼 같았으면 어땠을까요?
여기서 예전 메터리얼이었으면, Diffuse에다가 칼라 하나만 연결해 주면 알아서 빛이 계산되어 나왔었지요?

 

그치만 지금은, 칼라를 연결했는데도 그냥 단색 칼라만 나옵니다. 아아아아아아아....

네, 이게 다른 겁니다. 예전에 쓰던 메터리얼은 라이트 계산 같은건 알아서 해주던 녀석이었습니다. 자동차로 비유하자면 '오토' 기어 차량이랄까. D에다가만 넣으면 알아서 가는... 

그렇지만 지금 만든 Advanced한 메터리얼은 '메뉴얼' 기어 차량 같은 느낌이어서 , 일일히 값을 넣어주지 않으면 안움직이는 녀석입니다. 귀찮은 대신에 어떨까요? 뭔가뭔가뭔가 성능이 좋겠지요? [각주:11]

자....... 여기서 그동안 배웠던 이론이 나옵니다.

일단 알고 있는게 이거였었죠

빛이랑 직각이 되는 부분이 가장 밝다.[각주:12]

빛이랑 직각이 되는 부분이라... 그러니까 이런 부분이죠.

 

이런 면이 가장 밝을 겁니다. 평면이 기울어지면 밝기가 떨어질거구요.

조명은 Direct Light이므로, 위치와 넓이는 상관없지요.
DIrect Light는 이런 조명이니까요

시작도 없고 끝도 없으시며 그 넓이도 존재하지 않으시고,
오직 한 방향만 존재하실 뿐이어다.

지저스돋네

뭐, 좋아요. 이제 이걸 벡터를 이용해서 표현해 봅시다. 가장 밝을 때는 벡터가 어떻게 될 때라고요?

 

여기서 평면의 벡터는 바로 노말 벡터.

오호라.....  

이것 봐라?

 

이제 대충 눈치 채시는 분들이 나올 것 같은데요... 그래요, 조명의 방향을 나타내는 조명 벡터 (일명 라이트 벡터 Ligjt Vector) 와 평면의 방향을 나타내는 노말벡터 [각주:13] 가 서로 마주보고 있으면 가장 밝게 되는 겁니다.
그리고 이것을 뭐라고 말하냐면,

밝기가 1.0이다

라고 말합니다. [각주:14] 우리는 이제 이렇게 생각하기로 했지요? 모든걸 0에서 1사이의 숫자로 말입니다.
즉 빛 밝기도 숫자로 보여야 한다는 말씀. 중요해요. 자 다시 한 번 집중해 봅시다.

 

그럼 좋아요. 그래픽 아티스트 여러분, 생각해 봅시다. 
아래 경우는 밝기가 어떠겠습니까? 벡터가 서로 45도 기울어졌을때 말입니다. 밝기가 얼마일까요?  

 넹 밝기는 0.5 일겁니다. 
45도면 반쯤 어두워지는 거지요.     ********* 틀립니다. 사실은 0.5 아닙니다. **********************

그럼 아래와 같이 90도가 되면 밝기가 얼마일까요?

그렇죠! 밝기는 0 입니다. 까맣게 되는 거예요.
빛이 있어도 안밝아요. 그냥 막 생각해 봐도 그럴 것 같잖아요.  

이걸 계산하면 되는 거지요.
다시 한 번 정리해 볼께요.

보통 이 계산은, 계산의 편의를 위해 조명 벡터를 뒤집습니다.
그래서 조명의 벡터가 조명에서 평면으로 가는 화살표가 아니고, 평면에서 조명으로 가는 화살표로 표시되지요.

그렇게 해서 한 방에 정리해 보면 이렇습니다.

평면벡터는 어딘지 이제 다 아실테니 조명 벡터만 보자면,

 

이런 느낌이 되겠지요. 슬슬 이해 가시지요? 이제 다르게, 풀 버전으로 한 번 볼까요?

짜잔~

네 그렇습니다. 노말 벡터와 조명 벡터를 뭔가로 계산해서, 서로 각도 차이가 0일때는 1이 나오고, 45도 차이일때는 0.5가 나오고, 90도 차이일때는 0이 나오게 하면 될겁니다.

 

************ 45도일때는 cos

그리고 소개하겠습니다 그 공식을.

사실 제대로 설명하려면 sin 그래프부터 보여드려야겠지만, 할 수 있다면 내적이 왜 sin 그래프 모양인지 증명까지 해야 겠지만, 그건 필요하면 나중에 할께요. 지금은 급해요 급해 ㅎㅎ
그냥 공식 이름부터 말하고 말께요. 더 설명했다간 맞아죽을것 같아

그 공식이란 벡터의 곱셈인 dot 공식입니다.[각주:15]

('닷' 이라고 부르죠. 좀 더 유식하게 '닷 프로덕트(dot product)' 라고 프로그래머에게 말하시면
프로그래머가 놀라면서 존경의 눈빛을 보내게 될 것입니다 후후후)

그럼 무작정 계산해 보도록 하겠습니다. 이미 이론이 너무 많이 나와서 325분이 쓰러지셨어요. 아아 죄송합니다. 반성하겠습니다.

 

닥치고 실습하겠습니다. 죄송합니다.

 

 자 주둥이가 찢어지기 전에 시작해 보죠.
아래 화면에서부터 시작입니다.

 벡터 두 개가 필요하죠. 조명벡터부터 갑니다.

 조명벡터는 들어오는 거니까 Input에 있겠죠. 우리가 만든거 아니잖아요? 받아오는거지.
보니까 있네요. 선택합시다.

 부왘ㅋㅋㅋ 나 정말 Shder FX 아이콘 디자인 정말 좋아요. 누가 한거야 이거 ㅋㅋㅋ
근데 화살표 방향은 거꾸로 된게 아닐까 합니다 .조명에서 평면 방향이 아니라 평면에서 조명 방향이 아닐까요. 계산하면 그렇게 나오는데, 아이콘 그림은 저렇게 되어 있어서 조금 의문입니다 .어쨌건 신경쓰지 말고 갑시다.

이번엔 평면벡터, 즉 노말벡터를 받아와야죠. 역시 Input을 보니까 Surface Vector가 있습니다. 부담없이 가져다 쓰지요. [각주:16]

 가지고 왔습니다 . 역시 아이콘은 직관적입니다. 그림만 보면 뭔지 다 알거 같다능

 그럼 이제, 두 벡터를 연산하는 Dot 이란걸 불러봅시다.
math에 보니까, DotCrossProduct 라는게 있네요!!! Dot과 Cross라고 하는 (내적, 외적) 벡터의 연산을 처리하는 함수 같은 녀석입니다! [각주:17]

 부왘ㅋㅋㅋ 아이콘 봐 ㅋㅋㅋㅋㅋ

자 이제 필요한 것들이 다 모인 것 같습니다. 연결해 보죠. 두 벡터를 dot 시켜 줍니다.

 

응? 그런데 dot에 있는 출력부인 Result가 파랑색입니다. float 인거죠. float3가 아닙니다.
그렇죠, 위에서 봤던대로 dot 공식을 적용하면 0.0~1.0 까지의 한 자리의 숫자만 나오는 겁니다. 밝기를 나타내는 float이 나오는 거지요. [각주:18]

뭔가 더 필요합니다. float 이 float3로 변할 수 있는 무엇이...
그럴땐 만만한게 Color지요!

그래요, 생각해보니 빼먹은게 있었네요.
빈 화면에서 오른쪽 클릭을 하고 Input 에서 LightColor를 선택합니다. 조명 색상이 빠졌잖아요!!!

부르는건 좋았습니다만... 이걸 더해야 할까요 곱해야 할까요? 이거 숙제입니다. 3분 드릴테니 생각해 보세요.

 

 

 

 

 

 

 

 

 

 

 

 

 

자 정답은?

곱하기 였습니다.

당연하잖아요? 더해 버리면 어두운 면이 아예 안나오고 하얗게 질려버릴 겁니다.

 

 자, 그럼 최종 결과를 보겠습니다.

잘 나왔습니다! 빛의 밝고 어두움을 표현하는데 성공했어요!!! 크흑

이걸 램버트(Lambert : 람베르트) 공식이라고 합니다.
조명 색상을 바꿔 보시고, 각도도 바꿔 보시지요. 잘 동작해야 정상입니다.

이렇게 당연하다고 생각하는 것을 직접 만들어 보니까... 마치 우리가 아무런 생각없이 방에 불을 켜지만, 우리가 직접 전구를 만든다면? 이라는 생각이 들지 않습니까?
그러므로 오늘의 교훈은 전기절약

 

자, 다음 시간에는 조금 더 발전된 조명을 배워보지요. 그러면서 이론을 살짝, 아주 살짝 더 배워보도록 하겠습니다.

 

그러니까 , 여러분 다음 달 3일까지 안녕~

 

* 최근 필자 사정으로 연재주기를 1달로 늘였습니다. 건강문제와 집안/회사일/외부일 때문이죠 뭐.
안정되면 갑자기 연재주기를 줄일 수도 있습니다. 내맘임.

  1. 역시나 3D 그래픽 아티스트들에게는 매우 쉬운 메뉴라서 자세히 설명 안했습니다. [본문으로]
  2. 벡터이면서 길이가 1인 것들이 주로 사용되는데요, 이것을 '단위벡터' 라고 하며, 노말라이즈(Normalize) 했다라고도 합니다. 각종 계산에서 편리해지기 때문에 거의 모든 벡터 계산은 이걸 기본으로 합니다. [본문으로]
  3. 이건 사실 세그먼트를 200까지 올려서 만든 이미지입니다. 여러분들의 이해에 도움이 되게 하기 위해서 말이죠. 그러므로 실제로 픽셀 노말은 더 빽빽합니다. 그냥 공으로 보일 정도로... [본문으로]
  4. 우리는 일단 Pixel light를 배웁니다. 요샌 vertex light 쓸 일도 거의 없어지는 것 같아요... [본문으로]
  5. 사실 normal에 대한 이론은 더 말할게 많이 있습니다만 여기서는 넘어갈께요. 빨리 해보고 싶어서 근질대시잖아요? [본문으로]
  6. free Directional light를 쓰셔도 상관 없습니다. 단, spot이나 omni light는 사용하지 마세요. [본문으로]
  7. 저는 평소에 프로그래머들 책을 볼 때, '이런 기본적인 것은 알겠지' 라고 쓴 글에 많이 좌절했던 사람입니다. 그래서 그 복수로 3D max 를 이 정도는 알겠지 라고 옹졸하게 글을 쓰고 있습니다. 이히힛 [본문으로]
  8. pass 란, 한 '사이클' 정도로 생각하시면 됩니다. '한 패스를 돈다' = '한 사이클을 돈다' = '한 과정을 돈다' = '한 번 첨부터 끝까지 그린다" [본문으로]
  9. 한 조명당 한 번 그리므로, 조명이 많아지면 많아질 수록 여러 번 그리는 방법입니다. 당연히 조명이 많으면 기하급수적으로 느려집니다. [본문으로]
  10. 어쨌건 최신 게임에서는 이 렌더링 방식으로 조명연산을 가볍게 만들기도 합니다. [본문으로]
  11. 성능이 좋은건 나중에 봅시다. 지금은 일단 1단에 넣고 앞으로 가기나 해야죠. [본문으로]
  12. 물리적으로 따지고 들어가면야 여러 가지 얘기가 나옵니다만, 우리 그래픽 아티스트들이 원하는건 정확한 물리기반의 광자이론이 아닙니다. 그저 '우리 그림을 이쁘게 하기 위한 정도의 지식' 이지요. [본문으로]
  13. 3d에서 엄밀히 얘기하면 버텍스 벡터라고 해야 할 거 같은데 일단 이렇게 설명을 해버리지만 나중에 어떻게 꼬일지 나도 모르게... [본문으로]
  14. 간만에 보는 0과1입니다. 늘 얘기했지만 shader는 0과 1이 사이에서 끝나요 [본문으로]
  15. 벡터의 곱셈은 두 가지가 있습니다 하나는 dot (내적) 이고 하나는 cross(외적) , 이지요. 제 수업때 cross를 쓸 일은 ..... 없겠군요. 후후후 [본문으로]
  16. 보시면 알겠지만, 여러 가지 용어가 혼용되어 사용되고 있습니다. 노말벡터, 평면벡터, 표면(Surface)벡터, 픽셀벡터... [본문으로]
  17. 프로그래머들 세계에서는 띄어쓰기를 잘못하면 문제가 되는 경우가 꽤 있습니다. 그래서 띄어쓰기를 안하고 대문자로 띄어쓰기를 대신하고는 합니다. 즉 Dot Cross Product 라고 씌여진 거지요. [본문으로]
  18. 어지러울까봐 미리 말씀 안드렸습니다만, 사실 dot을 적용하면 -1.0~ 1.0 까지 나옵니다. 지금은 음수가 무시되는 옵션이 켜져 있어서 0~1까지만 나오는 겁니다. [본문으로]
반응형

댓글