본문 바로가기
툰렌더링 공부

레벨5 기술 보고서

by IX. 2022. 11. 20.

레벨5의 첫 작업기록을 보니 10.14로 기록되어 있습니다. 한달이 넘었단 이야기죠. 게시물의 제목이 레벨 5인인 이유는 툰렌더 연구 이후 5번째 캐릭터이기 때문입니다. 

왼쪽부터 1호,2호,3호...

 

유니티짱에서 원신에 이르기까지, 미소녀 캐릭터는 눈부분을 안쪽으로 파서 동공을 별도로 만드는 식의 모델링이 정석으로 여겨져 왔습니다. 이 방식은 대체로 괜찮은 결과물을 보여주지만, 한가지 약점이 있습니다. 눈 부분에 셀프쉐도우가 안예쁩니다. 모자를 쓰거나 나무 그림자에 얼굴이 드리워졌을 때, 눈 부분의 그림자 처리가 예쁘지 못하다는 단점이 있어요

 

이 단점을 극복하고 싶었습니다. 어떻게서든 캐릭터의 얼굴에 나무 그림자를 드리워보고 싶다...

셰이더를 배운지 1년이 다 되어가는 지금이라면 해볼만하지 않을까? 싶었어요. 문제가 되었던 눈에 가장 많은 공을 들였죠. 모델링을 잘하는 것과는 별개의 문제이기 때문에 새로운 설계가 필요했습니다. 좀 더 평면적으로. 눈 텍스처만 4장이 사용됐고, 시선처리는 셰이더에게 맡겼습니다. 홍채의 모양을 달리해 감정표현을 하고, 하이라이트를 더해줬어요. 결과는 꽤 괜찮았습니다.

 

눈을 하고 나니 입은 크게 어려울 것이 없었습니다. 비슷한 듯 다른 로직을 적용했지만, 눈과는 다르게 입은 꽤 입체적으로 생겼으므로 매핑을 입안쪽의 오프셋을 달리 해줍니다. 라이브2D로 만든 캐릭터들에게서 많이 찾아볼 수 있는 방법이죠. 여기에 만화적 표현을 위해 마스킹의 오프셋 또한 옮겨주었습니다. 이 '입돌리기'는 적용된 것과 그렇지 않은 것의 차이가 꽤 큽니다. 

입돌리기 적용
입돌리기 미적용

 

하지만 이렇게 되니 셰이더에 팩터가 많기 때문에, 전체적인 표정을 조율하기가 힘이 듭니다. 때문에 본체 옆에 컨트롤러를 붙였습니다. 드라이버의 값을 local로 잡으면 화면 어디에 옮겨놔도 잘 작동합니다. (사실 이건 회사에서 작업한 것을 간편화한 것입니다. 회사에서도 비슷한 컨트롤러를 사용하는데, 훨씬 더 복잡하게 생겼습니다. )

 

머리카락의 셰이더는 레벨1에서 제작된 셰이더를 개량했습니다. 아무래도 오래된 물건이다 보니 '뭐 이런게 돌아가고 있지'라는 부분이 있었기 때문에 계산이 잘못된 부분을 올바르게 손봤습니다. 앤젤링의 모양은 별도의 텍스처 없이 UV에 노이즈를 더한 절차적 생성을 통해 만들어 더해줍니다. 그리기 꽤 성가신 부분이기 때문에, 이런 자산들이 많아지면 작업이 훨씬 수월해지리라 생각합니다. 다만 지켜야 될 규칙들은 늘어나겠죠.

 

몸의 셰이더는 제가 그림을 그리는 과정을 그대로 합성했습니다.

블렌더의 셰이더는 셀프 쉐도우를 던져주지 않기 때문에, principle BSDF를 그대로 RGB로 변환해 사용할 수밖에 없었습니다. 전 셀프 쉐도우를 굉장히 좋아하기 때문에... NDotL만으로 표현된 명암만 쓰느니 차라리 포기하고 말겠다.라는 마음이었죠( 앞서 말씀드렸듯 레벨5작업을 시작한 계기도 눈에 드리워지는 셀프 쉐도우를 표현하고 싶어서였습니다.)

물론 실제로는 좀 더 복잡합니다.

 

온 몸에 묻은 물방울은 잘 안보이지만, 꼭 표현해보고 싶었습니다. 사실, 이건 꽤 비쌉니다. 방울 하나하나에 실제 굴절이 적용되고 있거든요. 아. 물론 화면기준 굴절입니다. 렌더러를 사이클까지 바꾸고 싶지 않았기 때문에, 어떻게든 이브이에서 해결을 보고 싶었어요.

 

물방울은 지오메트리 노드로 전체에 발랐습니다. 익숙한 방식이죠? 지오메트리 노드를 첫 강에 단골로(그 어떤 강의든간에!) 등장하는 Distribute Point on Face(랜덤한 점에 인스턴싱)노드입니다. 

 

본을 심을 차례입니다. 몸이야 블렌더의 유료 애드온인 AutoRig Pro가 자동으로 해줍니다. 그 간의 작업들은 리깅에 큰 노력을 들이지 않았으나, 머리카락이 얼굴을 뚫게 하는 것이 항상 마음에 걸렸던 터라 이번엔 드라이버를 사용해서 각도제한을 줄 생각으로 머리카락의 가닥별 축을 모두 통일시켰습니다.

사실 이렇게 보면 잘 모르겠습니다만...

 

하지만 이 계획은 실패했습니다. 드라이버와 애니메이션은 동시에 수행할 수 없습니다. 블렌더가 인지하기엔 그것들은 둘 다 커브일 뿐...

 

그렇다면 제약조건을 걸면 어떨까? 싶어 Limit Rotation으로 움직임을 제한했습니다. 이 방법은 성공했고, 머리카락이 얼굴을 뚫는 문제를 해결했습니다. 하지만 품이 너무 많이 들어 실무에서 사용하려면 스크립트가 필요합니다. 이번 작업에서도 임시로 간단히 작업할 수 있는 스크립트를 제작해 사용했습니다.

선택된 본의 스프링본을 해제하고 x축에 대해 180도 제한을 거는 스크립트입니다. 보시다시피 간단한 코드 몇 줄이지만, 이걸 손으로 해주려면 반나절 걸립니다.

import bpy

for bone in bpy.context.selected_pose_bones:
    bone.sb_bone_spring = False
    bone.sb_bone_rot = False
    constraint = bone.constraints.new(type='LIMIT_ROTATION')
    constraint.use_limit_x = True
    constraint.min_x = -3.14159
    constraint.owner_space = 'LOCAL'

 

머리의 찰랑거림을 표현하기 위해 머리카락 끝에 제어본을 달았지만, 첫 계획이 틀어지며 실제로는 사용되지 않았습니다.

 

스키닝은 Preserve Voulme을 체크해 듀얼쿼터니온 방식을 사용했습니다. 이 방식은 대체로 좋은 결과를 보여주지만 겨드랑이 부분에 과도한 풍선 효과를 일으킵니다. 

등빨!

이를 해결하기 위해 멀티 아마추어를 적용해 리니어 영역을 지정해주어 해결했습니다. 이같은 방법을 게임에서 사용할 수 없는 것이 유감입니다. 게임 엔진에서는 아직 듀얼쿼터니온 방식의 스키닝이 지원되지 않아요. 비싸거든요.

멀티아마추어...라는 걸 처음 알았습니다.

 

하지만 스키닝 방식이 어느 쪽이든 캐릭터가 팔꿈치를 접었을 때 척골의 모양이 예쁘지 않다는 문제가 있었습니다. VRoid에서는 이를 대각선 와이어로 해결했습니다. 이는 실용할 수 있는 가장 멋진 방법이라고 생각합니다만, 이번작품은 처음부터 게임엔진으로 가져갈 생각이 없었기에 전부터 사용해보고 싶었던 드라이브를 써보기로 했습니다.

팔뼈들의 각도를 기준으로 셰이프키를 만들어 이를 조율해주는 방식입니다. 팔이 접혔을 때는 1, 아닐 땐 0. 작업은 어려울 게 없었으나, 드라이브는 꽤 고급기능에 속하므로 좌우반전같은 기본적인 매크로가 지원되지 않는 점이 불편했습니다.

 

하지만 이 방식의 문제는 데이터이전을 할 수 없다는 것이었습니다. 이걸 다 만들고서야 깨달았어요. 흑흑. 

아래의 스샷을 보면 팬티엔 엉덩이의 드라이브 데이터가 이전되지 않았음을 알 수 있습니다. 사실 당연한 이야기입니다... 완전 수동으로 해주는 작업이니까.

엉덩이의 훌륭했던 볼륨은, 이제 문제아가 되었습니다.

 

이론적으로는 완벽한 모델을 만들 수 있는 유일한 방법입니다만, 제작이 어렵고 데이터 이전을 할 수 없으면 무용지물입니다. 다음 작품을 만들 기회가 생긴다면 이 기능은 쓰지 않을 것 같습니다.

 

한달간 꾸벅꾸벅 졸아가며 어찌어찌 완성은 했습니다. 하루평균 작업시간은 2시간 정도로, 애를 재우고 난 후에야 작업이 가능하기 때문에 시간이 절대적으로 부족했던 작업이었습니다. 구상만으로도 2시간을 보낸 적도 많아요. 그런 날은 정말 아깝...개인작은 이제 좀 힘들지 않을까 싶습니다. 잠을 줄이니 사람답게 못사는 느낌이라. 흑흑

 

전작들도 그렇긴 했지만 RnD성향이 짙은 작업이라 쉬운 내용들은 아니라고 생각합니다.긴 글 읽어주셔서 감사합니다. 

좋은 하루 되세요.

 

댓글6