본문 바로가기
Shader

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

by 대마왕J 2012. 8. 17.

예압. 잘 계셨었었었나요???!?

15강의 시간이 돌아왔습니다! 힘세고 강한 15강!

 

만약 내게 물어보면 나는 대마왕.

 

요새 계속 좀 어려운 얘기를 하고 있는 것 같습니다.

제가 얘기했잖아요 ㅋ 초반 10강 까지가 커피면, 10강 이후부터는 T.O.P입니다 ㅋ
확실히 슬슬 중반까지는 온 것 같은데... 나름 길게 천천히 설명했다고 생각했으면서도 사실은 너무 급하게 들어간게 아닐까 라는 생각이 듭니다.

중간에 흑백 이미지 만들기라던가 그런거 한 두 번 더 들어가서 좀 더 익숙해 지게 만들었어야 하는 게 아니었나..? 싶었다는.

일단 dot 나오면서부터 좀 수준이 달라져서 말이죠. 으흠. 뭐 그렇지만 이왕 시작한거 일단가고...

일단 생각해 둔건 이제 노말맵에 대한 설명... 그리고 스페큘러에 대한 설명... 정도까지 생각하고 있습니다.
렌더타겟이 안되니 더 깊은 수준도 애매하고... 반사벡터를 이용한 큐브맵? 아... 이건 1부에 했었어야 했구나....
1부에 큐브맵과 흑백/세피아 만들기를 했어야 했던 것 같아요. (아닌데 큐브맵 반사벡터 제대로 설명하려면 1부에 안되는데 아이씨... OTL 뭐야 몰라 무서워)

여기에 감마 코렉션이나 HDR 같은, 중요하지만 실습하기는 엄청나게 곤란한 그런 것들까지 할 수 있으면 얼마나 좋을까.. 라는 욕심이 들지만 뾰족한 방법이 생각나지 않는다는게 문제입니다. 뭐 저도 HDR을 사용할 줄만 알지 구현해 본적은 없기도 하고 ㅋㅋㅋ 에이 몰라 일단 노말맵과 스페큘러까지만 해도 거의 책 한권에 달할 분량이므로 거기까지 하고 나서 생각해 보렵니다.

자, 오래간만에 말씀드리지만, 이 강의는 '그래픽 아티스트를 위한 ' 강의입니다. 그래서 설명이 지나치게 자세하고, 다소 뛰어넘는게 있더라도 어떻게 하면 쉽고 재미있게 배울 수 있을까에 중점을 둔 원고입니다. 그 점 잊지 말아 주세요. 이해 안되는건 바로바로 리플 달아 주시구요.   

 

자 그럼...

오늘은 지난 번에 이은, '진짜 재밌는' 부분인 Dot 연산의 응용에 대해 계속 얘기해 보겠습니다.

 

1. 지난 강의의 줄거리

 

잊어버리셨을지도 모르지만...

저번 14강의의 핵심내용은 아래와 같죠.

dot(닷) 연산이란 것이 있고, 이걸로 '-조명 벡터'와 '노말벡터' 두 벡터를 연산하면, [각주:1]

두 벡터의 각도 차이에 따라 값이 다르게 나오는데, 대충 아래처럼 나온다는 것이었습니다.  

이 값은 코사인 그래프로 나오는 거라서, 그래프로 표현하면 아래와 같은 모양으로 나오게 되지요.

코사인 그래프처럼 살짝 휘었지요?

그치만 오늘 중요한건 그게 아니라

나오는 값이 1에서 0까지가 아닌,
1에서 -1 까지 나올 수 있다는 것입니다.

 

잊지마라!!!

 

 

여기에 일단 주목해야 해요.

일단 평소 계산할 때는 이 음수값이 오히려 오류가 날 수도 있는 귀찮은 값이라서 ,
음수가 안나오는 옵션을 켜고 계산을 합니다. [각주:2]

 

오늘은 이 봉인을 풀어서 재미있는 짓을 해 보겠습니다!!!

 

아따 재밌것다

 

 

2. 하프 램버트

시작의 발단은 자기네 자료란 자료는 전부 공개하기로 크게 유명하고, 하프 라이프라는 게임으로는 조금 유명한 ㅋ  대인배 밸브 횽아들께서 시그래프 2006년에 발표한 자료에서 시작합니다.

https://developer.valvesoftware.com/wiki/Half_Lambert

 

영어다 ... 영어야... 이히히히히

 

더 뭔 소린지 모르겠어

 

네, 저도 영어만 보면 머리가 멍해져요. 보통 이런거 공부하시는 아티스트 분들도 그렇잖아요. 영어 좋아하시는 아티스트분 얼마나 될까나. 난 지금 아티스트라고 보기도 애매하면서 영어보면 머리아프면 뭐지

그래도 공부해 보겠다고 막 찾아보면, 이런 글이 찾아지죠.

 "램버트 라이팅은 확산반사의 음영처리로 많이 알려진 일반형으로, 시선 방향에 의존하지 않고 광원의 입사방향과 면의 방향(법선 벡터)만으로 계산되는 음영처리 기법이다. 이 기법에는 「그 지점의 밝기는, 면의 방향과 빛의 입사 방향이 이루는 각도θ의 cosθ값에 비례한다」라는 「램버트 코사인법칙」이 정의되어 있지만, 실제로 이것으로 라이팅을 하면 명암이 매우 강렬하게 나오는 특성이 있다.하프라이프2에서는, 이 심하게 변하는 코사인 곡선에 바이어스를 걸어 어두운 부분의 계조(단계영역)를 들어 올리는 생각을 했다. 램버트 코사인 법칙의 코사인 곡선이 절반이 되도록 "1/2"을 곱한 다음, "1/2"을 더하고, 다시 이것을 제곱해서 완만한 곡선으로 변환해서 음영처리를 실시하기 때문에 「"하프" 램버트 라이팅」이라고 한다."

http://allosha.tistory.com/57 에서 인용합니다 .

... 솔직히 저렇게 글쓰는거 이해 안가요. 저거를 알아들으라고 쓴 건지 자기만 알아보려고 암호로 쓴 건지. ㅋ. 
솔직히 그래픽 아티스트들이 알아보기 힘들게 하려고 프로그래머들이 일부러 저렇게 꼬아서 쓴 게 아닐까 하는 음모론이 대두되고 있습니다.  

 

 

그러므로 이런 글을 읽고 나면 우리는 ,

더 뭔 소린지 모르겠어

 

이렇게 됩니다. 늘 이래왔었죠.
이것보다 더 큰 문제는, 일단 몇 번 읽어보고 이해하려고 노력한 후에...

   

"자기 블로그에 이 글을 그대로 복사해 가서 공부한 것인 양 붙여놓고서는, 언젠가는 읽어봐야지 라는 마음을 가진 채 블로그를 조용히 덮고 다시는 열어보지 않지요." [각주:3]

 

 

.....

 

 

 

 

... 자 너무 좌절하시지 말고, 오늘은 그 굴레를 좀 벗어나 보도록 합시다.

 

 

 

3. 하프 램버트는 왜 필요하게 되었는가?

...뭐 자기들이 필요하니까 필요했겠죠. 사실 이게 정답입니다 ㅋ
그렇지만 이렇게 말하면 수업이 안되니까, 일단 이거부터 만들어 보죠.

 

흔한 일반 램버트

 

 

네 지극히 단순한 램버트 공식입니다. 일반적인 라이트이지요.

근데 말입니다. 근데 말이죠.  또 근데 말이죠.

이 라이트 뭔가 좀 구린 것 같지 않아요?

 

그러니까 좀 자세히 보면, 저기 어두운 그림자로 떨어지는 부분, 그 부분이 너무 딱 떨어져 보이지 않느냐고요.
프로그래머들처럼 매정해 보이지 않냐고요 ㅋ

 

 

"괜찮은데 뭐" 라고요?

하긴, 많은 프로그래머들이 초기에 그렇게 얘기했죠 (사실 지금도 많은 프로그래머들은 '괜찮은데 뭐' 라고 말합니다 ㅋㅋ )

그렇지만 우리는 아티스트들이니까, 그렇게 생각하면 안됩니다.
여러분은 이미 이거를 보신 분이잖아요.

이거요 이거.

max에서 스카이라이트 걸고, 라이트 트레이서로 단순하게 건 이 이미지.
그림자도 없지만 이 이미지를 한 번 보고 나면,

 

이 이미지가 멋져 보이지는 않을거 아녜요.

물론 계산 자체의 양이 다르다는건 잘 알아요. 라이트 트레이서 사용하면 저기 위의 이미지 렌더링 하는 것도 한 장에 5초 정도 걸리는데, (제 컴에서) 아래 이미지처럼 게임용(Lambert:램버트)으로, 실시간으로 그리려면 적어도 1/30 초에 그려야 30프레임으로 나올테니까요. 계산 차원이 다르죠.

 

그런데 그렇게 하니까, 이미지가 너무 뭐랄까. 음영이 딱딱하게 져서 안이쁜거예요. 특히 캐릭터에서.

 

램버트를 이용한 캐릭터 조명.

 

캐릭터가 캐릭터처럼 보이게 하는 기법은 사실 굉장히 많고 복잡해요. 사람 피부가 마네킹과 다른 이유는 빛의 반사와 흡수, 투과 등이 완전히 다르기 때문이거든요. [각주:4]

 

아... 구글 검색한 사진인데.. 언젠가 제가 찍어야 겠군요..

 

사람이므니다 사람 2 이니므니다 우리 집 쌍둥이들이므니다 ㅋㅋ 맥락없는 딸자랑 ㅋㅋㅋ

근데 그것 이전에, 일단 빛의 음영부터가 영 아니예요. 아시다시피 실세계에서 저렇게 딱 끊어지는 조명이 나타나는 경우는 거의 없잖아요. 있다면 아주 강한 조명을 쓴 스튜디오 사진 정도?

그러니까, 꽤 어두운 배경에서 왠만큼 강한 조명으로 일직선으로 때리면서 조명을 조절하지 않는 한 저런 환경이 나타니기는 좀 힘들어요. 보통은 강한 빛을 때리면 그 빛이 주변에서 튕겨나와서 다시 뒷면을 밝게 비춰주죠. [각주:5]

게다가 아까 얘기한 것 처럼, 사람 피부라는게 그렇게 딱 끊어지는 확산광을 내놓지도 않아요. 플라스틱이라면 모를까.

 

사람이 아니므니다

 

 

네네 이렇게 여러 가지 이유로, 결론내자면

 

저건 마네킹

주저리주저리 설명하면 뭐해. 마네킹 같고 하여간 싫잖아요.

 

저걸로도 괜찮다고요? 뭐 괜찮을 수도 있겠죠. 네네 전 이해해요. 사람의 가치가 다 똑같은건 아니잖아요.
음영이나 재질같은게 뭐가 중요하겠어요. 그림만 제대로 있으면 되잖아요.  

그러니까 이것도 괜찮으시잖아요 . 그렇죠? ㅋㅋ 게임에는 흔한 빌보드 기법이잖아요.

 

그렇지만 사실은 어쨌건 '저건 구린' 거죠. 구려요.

 

픽사의 초기 작품이 지금 보면 구려 보이는 이유도 , 바로 그 조명의 반사와 투과 때문이잖아요.
근데 사실 게임도 딱 이 전철을 밟아 나가고 있는 거지요. 다른 점이라면 '속도' 가 중요하달까...

 

넹 얘기가 잠시 딴데로 샜는데, 어쨌거나 캐릭터가 나오는 장면에서, 저렇게 '딱 끊어지는 음영이 나오면 안이쁘다' 에서 시작해서, 그걸 개선하고자 밸브 사에서 제작해서 하프-라이프(Half Life) 에서 사용한 램버트 (Lambert) 변형 기법이 바로 하프-램버트 (Half Lambert) 입니다.

물론 이것만으로 캐릭터의 피부 느낌이 해결되진 않지요. 피부의 반사나 투과는 여기서는 완전히 신경쓰지 않고, 그냥 빛 떨어짐만 신경쓰자는 겁니다.  

 

램버트를 이용한 캐릭터 조명.   

 

 

4. 하프 - 램버트 만들기

뭐 알겠습니다. 막상 들어보니까 일단 시작한 이유는 쉽게 알 수 있겠죠? 그냥 '안이쁘니까 이쁘게' 가 모든 일의 발단인 겁니다.[각주:6]

어려운 것 같지만, 이거 사실 굉장히 쉬워요. 게임이라는게 속도에 민감하기 때문에, 사실 어려운 공식을 이렇게 간단하고 쉽게 만들어 내는게 진짜 기술입니다 :)
그래서 그래픽 아티스트들도 쉽게 따라 할 수 있지요. 한번 해 보겠습니다!!

 

자, 시작은 여기서부터입니다.

반도의 흔한 램버트지요. 조명 벡터와 노말벡터를 닷 시킨 후 그 결과물을 라이트 칼라와 곱해준 것을 볼 수 있습니다.

 

우선 해줘야 할 일은, DOT 공식을 선택한 후에, 음수값 제한을 풀어주는 겁니다 .

이제 어두운 부분이 무조건 0이 아니라, 음수값이 나오기 시작하는 거예요. [각주:7]

음수값이 나오기 시작!!! 1에서 -1 까지!!!!

 

눈으로는 별 변화 없습니다만... 이제 dot 값은 위 그림처럼 나오고 있을 겁니다. 
최대값이 1.0 이고, 최소값이 -1.0 인 값으로요.

네. 그러면 진짜 핵심을 한 번 저질러 보죠.

가장 중요한 마법의 주문을 가르쳐 드리겠습니다.
자 모두 따라서 외쳐 보세요! 마법의 주문입니다!!!

*0.5 -0.5

 

이게?

 

이게 왜 마법의 주문이냐고요?

잘 모르시겠다고요?

자, 다시 한 번 다른 그림으로 보여드리죠. 현재 이 상태란 말입니다. 각 지점의 값이 대에에에충 저런 상태예요. 
  

이 수치에 위의 공식을 대입해 보죠.

  1.0 일때 :  1.0 * 0.5 + 0.5 = 1.0
  0.5 일때 :  0.5 * 0.5 + 0.5 = 0.75
  0.0 일때 :  0.0 * 0.5 + 0.5 = 0.5
-0.5 일때 : -0.5 * 0.5 + 0.5 = 0.25
-1.0 일때 : -1.0 * 0.5 + 0.5 = 0.0

놀랍게도, 1.0 ~ -1.0 이었던 수치가, 1.0 에서 0까지로 변했습니다! 이 간단한 공식만으로 말이죠!

 

이제 갑자기 이해가 가는 코사인 그래프..

 

만약 이것을 dot 의 공식 그래프인 코사인 그래프로 보자면, 1에서 -1까지의 범위인 빨강색 그래프가, 1에서 0까지의 범위인 파랑색 그래프로 "끌어 올려진" 결과가 나오는 것이겠지요! 그야말로 마법(Magic)같은 공식이라고 할 수 있겠습니다! [각주:8]

[각주:9]

훌륭합니다.

 

자, 그럼 뭐 이론은 알겠으니까, 이걸 적용하면 어떻게 되는지 한번 보겠습니다.

 

시작은 여기서부터 시작합니다. dot으로 나온 저 결과물에서부터 말이죠.

 

Maps / constant 로 상수를 두 개 만들어 줍니다. 값은 0.5로 넣어 놓지요. 0.5 두 개가 필요하니까요

 

Math/MathOperator 를 이용해서 dot 결과물에 0.5를 곱해주고, 0.5를 더해줍니다. 간단하죠?
이렇게 해서 *0.5+0.5 가 완성되었습니다. 이제 결과물을 볼까요?

 

짜잔.

이전의 그림과 비교해 보세요. 뭔가 어두운게 상당히 뒤로 밀려났죠?

결과물은 어떻게 보이게 될까요?

비교해 봅시다.

 

일반 램버트

하프 램버트

어떻습니까? 어느게 더 '고급 렌더링 처럼' 보이나요? 어떤게 더 글로벌 일루미네이션 기법이 들어간 것처럼 보이나요? 어떤게 더 주변광이 반사되어 영향을 끼친 것 처럼 보이나요?

  

어떤게 위의 그림의 '스카이라이트' 를 이용한 라이트 트레이서의 결과물과 비슷해 보이나요????

 

두 말 할것 없이 하프 램버트 쪽이 훨씬 더 괜찮아 보입니다. 빛도 부드러워 보여요. 단지 0.5를 곱하고 0.5를 더했을 뿐인데 말이죠. [각주:10]

물론 이건 물리적으로는 완전히 말도 안되는 계산 방식입니다 .
이것은 그냥 '좀 더 이쁘게 보이도록' 하는 꼼수로, '마치 GI 라이트를 받은 것 같은 효과'를 가상으로 내기 위해서 만든 공식인 것입니다. Fake 라고요.

 

 

자, 어쨌건 그럼 이렇게 구현해 보고 아래 PT 문서를 한번 더 봅시다.

이제 이해가 되시죠????

하프 램버트를 사용하면 어떻게 되는지 말이죠???

 

 

 

이제 다시 이 글을 읽어보세요.

 "램버트 라이팅은 확산반사의 음영처리로 많이 알려진 일반형으로, 시선 방향에 의존하지 않고 광원의 입사방향과 면의 방향(법선 벡터)만으로 계산되는 음영처리 기법이다. 이 기법에는 「그 지점의 밝기는, 면의 방향과 빛의 입사 방향이 이루는 각도θ의 cosθ값에 비례한다」라는 「램버트 코사인법칙」이 정의되어 있지만, 실제로 이것으로 라이팅을 하면 명암이 매우 강렬하게 나오는 특성이 있다.하프라이프2에서는, 이 심하게 변하는 코사인 곡선에 바이어스를 걸어 어두운 부분의 계조(단계영역)를 들어 올리는 생각을 했다. 램버트 코사인 법칙의 코사인 곡선이 절반이 되도록 "1/2"을 곱한 다음, "1/2"을 더하고, 다시 이것을 제곱해서 완만한 곡선으로 변환해서 음영처리를 실시하기 때문에 「"하프" 램버트 라이팅」이라고 한다."

여전히 읽기 힘들게 씌여진 글이지만, 어쩐지 이해되지 않나요? 거기다가 우리가 한 것 외에 추가적인 무언가도 언급되어 있는 듯 합니다만... 그건 숙제로 내겠습니다.

ps.

숙제가 있습니다.

사실 *0.5 +0.5 를 대입하는 이 공식은, 실무에서 사용하기에 좀 과다하게 부드러운 감이 없지 않습니다.
노말맵 같은 요철까지 너무 죽어 버리곤 해서... 실제로는 조금 그 효과를 줄여서 사용하지요.

줄인다고 하는 것은 뭐 단순하게 뺀다는 것은 아닙니다. 0~1 까지의 숫자가 이미 나와 있는데, 이걸 단순히 빼면 음수가 또 튀어나오게 되지요.

그래서 보통은 이 *0.5+0.5 를 이용해 나온 결과물에, 제곱을 해서 평평해진 음영을 좀 더 날카롭게 해주곤 합니다.

결과물에 제곱을 해 준다...?

자, 이 결과물에 제곱을 한번 해 보세요. 어떻게 되나 보세요. 2배 제곱, 3배,4배 제곱을 해 보세요.

힌트를 가르쳐 드립니다. 제곱하는 함수는 power 라고 부르며, Math에 RaisetoPower 라고 하는 이름의 노드로 존재할 겁니다. (아마도...)

 

ps2.

최근 shaderFX의 다운로드 경로가 막혔습니다.
이전에 무료로 풀던 경로가 없어지고, 주인장이 오토데스크에 취직해서 더 서비스를 안한다는 말이 씌여 있네요...
그러면서도 데모 버전을 받아서 결재하면 사용가능하다는 안내 게시물은 있습니다만, 정작 데모 버전 받는 곳이 없어요...

이전에 사용하던 버전들은 물론 계속 사용이 가능합니다만, 그렇다고 제가 가지고 있는 버전을 여기다가 당당히 올릴 수도 없고 말이죠. (재배포 되나..?)

그래서 고민중입니다. shader FX가 앞으로 이렇게 계속 서비스를 하지 않는다면, 강의를 중단해야 하는건가...? 라고 말이죠. 어떻게 하는 것이 좋을까요?????

 

자 이렇게 해서 15강은 이걸로 끝!!! 아 KGC 강연준비 하러 가야징...

 

  1. 단, 두 벡터의 길이는 1이라는 전제가 붙어야 합니다. 나중에 기회되면 말하겠지만, 이것을 '단위벡터' 또는 'Normailze된 벡터' 라고 합니다. [본문으로]
  2. 코딩으로는, max(0,dot) 함수를 사용하면 되지요. [본문으로]
  3. 제가 그래서 잘 알아요. 크흑. 지금도 스크랩만 해놓은 게시물이 한가득... ㅠㅠ [본문으로]
  4. 흡수는 뭐.. 열 에너지가 되어 사라집니다. 반사와 투과만 보면 돼요. 피부는? 사실 은근히 반투명으로 투과되어요. [본문으로]
  5. G.I (Global Illumination : 전역조명) [본문으로]
  6. 셰이더를 하다 보니까, '물리 원칙에 맞게 만들기 위해서' 만드는 셰이더와 '알게뭐야 그냥 이쁘게' 만드는 셰이더 두 종류가 있더라고요. 저는 당근 후자편. [본문으로]
  7. 일단, 눈으로는 안보일 겁니다 [본문으로]
  8. 보통 이런 것을 그래서 매직 넘버 (Magic Number) 라고 부릅니다. 이론상으로는 복잡하지만, 열심히 연구해서 매우 간단하게 만든 것이지 허접한 것과는 차원이 다른 기술입니다. [본문으로]
  9. 보통 프로그래머들은 코드 안에 이런 '매직 넘버' 같은 상수를 넣어두는 것을 '하드코딩' 이라고 부르면서 안좋아 합니다. 실제로 유지보수할때 곤란해 지는 경우가 많아서 말이죠. 그렇지만 쉐이더는 일종의 외부 스크립트라서, 이런 매직 넘버를 많이 사용하는 편입니다. [본문으로]
  10. 개인적으로는 하프 램버트의 부드러움은 노말맵의 요철 표현까지 부드럽게 만들어 버려서, 저는 저 수치대로 그대로 쓰진 않습니다. 약간 개량해서 사용하죠. [본문으로]
반응형

댓글