3.22

기본적인 방향성은 정립했으니 이제 자연물을 만들어보자. 킷배시는 프랍만을 제공해주기 때문에 터레인을 어찌만들 것인가? 에 대한 고민이 먼저 필요하다. 블렌더에서 기본제공되는 Landscape를 사용해보자. 기본적으로는 꺼져있고, 애드온탭에서 켜주어야 한다.

이걸로 언덕이나 산등을 만들어서 렌더링하면 좋을 것이다.

3.23

감기로 인해 하루 휴식.

3.24

킷배시에서 내려받은 풀은 아무래도 폴리곤이 많다. 줄여야 한다.

사이클 프로젝션은 알파를 지원하지 않는다. 따라서 수동으로 렌더를 걸어서 뭉치별로 짤라주고, 폴리곤을 나누어 주어야 한다. 최근 자동화에 익숙해지다보니 이런 작업이 꽤 성가시게 느껴진다.

배치에 오류가 있었다. 아이고 … 다시 해야 한다. 내일 하자.

3.25

나뭇잎을 짜르던 도중 의문이 생겼다. 격자를 꼭 넣어야 할까…? 테스트해보자.

차이가 1도 없네…?! 그냥 안짜르기로.

오늘의 깨달음. 버텍스를 움직일 때 G를

  • 한 번 누르면 UV를 깨뜨리며 자유 이동
  • 두 번 누르면 엣지를 따라 이동
  • 세번 누르면 UV를 깨뜨리지 않고 자유 이동

이다. 이걸 왜 작업 다 끝날 때 깨달아가지고 흑흑.

본격적인 작업에 앞서 나뭇잎이 잘 움직이는지 테스트가 필요하다. 역시나 제대로 움직이지 않았고, 볼만하게 움직이도록 손을 봐 준다.

나무는 카메라 이동에 대해 예상보다도 더 평면적으로 움직인다.

그래도 깊이 차이를 준다고 준건데… 흐음. 더 주어볼까

풀은 준비했으니 이제 심어보자

원경은 나무를 일일이 심기보단, 만들어진 이미지를 사용하는 편이 효율적일 것 같다. 이런 건 AI에게 맡기면 좋다.

https://civitai.com/models/4468/counterfeit-v30

회사 다닐 때 썼던 체크포인트. 배경은 얘가 일을 가장 잘한다. 다운로드 받고, 설치하고 기다리자.

스테이블 디퓨전은 생각보다 메모리를 많이 먹는 모양이다. 전에 이걸 구동 시키고 게임을 실행한 적이 있는데, 프레임이 현저하게 떨어지는 걸 볼 수 있었다.

아차. 실수로 오렌지 믹스를 사용해 돌렸다. 체크포인트를 바꾸고…(말은 왜 그렸어…)

멋지긴 한데, 좀 더 청명했으면 좋겠다.

좋다. 더할 나위가 없다. 하늘까지 완벽.

잘 어울린다. 물레방앗간은 빼고 초원위의 집으로 바꾸자.

나무를 진짜로 많이 심으면 퍼포먼스 뿐 아니라 컨트롤도 어렵기 때문에 몇개를 모아서 그려준다.

공사장 장막 같이 생겼다. 실제로 공사할 예정.

대략적인 배치는 끝났다. 작은 풀들은 베이킹된 그림자를 토대로 색을 정해야 한다. 셰이더에 G채널이 필요할 것이다. 일단 구워보자.

나무는 버텍스 컬러의 G채널을 통해 색을 양감을 준다. 이를 그림자를 통한 버텍스 컬러 베이킹으로 할 수 있을 줄 알았건만, 마음에 드는 결과물이 나오지 않아 결국은 수동으로 처리해 주었다.

나무는 일단 된 것 같은데, 유니티로 넘겨서 느낌을 보자.

처음 넘기면 참으로 막막한 상황.

비슷하게 잘 넘어온 것 같으니 이제 디테일을 추가해 보자.

숲 배경의 완료.
이 프로젝트를 처음 시작하며 그리고 싶었던 풍경, 캐릭터의 눈을 메쉬가 아닌 셰이더로 처리한 이유가 바로 이 영상에 있다. 캐릭터에게 드리워지는 나무 그림자는 툰 렌더를 진행하며 꼭 해보고 싶었던 것이다.

숲을 진행하며 얻은 결론. 식생을 공유해 사용하는 것은 어려운 일이다. 스테이지마다 색상이 다를 것이므로 그냥 그때그때 만드는 것이 생각할 것이 적고 더 다채롭다.

이제 테스트해보고 싶은 배경은 노을, 밤, 비.. 정도가 남았다. 밤과 비는 확실히 역광이고, 노을은 어찌될지 모르겠다.

배경 #4

3.21

베이킹 작업을 기준으로 작업하다 보니 중간에 오브젝트 추가가 쉽지 않다. 다음 작업을 할 때엔 좀 더 수월하게 할 수 있지 않을까?

풀이 살랑거려야 하기에 Plants셰이더가 또 필요하다. sin(_Time.y)값을 잘 비벼보자.

살랑살랑. sin함수를 이용한 셰이더는 이 이상 움직이면 모양이 일그러진다.

이후의 배경 퀄리티를 어디까지 올릴 것인가…? 를 두고 고민 중

베이킹 후엔 디자인을 바꿀 수는 없고 약한 플라스터 정도가 전부인 것 같다.

하지만 뭔가 허전한 건 여전해서… 어찌할까 고민하던 끝에

애랑 한 물감놀이 질감을 적용해 보기로 했다.

?!? 잘 어울리네?!

3.22

최종적인 배경의 그래픽 방향성 정립했다. 사실 대부분의 방향이 렌더링할 때 결정되기는 한다. 처음에 만들 때 잘 만드는 게 중요할 듯. 6살 꼬마의 물감 놀이는 바닥 퀄리티 상승에 아주 큰 역할을 했다.

사실 이 뒤에선 막 응원하는 NPC들이 있어야 진짜 끝이 나는 거긴 한데… 그걸 어찌 만들지는 생각을 안해봤다. 어려운 과제인만큼 천천히 고민을 해보기로 하자.

첫 배경이 끝났다. 이 배경은 킷배시에서 제공하는 무료 모델만 가지고 만들었다. 이제는 (정말로) 유료결제를 해야 할 시간이 아닐까

배경 #3

3.18

최종적인 룩을 만들 때 필요한 방향성을 정하자. 생각보다 채도가 높은 배경이 어울리지 않는다.

3.19

늘 그랬듯이, 베이킹은 완벽하지 않다. 하지만 좀 더 신경을 쏟는다면, 어느 정도는 커버가 될 것이다.

작업속도를 늦추는 요인은 대부분 망설임이다. ‘이거 맞나?’라는 생각. 하지만 결국 고생한만큼 보람이 있다. 내일은 언랩을 펴보자. UVPack Master가 작동하지 않는데,아마 버전업이 된 모양이다.

https://blendermarket.com/products/uvpackmaster

UV Pack Master의 가격은 $44. 대충 5만원 정도 하는데, 충분히 돈값을 한다.결과물을 보면 바로 알 수 있다.

이걸 언제 하고 있겠는가.

프로젝션으로 인해 생기는 애매한 부분들이 있다. 이런걸 최소화해주려면 메쉬를 사용하는 방법밖에는 없으니, 폴리곤을 더 사용해 보자.

시행착오로 인해 UV를 펴고 펴고 또 펴고…

대체로 잘 구워졌지만 요부분의 해상도가 좀 약하니 강조해주자.

하지만 이걸 하려면 전체가 흐트러진다. 나름 멋있는데..?!

가까이서 보면 조금 흐트러지지만, 이 정도면 충분하다.

메쉬 파트는 생각보다 잘 구워졌다. 이제 플래너 파트를 만들어보자.

요로케 구우면

잘 그려준다.

하나 아쉬운 것은 직교뷰로만 그려준다는 것.

3.20

삽질을 거듭해서 1차 베이킹을 끝냈다.

이제 이걸 엔진으로 넘겨보자.

아이고 크다. 먼저 배경용 셰이더가 필요하다.

하지만 그래봐야 언릿/컷아웃이다.

경계선 부분이 생각보다 더 거슬리는데, 이를 해결할 방법을 찾아야 한다.

하늘을 깔고..

그림자 셰이더를 만들자. 공부해야 할 것이 좀 있을 줄 알았는데 생각보다 구현이 쉽다. 오브젝트 포지션에서 버텍스의 위치를 클립기준으로 바로 변환하는 것을 일단 월드 기준으로 바꾸고 y를 0으로 조작한다.(2를 곱한 것은 그림자가 너무 짧게 표시되기 때문이다.)

OUT.positionWS = TransformObjectToWorld(IN.positionOS.xyz);                
OUT.positionWS.z = OUT.positionWS.y * 2;
OUT.positionWS.y = 0;
OUT.positionHCS = TransformWorldToHClip(OUT.positionWS.xyz);

그림자는 원본메쉬를 쓰기엔 좀 아깝다. 때문에 프록시를 만들어서 붙이는 편이 좋다.

심플리곤이 없으니 그냥 블렌더에서 기본제공하는 Decimate : 0.1, 그리고 그림자가 너무 얇으니 볼품이 없어서 Fatten 0.005를 주어서 조금 두껍게 해주었다. 그런데도 폴리곤이 6300개 정도 된다.

하지만 메쉬 셰도우는 평면에서만 쓸 수 있다. 따라서 바닥에 그리는 오브젝트와의 큐문제가 있을 수 있기 때문에 배경보다 큐를 하나 더 높게 주어 항상 출력되도록 하자.

이제 배경보다 항상 위에 출력된다. 배경 아래로 들어가는 것보다야 이 쪽이 나을 것이다.

이제 다른 캐릭터들의 그림자를 생성해야 한다. 하지만 오늘은 타임오버.

3.20

그림자는 공통된 머티리얼을 사용하고 있으며 스테이지마다 그림자의 색을 변경할 수 있도록 설계되어 있다. 다만 빛 방향에 따라서 각도가 변하지는 않는다. 이는 역광이어도 마찬가지인데, 원리대로라면 그림자도 반전되는 것이 옳지만 이 경우 캐릭터의 위치를 빠르게 파악하는 정보역할을 하기 때문이다.

그 다음은 바닥에 오브젝트를 좀 더 추가해 보자. 지금은 너무 심심한 느낌이 든다.

배경 #2

3.15

배경은 모델링을 구입해서 배치한 후, AI를 통해 텍스처링을 할 예정이다. 이 텍스처링 기술은 (주)너디스타(https//nerdystar.io)가 보유하고 있으며, 난 지인찬스로 첫 베타테스터(?)가 되었다.

툴을 받아서 처음으로 돌려보다보니 이런 저런 오류가 보였다. 개발을 하다 보면 문제는 매일 터진다. 처음부터 끝까지, 공정은 완벽하지 않다. 매일이 시행착오의 연속이다.

버그를 수정하는 것은 시간이 걸리기 때문에, 작업은 병렬로 진행해야 한다. 남는 시간에 다른 일을 해보자. 현재의 시스템으로는 캐릭터에 그림자를 드리우기 위해서 투명오브젝트를 사용해야 하는데, 이 셰이더를 개발해두는 편이 좋겠다.

챗GPT에게 물어보니, ShadowCaster라는 라이트모드가 있다고 한다. 해보니 정말로 된다! 오오.

이 오브젝트는 면을 컬링하는 게 아니라, 그림자만 계산하는 것이다. 뎁스와 렌더링 부분이 필요없으니 이 부분을 없애고 셰이더를 가볍게 만들어준다.

이는 캐릭터에게 나무 그림자를 드리우는데 사용할 예정이다. 조명은 정면에서 때리는데, 나뭇잎이 화면을 가리면 안되니까 이런 꼼수를 사용한다.

이것이 빌드를 해도 잘 나올지 테스트해보아야 한다.

배포용 빌드화면. 잘 나온다. 야호

이제 킷배시를 결제할 시간이다.

3.15

킷배시를 결제하기 전에 테스트가 좀 더 필요하다.

근사한 집 3채를 준비했다.

오…!? 확실히 박스보단 좀 더 괜찮은 결과를 보여준다.

한 번 느낌을 보자.

아쉬운 결과가 나왔다. 꽤나 커다란 오브젝트임에도 불구하고, 옆면이 그렇게 잘 보이지는 않는다. 이는 캐릭터를 잘 살리기 위해서 원근을 매우 줄여놓았기 때문이다.

이-렇게 길게 늘여보았지만… 생각보다 잘 보이지 않는다. 흐음.

그렇다면 3D모델을 그대로 사용하는 것의 잇점이 크지 않아 보이는데…

하지만 그것은 사이즈가 충분히 크지 않아서일지도 모른다는 생각.

3.16

여러가지 가능성을 놓고 테스트 중. 씬을 원하는대로 컨트롤할 수 있는 마음이 반, 또 매핑이 그리기 귀찮은 마음이 반. 하지만 절충안은 없는 상황.

여전히 고민 중.

3.18

제작 방식에 대해선 거의 정립은 했다. 배경은 어차피 플랜을 사용할 예정인데, 실루엣만 보고 AI가 이 물건이 무엇인지 맞출 수 있을까?

어..음.. 못알아먹는다.

아래는 모델 직접렌더링 테스트.

사이클렌더가 나쁘지 않지만, 조금 밋밋한 느낌이 있다.

AI는 포기하고, 모델을 바로 쓰되, 렌더링 샷에 리터칭을 하는 방향으로 가는 편이 좋아보인다.

오늘의 깨달음. 유니티의 FoV(Field of View)는 Vertical을 기준으로 씌여진다. 이를 블렌더와 맞추려면 축을 Horizontal로 바꾼 후 변경되는 값을 들고가야 한다. 블렌더는 가로/세로 선택이 없고, 무조건 가로기준으로 계산한다.

원경의 자잘한 오브젝트들은 Plane을 쓸 예정이다. 초안은 통샷을 렌더해서 누끼를 딸 예정이었으나….

플랜을 대고 노마진으로 프로젝션하면 오브젝트 단위로 잘 뽑아준다. 알파까지 예쁘게!

그런데 AO도 구워지고 있는 거 맞나?

맞다. 잘 구워지고 있다.

원경은 대체로 플랜을 사용할 것이다. 메쉬엔 컬러만 지정할 것이니 UV를 펼 필요가 없고, 폴리곤도 절약된다. 문제는 근경이다. 이건 실제 메쉬를 사용해야 한다. 조명상태를 베이킹하기 위해 UV도 펴야 하니 일이 좀 귀찮아진다. 하지만 이 정도는 해야 할 것이다…아마도.

테스트를 하느라 너덜너덜해진 해적의 집.

남은 것은 식물이다. 그림자는 베이킹 시에 고정된다. 하지만 식물은 바람에 흔들려야 한다. 어렵게 생각하면 셰도우, AO패스를 따로 분리해 저장한 뒤, 유니티의 그림자 감쇠값을 받아서 합성해주면 될 것 같은데, 그렇게 수고스럽게까지 작업하고 싶지는 않다. 잘 될지도 모르겠고…식물은 별도로 생각하기로 하자. 그게 아니더라도 해야 할 일은 많으니까.

타격 효과 강화

3.13

배경을 만들기 위해서 필요한 툴을 기다려야 하기 때문에, 남는 시간에 전에 구상해두었던 이펙트를 만들어 보기로 하자. 직접적인 파티클 타격 효과는 아니고, 때렸을 때 삐죽이는 셰이더 효과와 빛이다. 만화에서 보듯 충격이 가해졌을 때 고양이가 털을 세우는 것처럼 몸의 일부가 뾰족하게 보였으면 좋겠다.

원리는 배면법과 같다. 단지 부분부분 적용된다는 것 뿐이다. 이제 이걸 타점에서 뻗어나가도록 벡터화 시켜주어야 한다. 타점을 구한 후엔 빛도 추가할 수 있을 것이다.

타점을 벡터 프로퍼티로 뺀다. 이는 당연히 월드좌표로 계산될 것이다. 그렇다면 현재 버텍스 셰이더에서 오브젝트를 HClip으로 바로 변환하던 것을 버텍스만 월드변환해서 섞은 뒤 WorldToHClip으로 바꾼다. 그런데 이런 함수가 있던가…? 있다! ( UNITY_MATRIX 형제 쓰기 싫어.)

이제 타점을 계산해서 맞을 때 넣어주어야 한다. 코드 계산으로 넘어가자.

타점은 충돌박스끼리 충돌했을 경우, 그 중심점을 구하면 될 것이다. 이런 건 챗GPT가 잘 알 것 같다.

using UnityEngine;

public class ManualOverlapCenter : MonoBehaviour
{
public BoxCollider2D boxCollider1;
public BoxCollider2D boxCollider2;

void Update()
{
if (boxCollider1 != null && boxCollider2 != null)
{
// 첫 번째 박스컬라이더의 경계를 구합니다.
Vector2 min1 = boxCollider1.bounds.min;
Vector2 max1 = boxCollider1.bounds.max;

// 두 번째 박스컬라이더의 경계를 구합니다.
Vector2 min2 = boxCollider2.bounds.min;
Vector2 max2 = boxCollider2.bounds.max;

// 겹친 영역의 최소 및 최대 지점을 구합니다.
float minX = Mathf.Max(min1.x, min2.x);
float minY = Mathf.Max(min1.y, min2.y);
float maxX = Mathf.Min(max1.x, max2.x);
float maxY = Mathf.Min(max1.y, max2.y);

// 겹친 영역의 중심점을 계산합니다.
Vector2 overlapCenter = new Vector2((minX + maxX) / 2f, (minY + maxY) / 2f);

// 겹친 영역의 중심점을 출력합니다.
Debug.Log("Overlap Center: " + overlapCenter);
}
}
}

테스트는 안해봤으나 언뜻 보기에는 맞는 것 같다. 타점은 구했는데, 이걸 셰이더 코드와 연동해주어야 한다. 캐릭터 셰이더 중 해당 프로퍼티가 있는 셰이더를 골라낸 후에, 데미지를 입을 때 값을 변경해 주어야 한다.

…는 타임오버. 내일 해보도록 하자.

러프한 구현 결과, 타점을 중심일 땐 꽤 괜찮은 결과를 보여주지만, 타점이 아래나 위일 땐 그렇게 인상적이지가 않다. 그렇다면 그냥 항상 중간일 때 출력하면 어떨까?

오.. 훨 괜찮은 듯?

3.14

효과가 괜찮은 것 같으니, 셰이더 전반에 추가를 해야 한다. 얼굴이나 눈에는 필요가 없고, 큰 덩어리를 구성하는 셰이더에만 추가하면 될 것이다.

그런데 그랬더니 너무 많이 뾰족하다… 좀 줄여보자.

0.005정도면 어떨까

적당해 보이긴 하는데, 헤어에 적용된 건 얼굴을 너무 많이 뚫는다. 손에는 선이 너무 많다.

헤어는 빼고, 말단부는 제외하는 편이 좋아보인다.

…로 하려다가 헤어는 역시 아쉬워서 추가하고 말단부와 무기만 제거했다. 추가로 랜덤 버텍스는 0.003으로 줄였다.

가시가 얼굴을 뚫는 현상이 많으니, 아무래도 뒤로 배치하는 편이 좋을 것 같다.

한결 좋아보인다.

다음은 타격 시 빛효과…인데, 타임오버. 내일 하자.

TEXCOORD7을 쓰는 날이 올 줄은… 자리가 꽉 찼다.

타점을 기반 DOT연산을 해서 옴니라이트처럼 뿌릴 것이다.

이것은 Distance이다. 이걸 곱해주면

요렇게 되는데… 왜 칼이 안나오지?

무언가..무언가 잘못됐다.

…라고 생각했는데, 플레이를 하면 또 잘 된다. 뷰포트에서 실시간 적용에 문제가 있는 모양.

일단 타점을 중심으로 한 빛은 구현했다. 타격효과는 플레이어마다 색이 다를테고, 이 빛이 데미지를 입은 플레이어에게 뿌려져야 한다.

완성된 구현. 음. 하지만 이것이 썩 괜찮아 보이지는 않는다…

음.. 아닌가? 쓸만한가..?

얼굴에는 왜 안나오지…?

히트 벡터는 제대로 들어온다… 흐음.

원인을 찾았다. 얼굴에는 가시를 일으키지 않기 때문에 타점 갱신이 안되고 있었다.

이젠 눈이 문제. 입은 괜찮아 뵈는데…

이렇게 플레이어에 따라 색을 바꿔줄 예정.

이제 눈동자에도 색깔이 먹는다. 눈동자는 남기고 싶었는데, 채널이 모자라서 그만.

셰이더 손댄김에 전부터 손보고 싶었던 역광 볼드 코드를 집어넣어보자.

역광의 색은 배경을 완성한 후 씬 제어 컴포넌트에서 처리해줄 예정이다.

완성된 것 같으니 이제 다른 캐릭터에게도 삐죽을 심어주자.

밤 배경엔 백라이트를 바꿔주어 분위기를 맞출 수 있다. 역시 역광은 예쁘다.

이제 셰이더에서 할 수 있는 것은 다 한 것 같으니 다시 배경으로 돌아가자.

배경 #1

3.12

드디어 배경 작업이다. 여느 작업처럼 이것도 몇 가지 준비 과정이 필요하다. 처음부터 모든 걸 제작하기는 힘이 드니 모델을 구입해 사용할 예정이다. 지인이 알려준 킷배시와 웹툰 준비 때 자주 들락거렸던 에이콘을 이용해 보자.

https://kitbash3d.com

https://acon3d.com

에이콘은 다양한 모델이 있지만 스케치업 파일이 대부분이 공수가 다소 들어간다. 스케치업에서 fbx로 내보내기를 통해 블렌더로 임포트해야 하기 때문. 킷배시는 월별 구독제로 모든 모델 이용이 가능하고 전용앱으로 블렌더에 바로 임포트가 된다. 이걸 주력으로 쓰되 부족한 것들은 에이콘에서 채우는 식으로 작업하기로 하자.

으음- 할인 폭이 크긴 하지만, 1년이나 쓸 것 같지는 않아…

이런 모델들은 대체로 폴리곤이 너무 많아서 게임에서는 바로 쓰긴 힘드니까, 심플리곤을 미리 깔아두자. 블렌더에도 Decimate가 있지만 심플리곤이 더 최적화를 잘 해준다.

https://www.simplygon.com

그런데 SDK를 받는 곳이 없네…?! 사이트가 바꼈다… 어찌된 일이지.

백방으로 방법을 찾아보았지만, 예전처럼 SDK를 무료로 제공하지는 않는다. 차라리 유료로 팔면 좋겠는데 무조건 B2B인 모양이다. 30일 무료버전 신청란에 회사이름과 도메인을 반드시 적으라고 되어 있다.

에이…그럼 이건 못쓰겠네… 그냥 Decimate를 써야겠다.

3.12

작업에 앞서 스테이지를 좀 길게 만들자. 그러려면 카메라 워킹이 필요하다.

모든 작업의 시작과 끝은 스파2가 있다. 이 오래된 게임의 스크롤방식을 벤치마킹했는데, 이것이 생각보다 어려운 과제였다. 캐릭터들은 가까이 있거나 화면 끝에 있다면 스크롤 되지 않고, 일정거리 이상 벌어져야 스크롤 된다. 그대로 구현하되, 카메라가 갑자기 튈 경우를 방지해 이동에 Lerp를 약간 넣었다.

스크롤이 있으니 확실히 공간이 넓어 보인다. 얼마나 넓어야 할까…일단은 10미터로 책정. 너무 멀어도 도망치는 적을 잡기 피곤하니, 충분해 보인다. 상하 스크롤은 정신 사나워서 취향이 아니므로 건너뛰고, 확대 축소는 작업량이 많으니 포기하자.

잡기 마무리 작업

3.9

바탕이 되는 작업은 끝났으나 여전히 일이 남아있다. 먼저 만들었던 작업들의 피격모션을 각캐릭터에 맞게 복사해주어야 한다. 또한 던지기 후 좌우가 뒤집히는 문제를 해결해야 한다. 그리고 타격형 잡기의 경우, 몇 번을 칠 지 스크립트에서 제어할 수 있게 코드를 수정해야 한다. 그 외에 작업보드에 적혀있는 버그들도 수정하고 가도록 하자.

유저는 같은 캐릭터를 고를 수 있어야 하므로 앨리스에게도 앨리스에게 잡히는 모션이 필요하다. 하지만 같은 파일을 링크할 수는 없으니 임시 파일을 만들어 진행해야 한다. 피격모션은 달래를 기준으로 제작된 것인데, 키에 큰 차이가 없어 그대로 사용해도 무방해 보인다. 앨리스의 발 잡기에 DamageSlam이 들어가므로, 이 모션도 함께 가져와야 한다.

GetUpSlam모션은 달래의 모션으로 일어나게 된다. 이것을 앨리스의 모션으로 바꿔주어야 한다.

잡기를 위해 데미지 모션은 4가지의 스테이트가 더 필요하다.

  • DamageFlying
  • DamageSlam
  • DamageSlamLying
  • GetUpSlam

지금까지 설정한 앨리스의 스테이트는 60개 정도 된다. 남은 것은 도발(D버튼), 등장 2개, 승리 2개, 스핀형 데미지, 스턴, 필살기 3개, 초필살기.. 아이고, 아직도 많구나!

작업 중 통일성이 없는 부분이 발견됐다. 앨리스의 허리는 Euler를 사용하고, 닐리의 허리는 쿼터니온을 쓴다. 이렇게 되면 작업이 호환이 되지 않기 때문에 확실하게 정의하고 가야 한다. 오일러를 쓸 필요가 없으므로 쿼터니온이 옳다. 하지만 이걸 해결하기 위해선 앨리스로 거슬러 올라가야 한다. 모든 애니메이션의 오일러 키를 쿼터니온으로 변경해 줄 것인가? 문제가 생기는 모션만 부분적으로 변경해줄 것인가…

스크립트가 필요하다. 구상은 잠자리에서. 오늘은 여기까지.

3.11

오일러를 쿼터니온으로 변환한다. 구상은 쉬웠는데, 구현이 꽤 어려웠다. 이제 챗GPT없으면 작업못할 듯.

이렇게 오일러로 되어 있는 키를

요로케 쿼터니온 변환해 준다.

ARP에도 회전값 변환기가 들어있기는 한데, 사용이 불편해서 새로 만들었다. Euler모드를 맞춰놓고 돌려야 제대로 작동하는 걸로 보아 비주얼키를 베이킹하는 모양이다. 게다가 액션그룹 지정도 안해줘서 목록이 밖으로 빠져나간다… 여러모로 언젠가는 해야 할 작업이었다.

이제야 다음 스텝으로 넘어갈 수 있다. 내일 하자..

오로라가 오로라를 잡았을 때. 아이고 작다. 이런 문제 때문에 Caught모션을 완전히 공유해 쓸 수가 없다. 사실 키가 같더라도 세컨더리 애니메이션 문제도 있긴 하다.

그래서 오로라는 다리를 쭉 편채로 맞아야 한다.

원래 멱살을 잡아 채는 모션인데… 오로라의 키가 작아서 머리채를 끌어당기게 됐다(…) 유독 오로라에게 더 가혹해져 버린 닐리.

이걸로 피격자의 모션은 일단락됐다.

이제 좌우 반전 문제를 해결해 보자. 좌우를 반전해 쓰고 있으니 완전히 해결할 수는 없고, 움직임이 큰 시점에 반전 모션을 미리 바꿔주어야 한다.

하지만 반전을 시키는 방법은 어렵다. 일단 모든 키를 반전시키는 방법은 내가 아는 한 블렌더에서는 지원하지 않는다. 다시 스크립트가 필요하다.

데이터를 살펴보니 원리는 단순하다. 반전할 수 있는 키의 리스트를 뽑은 후에 위치는 x, 회전은 y,z를 반전해주면 된다.

…하지만 이걸 굳이 해야 하는가?

모션을 2개로 나눈 후의 세컨더리 애니메이션은 생각보다 일이 크다. 잡기 애니메이션은 사실 상당히 러프하게 만들었는데, 수량이 너무 많기 때문이다. 모든 걸 제쳐두고 돌아가게 하는 것이 중요하다.

그렇다면 이건 포기하는 편이 낫겠다. 뭣이 중헌디.

오로라의 잡기

3.6

오로라는 잡기 캐릭터인만큼 잡기 기술이 많을 예정이지만, 스킬을 제외하고 제작 중인만큼 기본잡기만 구현하기로 한다. 기계팔로 잡기가 생각보다 이미지가 안떠올라서 킥잡기를 먼저 작업 중

요렇게 올라가서…

요렇게 때릴 예정.

피격자의 시작 애니메이션도 완료. 애니메이션은 타격자 중심으로 만들어지기 때문에, 키가 다를 경우 피격자의 애니메이션은 조금씩 달라져야 한다.

3.7

이제 마무리 공격. 쾅! 피격자의 상하가 뒤집히지 않기 때문에 Flying이 아닌 DamageJumpHeavy로 연결되는 편이 자연스러울 것이다. 이제 엔진에 넣어보자.

얍얍얍! 잘 작동하는 것 같다. 이 잡기는 기존과는 달리 모든 행동이 끝난 후에 방향이 변하지 않는데, 이에 대한 처리가 추가로 필요하다.

내일은 지인에게 배경 제작법을 전수받으러 가야 한다. 따라서 앨리스가 반대방향으로 날아가는 문제는 모레 처리하도록 하자.

3.8

강펀치잡기. 원래 계획은 잡은 후 바닥에 쾅! 내리찍을 예정이었지만, 내리찍은 후의 방향이 DamageSlam과 맞지 않아서 관두었다. 타격형 잡기가 워낙 어려워서인지 던지기는 이제 좀 수월하게 느껴진다. 엔진에 넣어보자.

잘 작동한다. 이로서 오로라의 기본잡기 모션도 일단락이 되었다.

하지만 잡기 작업이 온전히 끝난 것은 아니다. 잡기 후에 좌우 반전 문제를 해결하고, 피격자의 모션들을 복사해서 각 캐릭터에게 붙여주어야 한다. 그리고 유니티의 애니메이션 컨트롤러에 클립으로 등록도 해주어야 한다.

달래의 잡기

3.4

닐리에 비한다면 달래의 잡기는 심플하다. 때문에 엔진 확인 작업 할 것도 없이 바로 디테일 작업에 들어갔다. 별달리 삽질이 없어서 기록할 것이 적다.

3.5

강펀치용 잡기. 엔진에 적용을 완료. 이것도 의도했던 건 아닌데 달래가 꽤나 속도감있는 캐릭터가 됐다. 나쁘지 않아 보인다.

2번 잡기 러프. 어깨위에 올라갈 땐 오로라를 염두해두어야 한다. 모션을 맞추려면 키가 가장 작은 캐릭터에 맞추어야 하기 때문이다.

달래의 잡기 모션 완료. 이제 고민되는 오로라의 차례.

닐리의 잡기

2.28

닐리의 잡기에 들어가기 전에 중요한 사실을 하나 깨달았다. 지금까지는 잡기 세트를 만들 때 캐릭터의 방향을 반대로 놓고 만들었는데, 링크로 가져온 캐릭터는 게임오브젝트처럼 스케일을 반전시켜도 애니메이션이 깨지지 않는다! 그러므로 캐릭터의 방향을 맞춰서 애니메이션을 만들면 좀 더 나은 품질의 애니메이션을 제작할 수 있다.

▲이렇게 잡기가 끝났을 때 데이터 상으로 변화가 일어나며 좌우가 바뀌는 것이 못내 아쉬웠는데, 이런 현상을 방지할 수 있다.

하지만 이걸 하려면 기존의 애니메이션을 모두 반전시켜야 한다. 조금 귀찮다… 그래도 해 보자.

반전은 키가 있는 프레임을 돌며 ctrl+c -> ctrl+shift+v를 누르면 된다. 이 때 새로운 키가 생기는 걸 원치 않으니 Replace로 조절해준다.

물론 코드를 조금 수정해주어야 한다. 성공이다! 이제 매우 깔끔하게 일어난다.

닐리는 처음엔 예상에 없었던 선생님 이미지가 나왔으니 강손 잡기는 궁디팡팡! 잡은 후에 여러번 때리는 형태로서, 상대가 버튼을 마구 누르면 좀 빠르게 벗어날 수 있다. 달심의 꿀밤때리기나 브랑카의 깨물기 형태의 잡기다. 이를 위해서 잡기는 기본, Loop, End. 총 3가지로 세분화되어야 한다.

코드는 나중의 일이다. 일단 애니메이션을 만들자.

그동안 때렸으니 이제 좀 맞자. 앨리스.

둘 다 무기는 다 어디 갔나…싶지만, 뭣이 중헌디?! 애니메이션 제작 도중 로브에 컬러가 튀는 건 … 왜 그럴까… 내일 심층분석을 해봐야겠다. 오늘은 여기까지.

2.29

닐리의 로브가 튀는 현상은 본이 엉켜있었던 것이 원인으로 파악됐다. 일단은 다행스러운 일.

오늘의 깨달음. 루프 애니메이션을 도입부와 이어지게 만들고 별도의 파일로 분리해낼 때엔 키를 복붙하기보단 액션전체를 카피한 후 중간키를 삭제하는 편이 낫다. 0프레임에는 트랜스폼 이외의 키들이 생각보다 많이 설정되어 있기 때문이다.(회전모드나 제약조건의 영향력 등)

엔드 모션은 테스트가 좀 필요해서 넣어보려니 문제가 많다. 스테이트 매니저를 공용으로 옮기고, 발생했던 버그를 잡고, 그 외에도 한참 리팩토링… 마음이 급해도 코드는 최대한 차근차근 진행해야 나중에 일이 적다.

오늘의 깨달음 2. FSM을 처음 시작할 때 LateUpdate()가 왜 있는지 알게 됐고, 스테이트 처리를 하면서 Awake()가 왜 있는지도 알게 됐다. Start()에서 마땅히 있어야 할 정보가 없을 때, 그리고 그 순서가 ‘얘 다음’이라고 장담할 수 없을 때 미리 만들어둘 확실한 절차가 필요한 것이다.

코드작업을 마무리하지 못했다. 현재는 잡기 관련 코드를 FSM에서 처리하고 있는데, 이걸 게임매니저로 옮겨야 한다. 오늘은 여기까지.

3.1

잡기 코드를 게임매니저로 옮겼다가 다시 개별캐릭터로 가져왔다. 상대방의 FSM을 조작하는 건 월권이라 생각해서 게임매니저로 옮기려고 했던 건데 괜한 삽질이었다. 달리 생각하면 애초에 잡기 자체가 상대방을 조작하는 것인지라 이 쪽에서 처리하는 게 맞는 것 같기도 하고…결국은 눈물의 롤백. 시간만 날렸다.

어쨌거나 코드는 완성됐다. 남은 것은 상대가 발버둥을 치면 좀 더 일찍 잡기가 풀려야 하는 것인데, 2P입력을 아직 안만들었다(…) 뭐, 중요한 것은 아니니 나중에 실제 데미지 처리 하면서 함께 풀도록 하자.

이제 애니메이션 디테일작업에 들어가야 하지만 타임오버. 오늘은 여기까지.

3.2

익스포트한 데이터는 완벽하지 않다. 이는 게임 엔진이 제약조건 기반으로 움직이는 것이 아니라 베이킹된 키에 의해 움직이기 때문이다.(다리가 땅에 붙지 않고 덜덜 떨리는 것을 볼 수 있다.)

이에 대해 프로젝트에 블렌더를 사용하고 있는 지인과 이야기를 했었는데, 키프레임 압축률에 의해 애니메이션이 깨지고 있다는 결론을 얻었다! 처음엔 ARP의 익스포트 문제일거라 생각했는데 내보낸 FBX를 블렌더로 임포트해본 결과, 데이터는 아무런 문제가 없었다. 이럴 수가! 유니티의 최적화 문제였다니.

키프레임 리덕션을 하고 회전 오차를 기본값인 0.5에서 0.1로 줄여주었더니

발이 정상적으로 땅에 붙어 작동한다. 이것이 최적화에 얼마나 악영향을 끼칠 지는 모르겠지만, 적어도 문제를 해결할 방법을 찾았다는 점이 고무적이다.

문제 2번. 잡기를 한 캐릭터를 반대편으로 던져보낼 경우 캐릭터가 반전된다. 이 경우 무기를 쥔 손이 반전되기 때문에 임시로 차일드를 왼손에서 오른손으로 변경해줄 필요가 있다. 제약 조건 중에 Child Of를 양손에 걸고 Influence에 키를 주면 될 것이다. 그런데 이것이… 안된다. 차일드 오브가 2개 이상될 경우 프레임 지연현상이 일어난다.

테스트 결과, 이것이 렌더링을 할 때는 문제가 없다. 제약 조건이 여러 개일 경우, 실시간 뷰포트의 연산을 줄이기 위해 이런 선택을 한 것으로 보인다. 이것이 실시간 익스포트를 할 경우 문제가 된다. 이건 일전에 목이 달랑거리는 현상과 비슷한 문제로 보이는데, 결국 메모리의 문제로 결론이 났었고

단순한 구조로 테스트를 해본 결과는 정상인 것으로 보아, 그 가설에 더욱 힘이 실리는 분위기이다. 그렇다면 이건 답이 없다…별 수 없이 그냥 매프레임 노가다를 해주는 수밖엔. 데이터가 너무 무거운 모양이다.

하지만 삽질은 결국 도움이 되는 무언가를 남긴다. 이 오차를 해결할 수 없을까?싶어 옵션을 뒤지던 중에 애니메이션 오토키프레이밍에서 ‘Only Insert Needed’란 옵션을 발견했다. 이 옵션은 트랜스폼 3대장에 모두 키를 주지 않고 움직인 트랜스폼에 대해서만 키를 준다. 이동과 회전값의 키 이격은 매우 흔하게 발생하므로 이 옵션은 상당히 유용하다. 소득은 있었다!

발 잡기(→K). 윙가르디움 레비오사!

아.쓰다보니 Only Insert Needed가 별로 안편하다[…] 왜 기본값이 꺼져있는지 이해하게 되었다.

닐리의 잡기도 완료!