[오픈클래스] 2010-06-20까지 진행된 오픈클래스 내용 - SHOP레벨에서 파티클의 충돌정보를 활용한 쉐이더 만들기.
안녕하세요^^ 6월 20일까지 중간에 진행하지 못한 1주를 제외하고, 약 3주간에 걸쳐 진행된 오픈클래스 내용입니다.
내용은 제목에서처럼 파티클의 충돌정보 이용하여 SHOP레벨에서 VOPs를 활용한 쉐이더를 만드는 것입니다.
첨부파일은 2010_06_20.zip <-- 클릭
혹시 링크가 깨지면 http://blog.naver.com/dls503/40105845729 <-- 이곳에서 같은 이름의 파일을 받으시면 되겠습니다.
우선 클래스에서 마무리된 결과물은 아래 영상과 같습니다.
완성도가 있는 결과물은 아니지만 방법적인 측면에서 참고해주시기 바랍니다.
(참여하신 분들이 더 멋진 결과물로 만들어주실것으로 믿습니다. ㅎㅎ)
이 작업에서의 핵심은 SHOP레벨에서 파티클의 충돌시간,위치에따라 각각 확장되는 영역을 지정하는 것입니다.
이 포스팅에서는 이과정을 중점적으로 정리하도록 하고 나머지부분들은 몇몇 부분만 간략히 소개를 하도록 하겠습니다. 이외의 부분들은 이것을 이용해서 이런저런 변화를 주는 내용들인데, hip파일을 분석해보면 어렵지 않게 알 수 있을것이라 생각합니다. 궁금하거나 이해가 잘 안되는 부분이 있으면 주저없이 리플로 남겨주시면 감사하겠습니다 ^^
1. 파티클의 충돌시간과 충돌위치 받아오기. (첨부파일 : setMask.hipnc)
말씀드렸듯이 이 작업이 가장 주요한 부분입니다. 우선 hip파일을 열어보시면 그리드에 파티클이 떨어지는 간단한 구성이 되어있는 것을 알 수 있습니다. popnet의 collision노드를 보시면 attribute탭이 있습니다. 이곳은 충돌에 관련된 많은 attribute들을 생성할 수 있는 부분으로 이번 작업에 필요한 것은 충돌시간을 나타내주는 hittime과 그리드와 충돌된 uv좌표를 내보내주는 hituv입니다. 이 두 곳에 체크가 되어있는 것을 확인하시고 SHOP레벨에서 /grid/vopsurface1로 들어가보면 forloop(find_hituv_and_hittime)을 중심으로한 간단한 네트억이 구성되어있는것을 볼 수 있습니다. 각각의 파티클들의 떨어진 위치와 시간이 모두 다르기 때문에 영역을 설정하는 부분은 모두 forloop안에 구성되어있습니다. (forloop에대한 자세한 내용은 이전 게시물을 참고하여 주시기 바랍니다.)
아래는 forloop내부의 네트웍 구성 입니다.

1_1 hituv 를 활용한 영역 설정.
알아보기 쉽도록 각각의 네트웍 박스로 묶어놓았는데 setMask라고 되어있는 부분은 hituv를 이용해서 파티클이 그리드와 충돌한 지점을 찾아내고 distance노드를 통해서 각각의 지점에 circle형태의 영역을 만들어주는 역할을 합니다. 여기서 중요한 것은 SHOP레벨에서도 쉐이더가 지정된 오브젝트의(현재는 grid) attribute은 VOPSOP에서처럼 parameter노드를 통해서 받아올 수 있습니다. 하지만 지금 받아와야 하는 attribute은 grid오브젝트가 아니라 파티클 오브젝트 입니다. 이럴때 사용할 수 있는 노드가 바로 Import Attribute(import_hituv) 이라는 노드입니다. 그리고 이 노드를 사용하기 위해서는 attribute을 받아올 오브젝트가 베이크 되어있어야 하고, 베이크 된 파일을 통하여 받아올 수 있습니다.
여기서 point number에 I가 연결되어있는 것에 주목해야 하는데, 현재 forloop의 설정은 initial Value = 0, End Value = 29, Step Size = 1로 되어있습니다. 즉 0에서부터 29가될때까지 1씩 증가하는 I값을 가지게 되어있는 것입니다. 그리고 End에 들어가있는 29라는 숫자는 파티클의 마지막 포인트 넘버 입니다. (파티클 오브젝트에서 $NPT를 attribute으로 만들어 불러올 수도 있겠습니다)
결과적으로 한 loop당 0번부터 29번까지의 파티클에서 hituv라는 attribute을 받아오게 되는 구성인것입니다. 이렇게 받아온 hituv가 그리드의 uv와 distance노드와 fit range노드를 통해 각지점에 circle 형태를 만들어 내게 됩니다. (distance와 fit range를 통한 영역 설정에 대한 내용 역시 이전 클래스에 정리되어있으니 참고하시기 바랍니다.)
여기에서 한가지 더 주목해야 하는 부분은 바로 네트웍 상단에 붉은 색으로 되어있는 compare노드입니다. 이노드가 필요한 이유는 아직 충돌이 일어나지 않은 파티클에 의해 만들어지는 영역을 삭제하기 위한 것입니다. 충돌이 일어나기 전에는 기본적으로 hituv에서 uvw값이 모두 0으로 나오기때문에 왼쪽아래(u,v,w가 각각0인지점)에서 서클들이 생겨나게 되기때문에 이 값이 0일경우 multiply를 통해서 영역을 없애는 방식입니다.(어떤 수든 0으로 곱해지게 되면 값이 0이 된다는것을 생각하시면 쉽습니다..)
1_2 만들어진 영역(서클)에 노이즈 추가하기
set_Mask 아래에 노이즈를 추가하기 위한 아주 초 간단한 구성이 있습니다. 보시다시피 turbnoise를 통해 생성된 노이즈를 uv값에 더해주는 역할을 합니다. 헌데 여기서도 잘 생각해봐야할 문제가 있습니다. uv를 기준으로 적용된 노이즈와 원본 uv값이 add노드를 통해 더해져 있는것을 볼 수 있는데, 이것은 우리가 노이즈를 통해 얻고자 하는 결과가 완전 새로운 노이즈패턴이 아니라 set_Mask에서 만들어지는 서클모양을 찌그러트리는것에 목적이 있기때문입니다.(파티클의 충돌지점을 유지하면서)
기본적으로 노이즈의 pos는 시드값을 받아들이는 부분입니다. rand()함수를 생각해본다면, rand($PT)에서 $PT에 해당하는 부분이라고 생각하시면 됩니다.
이것은 결국 노이즈가 형성되는 기준만을 지정할 뿐이지 pos에 들어오는 값은 완전히 새로 바뀐 노이즈값으로 생성되기 때문에, 서클이 찌그러지는 형상을 만들기위해서는 원래의 uv값과 더해주어야 하는 것입니다. distance의 p2에 turbnoise1의 아웃풋 바로 연결해보시면 파티클이 실제 떨어진 지점과는 전혀 상관없는 패턴이 형성되는것을 알 수 있습니다.
1_3 hittime을 이용해 충돌 시간에서부터 영역 확장시키기.
이것은 1_1.과 비슷한 과정입니다. 다만 받아오는 attribute이 hittime이라는 것이 다르고 fit의 개념이 정말 중요하게 사용되는 부분입니다. 우리가 받아오는 hittime은 각각의 파티클들이 충돌한 시간을 담고있는 attribute입니다. 만약 어떤 파티클이 충돌을 일으킨 시간이 3초라면 3이라는 값을 가지게 되는것이지요. 이 경우 만들어지는 영역은 충돌이 일어난 3초부터 확장되기 시작해야 합니다.
그러기 위해서는 3초지점에 0의 값을 갖고 이후로는 점점 커지는 값을 만들어줘야 하겠지요. 우선 (현재시간 - 충돌시간)을 생각해 볼 수 있겠습니다. 현재시간이 3초가 되면 값은 0이 되는것이지요. 만약 현재시간이 4초가되면 1(4-3) 5초가 된다면 2(5-3) 이런식으로 늘어나게 되겠구요. 하지만 현재시간이 3초보다 작은 경우에는 마이너스의 값을 갖게 되는 문제가 있습니다.(예를들어 2-3 = -1)
이런문제는 fit range노드를 통해서 조정해줄 수 있습니다. fit2노드를 살펴보면 값이 각각 0, 10 , 0 , 0.3 이렇게 되어있습니다. 이것은 (현재시간 - 충돌시간)이 0이되는 지점 에서부터 10이 될때까지의 값을 0에서0.3사이의 값으로 재조정 해줘라.. 하는 내용입니다. 결과적으로 (현재시간 - 충돌시간)이 0보다 작으면 계속 0이라는 값을 내보내게 되고, 확장은 충돌시간으로 부터 10초까지 진행되게 됩니다. 10초 후에는 0.3의 값으로 고정되게 되구요.
글로 써 놓으니까 먼가 복잡해 보이지만 Fit이라는 함수가 작동하는 방식을 이해하면 쉽게 알 수 있는 내용이라 생각합니다. 그리고 이렇게 hittime에 의해서 만들어진 값은 마지막으로 fit1노드로 들어가면서 hituv에 의해 만들어지는 영역의 크기를 조정하게 됩니다.
이렇게 만들어진 결과물은 루프가 돌아갈때마다 circle이라는 변수로 계속해서 저장이 되게 됩니다.(add1노드) 만약 이렇게 더해주지 않는다면 결과물은 마지막 loop에서 계산된 단 하나의 circle만을 내보내게 됩니다.
마지막으로 fot loop의 뒤에 연결되어있는 colormix노드는 단지 영역을 확인하기 편하도록 하기 위한것으로 현재는 별다른 의미가 없는 노드입니다.
여기까지의 결과물로 다음과 같이 이 후의 작업에서 기준이되는 영역이 설정되었습니다. (노이즈는 적용되지 않은 상태입니다.)
시작할때 밝혔듯이 여기까지가 핵심 내용 입니다.
첨부된 파일중 Final.hipnc는 이것을 이용하여 서피스 쉐이딩과 디스플레이스먼트를 만드는 구성이 들어있습니다.
2. 디스플레이스먼트 쉐이더
파일을 열어서 shop/grid 에 vopdisplace1을 살펴보면 다음과같이 구성되어있습니다.

vopdisplace는 이름에서 알수 있듯이 디스플레이스먼트 쉐이딩을 만드는 곳이고, 여기에는 아까 만든 forloop를 복사해서 그대로 쓰고있습니다. 후디니의 헬프파일을 보면 서피스 쉐이더와 디스플레이스먼트 쉐이더간에 변수를 공유할 수 있는 import displacement variable과 import surface variable이라는 기능이 있는데, 클래스 진행중에 말씀드렸듯이 아무리 눈을 씻고 찾아봐도 import surface variable이라는 노드는 찾을 수가 없었습니다. 아마 버그가 아닐까 생각하고있습니다만 정확한건 잘 모르겠군요.. 흠..; 혹시 시원하게 아시는분은 꼭 알려주시기 바랍니다..^^;
여하튼 그런 이유로 디스맵에는 vopsurface에서 만들었던 forloop의 내용을 그대로 복사해서 사용하고있습니다. 파일에서 디스플레이스먼트 쉐이더의 구성은 크게 별다른건 없고, 만들어진 영역에만 노이즈가 적용되도록 aanoise가 multiply 되어있는 상태입니다.
다만 forloop뒤에 붙어있는 parameter(mask)는 vopsurface에서 아까 말씀드린것처럼 vopsurface1에서 import displacement variable을 통해 변수를 받아볼 수 있도록 값을 export해주는 파라미터 입니다.입니다. (물론 이것을 사용하지 않고 vopsurface에서도 따로 forloop를 사용해도 되지만, 이렇게 만들어놓으면 값을 조정할때 양측이 함께 연동되어 적용된다는 장점이 있습니다.)
3. 서피스 쉐이더
vopsurface1에 들어가보면 다음과같이 구성이 되어있습니다.

자.. 여기에서 foroop대신 dimport1이라는 이름의 노드가 사용되고 있는데 이것이 바로 아까 말씀드린 import displacement variable 노드입니다. 이것으로 vopdisplace1에서 만들어진 mask라는 변수를 받아오고 forloop(find_hituv_and_hittime)을 대체하고있습니다. 왔다갔다해서 좀 혼란을 드리는게 아닌가 싶기도 한데, 정리를 한번 하자면 forloop를 vopdisplace1에 복사해서 사용하고있는 상태이고 이것을 다시 vopsurface1에서 불러와서 사용하고있는 것입니다. 이렇게 한 이유는 import surface variable이라는 노드를 아무리 찾아봐도 없기 때문이었습니다.
결론은 애초에 vopdisplace에서 작업을 시작했으면 되었을것을.. ㅡ,.ㅡ 아무튼 이부분은 혼란이 없으시기 바랍니다^^;
여기서 살펴볼만한 대략 두가지 정도를 짚고 넘어가도록 하겠습니다.
우선 첫번째는, 영역의 경계부분을 조명에 상관없이 밝게 빛나도록 만들어야 하는데, 이것을 위한 경계부분을 어떻게 추출할 것인가 입니다. 해답은 boundary_mask 네트웍박스에 있습니다. 사진으로는 알 수 없지만 파일을 열어서 확인해 보면 fit1과 fit2는 값이 뒤집어져 있는것을 알 수 있습니다. 우리가 만들어놓은 영역은 서클모양을 기준으로 서클내부는 1, 서클 외부는 0, 경계부분은 0과1사이의 회색톤의 값을 갖게 됩니다. 이것을 뒤집어서 곱해주면 양쪽중 어느 하나라도 값이 0인부분은 0이되게 되겠죠. 결과적으로 서클내부와 외부는 값이 모두 0(블랙)이되고 그 경계부분만 남게 됩니다.
그리고 두번째는 바로 lighting model이라는 노드가 하는 역할에 대한 것인데, 이것이 하는 역할은 흔히들 알고계시는 퐁이나 램버트와 같이 서피스가 빛에 반응하는 방식을 설정해주는 노드입니다. 만약 라이팅 모델이 적용되지 않은 상태에서는 빛도, 그림자도 아무런 의미가 없게 됩니다. 다시 말하자면 self illumination이 100% 적용되고 있는 상태라고 보시면 됩니다. lighting model과 블렌딩을 하면 그 정도를 조정할 수 있게 되는 것이구요. 구성을 살펴보면 boundary_mask에 의해서 만들어지는 값은 lighting model뒤에 연결되어서(lighting model이 적용되지 않은 상태) self illumination효과를 내고있는 것을 알 수 있습니다. 결과적으로 그부분은 빛이 세든 약하든 그림자가 있든없든간에 렌더링시 항상 정해진 색을 유지하게 되는 것입니다.
이상으로 이번 클래스에 대한 정리를 마치도록 하겠습니다. 제가 쉽게 풀어서 설명하는 재주가 부족해서 좀 복잡해지는 부분도 있는거같은데, 혼란스러운 부분이 있다면 꼭 질문해주세요..^^;
더불어서 더욱 효율적인 방식이 있으면 공유해 주시기 바라겠습니다.. ㅎㅎ
Houdini
Sun, 06/27/2010 - 20:30
Permalink
잘했어요.
많은 질문 부탁드립니다.
kybin
Tue, 07/06/2010 - 11:54
Permalink
좋은 강좌네요
잘 읽었습니다. 감사합니다. 지현팀장님은 건강히 잘 지내고 계신가요? ㅎㅎ