5.5
달래는 닐리보다는 쉬울 것이다. 앨리스보다도 쉬울 것으로 예상한다.
지금까지 작업을 하며 했던 삽질들을 한 번 정리하고 넘어가도록 하자.
- Flipped애니메이션들은 모든 정방향 애니메이션이 끝난 후에 제작하는 편이 좋다.
- 본의 마디가 많을 때, 루트와 중간본의 애니메이션은 따로 제작하자. 물론 루트 적용해보고 잘 나오면 좋고.
- 세컨더리가 필요한 부분에 대해서는 Idle에 초기값을 넣어둘 뿐, 애니메이션 하지 않는다.
달래의 이슈는 스커트다. 대부분의 문제가 치마에서 발생하는데, 3D는 원래 몸에 딱 달라붙는 옷을 표현하는 것이 어렵다. 조금만 어긋나도 뚫리고, 오차값을 너무 허용하면 순식간에 펑퍼짐해져서 테가 안난다.
이번에 세컨더리 애니메이션 작업을 하며 Shrink Wrap에 대한 걸 배웠다. 달래의 스커트에 응용할 수 있지 않을까?
….는 테스트 결과, 안된다. 애초에 Shrink Wrap이 완전하지 않기는 하다. 하지만 적어도, 이 제약조건은 충돌스크립트를 탄생시켰고, 이에 따라 수동 노가다의 길을 더 원만하게 해줄 것 같긴 하다. 따라서…

치마 본의 컨트롤러 제약은 삭제하고 일반적인 방법으로 대처할 수 있을 것 같다.

허나 이를 위해선 치마본 설계를 다시 하여야 한다. 기억이 가물가물한데… 여기서 세로 본은 컨트롤러일 뿐이고, 실제로 치마를 움직이는 것은 가로 본이다. 기존까진 2마디였는데, 닐리와 같이 3마디를 쓰자.
이미 앨리스보다 쉬울거라는 예상은 벗어난 것처럼 보인다. 차근차근 웨이팅해보자.

치마본의 스케일에 사용된 드라이버는 상당히 복잡하다. skirt_scaler에 할당된 저 값들은 대체 무엇을 의미하더라….
def skirt_scaler(z, x, y, front, side, back, level, limit):
코드를 봐도 모르겠네?! 한 분야를 너무 깊숙히 들어가면 이런 코드가 나온다…
5.6
코드를 건들수록 망가지는 것 같아서 다시 롤백했다. 과거의 나를 믿어야 한다.
어디까지 다이나믹 본으로 돌려야 할까? 를 고민하다가 루트본만 애니메이션을 하는 쪽으로 가닥을 잡았다. 그런데 잠깐… 닐리도 이렇게 하면 다이나믹본을 사용할 수 있지 않을까?

사실 문제가 되는 모션들은 바로 이런 것이었다. 사정없이 깨지고 뚫리는 것이 싫어서 수동노가다를 선택했던 것인데, stiffness값을 올려주니 이런 부분들이 많이 상쇄되는 것을 발견했다.

엉덩이 부분이 뚫리는 것은 컬라이더를 조금 보강하면 될 것이다. 필요한 경우, 애니메이션 이벤트에서 동적으로 설정해줄 수도 있을 것 같다. 다이나믹본은 기존의 애니메이션에 물리계산을 덧붙인다. 그렇다는 것은 의도적인 천의 모양도 잡아줄 수 있다는 이야기이다. 생각보다 더 좋은 것 같다. 지금까지 난 뭘 한거지…흑흑
과감히 노선을 틀어보자. 달래를 중단하고 다시 닐리로
5.8
닐리와 앨리스의 작업을 해결했으므로 다시 이어서 해보자.

가슴본에 저고리 고름이 달린 형태라 애를 좀 먹었는데, 다이나믹본은 본에 본을 달았을 경우 exclusion을 통해 자식본을 계산에서 제외해도 작동이 안된다. 이유는 모르겠지만, 물리계산에 필수적인 end본 계산부분에서 뭔가 오류가 있거나, 아니면 원래 그렇게 사용하는 것이 아니거나.

이럴 경우 똑같은 본을 복사해서 해당 본의 자식으로 달아주고, 그 본을 연산에서 제외시키면 된다. 이 과정에서 사본의 본 움직임을 원본과 똑같이 하는 Constraint도 적용해보았는데, 작동되지 않는다. 애니메이션 키만 따라가는 모양. 혹은 Update()시점의 차이일지도 모른다. 뭐든 안된다. 어차피 더 좋은 방법을 알았으니 쓸 필요가 없다.

아직은 순조롭게 진행 중. 세컨더리 애니메이션의 대부분을 다이나믹 본에 의지함으로서 그동안 만들었던 애드온의 기능 중 많은 기능이 쓸모없어졌다. 오로라까지 작업한 이후에 쳐낼껀 쳐내도록 하자.
5.9

캐릭터가 앞으로 이동할 때 머리카락이 캐릭터를 가린다. 아이고, 예쁜 얼굴을 가리면 어떡하니. 해결방법을 찾아보자.

컬라이더를 조금 앞으로 빼주는 것으로 해결. 그렇게 예쁘지는 않은 것 같지만… 그래도 가성비가 좋은 방법이다.

입셰이더에는 각도에 따라 입이 돌아가는 코드가 들어가 있다. 난 입을 그릴 때, 특히 옆모습을 그릴 때 얼굴 옆에 그리는 습관이 있기 때문에 이런 코드를 넣은 것이다. 그런데 이것이 오작동해서 입이 비뚤게 보이는 버그가 있었다.
// 뷰에 따른 오프셋 계산. 0.04는 임의의 속도.
float3 leftWS = normalize(TransformObjectToWorld(float3(1,0,0)));
float3 view = _WorldSpaceCameraPos.xyz - OUT.positionWS.xyz;
float3 V = normalize(float3(view.x, 0, view.z));
offset.x += dot(leftWS, V) * 0.04;
이것이 문제의 코드. 원리는 오른쪽과 카메라를 Dot시켜 나오는 값을 더한 것. 그런데 leftWS의 벡터를 위치로 계산하고 있는 것이 문제였다. 셰이더에서 벡터를 다룰 때, 위치인가? 방향인가?는 계산방법이 조금 다르다. 복잡한 건 모르겠으니 그냥 유니티에서 제공해주는 걸 사용하면 된다. 따라서 이 코드는 이렇게 수정되어야 한다.
// 뷰에 따른 오프셋 계산. 0.04는 임의의 속도.
float3 leftWS = normalize(TransformObjectToWorldDir(float3(1,0,0)));
float3 view = _WorldSpaceCameraPos.xyz - OUT.positionWS.xyz;
float3 V = normalize(float3(view.x, 0, view.z));
offset.x += dot(leftWS, V) * 0.04;
이제 정상작동하는 것을 확인할 수 있다.
달래가 은근 달린 것이 많다 보니 타격등에서 캐릭터경직이 일어날 때 다이나믹본이 움직이는 것이 꽤 거슬린다. 그래서 경직중엔 업데이트가 되지 않도록 수정했는데, 이렇게 되니 세컨더리본들의 움직임이 초기화되기 때문에 자연스럽게 보이기 위해 맞을 때 세컨더리본을 ‘예쁘게’수정해 주어야 한다. 내일은 이걸 해보자.
…
맞을 때 세컨더리본을 수정하기 위해선 꽤나 많은 품이 드니까 다이나믹본 코드를 수정해보자. 그런데 코드에 타임스케일을 곱해주면 오류가 난다. 하지만 변수를 별도로 할당해서 처리하면 오류가 나지 않는다. 왜지…?!
뭐 일단 작동하니까 넘어가도록 하자.