2Pass 쉐이더 완성 by 김윤정

* Hybrid 님이 지적해주신대로 1pass로도 충분히 구현 가능합니다. 뷰 벡터를 계산하면 가능하니까요.
제가 왜 V를 L로 보고 있었을까요 (...)


프로그래머분들이 보면 콧방귀를 뀌며 비웃을 일이지만...(전 그래픽 디자이너 출신이라고욧) 
어쨌건 이제야 완성했습니다. ㅎㅎ
그동안 사실 별로 필요한 줄을 몰랐던 것도 사실이거든요.

기본적으로 1pass로 2side 재질은 거의 만들지도, 사용하는 것도 권장되지 않았던 데다가
필요해서 2side를 사용한다고 해도 특별히 안쪽 (빛 안받는 쪽) 이 어두워지 않아도 크게 이상하지 않았던 거죠.
2side라고 한다면 보통 종이나 천일텐데, 그런 경우 뒷면에 빛이 투과가 되는 느낌이 오히려 투과 안되는 것보다 자연스러웠기 때문입니다.

이론을 설명하자면 다음과 같지요.
휘어진 plan이 있고 vertex와 normal이 이렇게 있다고 칩시다.
그리고 빛이 이렇게 들어오고, 시야 (뷰벡터)가 이쪽에 있다고 치지요

그럼 뭐 기본적으로 알아서 밝아집니다. dot공식으로 처리하면 밝게 보이는 것은 기본.

그렇지만 만약 이렇게 본다면?
이렇게 본다면 , 원칙적으로는 어둡게 보여야 할 것 같지만 사실은 2side 옵션을 켜 놓아도 밝게 보입니다. 빛은 분명 반대편에 있는데 말입니다.
왜냐하면, 빛이 밝아지는 것은 vertex가 밝아지는 것인데 이 상태는 비록 뒷면이어도 vertex랑 normal은 각각 하나씩밖에 존재하지 않기 때문에 뒷면에서 봐도 밝아 보이는 것입니다. 즉 앞면이 밝으면 뒷면도 밝다는 것. 

뭐 사실 머리카락이나 천 등에 이대로 그냥 써도 그렇게 크게 어색하지는 않습니다.
여기서부터는 그래픽 디자이너의 영역이긴 한데...
사실 이게 어둡게 처리되어 음영지는 것보다는 오히려 투과해서 밝아지는 쪽이 낫거든요

그치만 뒷면이 꼭 어두워져야 하는 경우도 물론 있을 수 있습니다.
철판이라던가, 기타 뒷면에는 특이한 느낌을 더 주고 싶다던가. 비치는 부분에  transparency칼라를 주고 싶다던가 등등.
그럴 경우에 간단하게 할 수 있는 방법은 plan 복사해서 뒤집고 2side 끄기.
구식의 방법이지만, 이만큼 간편한 방법도 없을 것입니다.
단점이라면 두 면이 약간이라도 단차가 생긴다는 것 정도인데, 이것도 큰 깃발 등에서는 그렇게 심하게 거슬리지도 않습니다.
그렇지만 머리카락과 같이 섬세한 겹침이 유발되는 오브젝트를 작업할때는 상당히 짜증날 수도 있고 보기에도 거슬릴 수도 있겠죠.
(얼마나 무시할 수 있느냐는 그래픽 디자이너의 선택)
그 외에도 LOD시의 문제라던가 등등 제작상의 다른 문제가 있을 수도 있는 관계로 2pass로 뒷면을 처리하는 방법을 구현해 봤습니다.

... 쉽네요...
그냥 두 번째 패스 지정하고 거기에 맞는 공식을 추가해주면 끝. 이정도로 쉬웠나. 왜 한 번도 안써본거지.
필요가 없으니까...!
사실 쉐이더를 굉장히 많이 만들거라고 생각되어도, 일반인이 이상하지 않을 정도면 충분한거죠.
실사를 정확히 구현하는 것보다 가볍고 대충이어도 이쁜 쪽이 장땡이랄까.


그래서 2 pass는 첫 번째 pass 에서 앞면으로 그리고, 두 번째 pass에서 뒷면을 그릴 때 vertex shader 함수 부분의 normal 계산에 - 값을 넣어주면 끝.
그렇게해서 처리한 결과물이 다음과 같습니다.
이렇게 되면 절대로 뒷면이 밝아지지 않겠지요.
물론 이렇게 안 밝아지면 그 나름대로의 단점도 있어서 다시 튜닝해줘야 하지만 말입니다 ㅎㅎ

어쨌건 처음 해본 멀티 패스.
응용하면 fur 표현도 어떻게 할 수 있는지 알 것 같네요. 후후후


덧글

  • The Nerd 2010/01/27 11:32 #

    신비로운 광 시뮬레이션의 세계
  • 김윤정 2010/01/27 14:04 #

    ㅎㅎ 정확히라면 시뮬레이션이라기 보단 흉내내기...
  • 베로스 2010/01/27 18:16 #

    내용이 재미지네요.
  • 김윤정 2010/01/29 06:42 #

    감사합니다. 이걸 이용해서 만든 것도 재밌습니다 :)
  • Hybrid 2010/01/29 20:00 #

    리플을 쓰기 위해서 안쓰는 이글루스를 로그인해야하는군요. ㅡ_ㅜ

    그런데, 굳이 2pass 로 해야하는 이유가 있나요?
    그러니까, 단순히 뒷면을 볼때 어둡게 보기 위해서는 쉐이더에서는 너무도 간단히 해결이 되니까요.
    (그냥 V 랑 N 계산해서 dot 이 양수면, diffuse 부분을 0 으로 만들어 버리면 되는 거...)

    // diffuseFactor = N, V, L 를 이용한 계산
    if( dot( N, V ) > 0.0 ) { diffuseFactor = 0.0; specularFactor = 0.0; }
    finalColor = ambientColor + diffuseFactor * diffuseColor + specularFactor * specularColor;

    제가 뭔가를 놓쳤나요? 'ㅁ'?
  • 김윤정 2010/01/30 09:43 #

    로그인은 죄송합니다 T_T 누가 악성 댓글을 심어놓더라고요.
    넹 저도 걍 그렇게 하면 될거라고 생각했지만 그건 완전히 앞면만 있는 오브젝트일 경우고용.
    지금처럼 완전한 plan . 즉 한 개의 vertex가 앞면 뒷면을 다 표현할 때에는 그렇게 안되더라고용.
    이미 vertex는 앞면을 계산할 때 밝은 빛을 받아 버렸기 때문에, 2side를 켜면 그 값이 다시 한 번 계산되는게 아니라 그냥 뒷면까지 그려 버리는 거니까요...
    게다가 지금 하려는 궁극적인 효과가 뒷면일때 반투명한 질감을 한정해서 내기 위해 만드는 과정이라, 뒷면의 독립적 제어가 불가피한 상황입니다 >_<
  • Hybrid 2010/02/01 10:54 #

    저는 잘 이해가 안가서..... 오히려 제가 질문하는 셈으로 여쭤봅니다. ^^;

    원래 하나의 vertex 가 양면을 모두 표현하는게 2-side 인데.....
    뒤에서 본다면, 결국 해당 삼각형의 픽셀에 대한 pixel shader 는 단 한번씩만 호출 되겠죠.

    그러고보니, 사실 쉐이더 프로그래밍에서 2-side 옵션은 끄고 켜는게 의미가 없던걸로 기억합니다. ㅡ0ㅡ;
    (그 옵션의 역할 자체를 쉐이더에서 처리하니까요.
    쉐이더 안에서 뒷면을 그냥 똑같이 그릴지, 어둡게 그릴지, discard 할지 결정할 수 있죠.)

    아마, 쉐이더를 사용하시는 방식이 서로 달라서 생기는 문제가 아닌가 생각이 들긴 하지만...
    일단 저는 김윤정님의 위의 방식이 잘 이해가 안가서 관심이 가는군요.. ^^;
  • 김윤정 2010/02/02 16:39 #

    아아 역시 제가 잘못 봤습니다. >_< V 를 L로 봤네요 (뭐가 씌였나)
    Hybrid 말씀하신대로의 방법이 맞습니다! 제가 잘못 이해한 겁니다!! 게다가 이것은 저도 초기에 생각했었던 방법이기까지 하네요 ㄷㄷㄷ
    if문 안쓰려고 고민하다가 여기까지 오게 된 것이었습니다. (털썩) ㅎㅎㅎ ;;;
    일단 2pass 공부했다고 생각하고 놔둔 다음에 나중에 다시 손보려 합니다.
    좋은 글 남겨주셔서 정말 감사합니다. 앞으로도 많이 도와주세요 >_<

  • 김윤정 2010/02/02 16:39 #

    앞의 글은 제가 뭐에 씌였는지 헛소리를 횡설수설해서 지웠습니다. >_< 죄송합니다.
※ 로그인 사용자만 덧글을 남길 수 있습니다.


MyADD

<script> (adsbygoogle = window.adsbygoogle || []).push({}); </script>