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이다. 이걸 곱해주면

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

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

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

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

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

얼굴에는 왜 안나오지…?

히트 벡터는 제대로 들어온다… 흐음.
원인을 찾았다. 얼굴에는 가시를 일으키지 않기 때문에 타점 갱신이 안되고 있었다.

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

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

이제 눈동자에도 색깔이 먹는다. 눈동자는 남기고 싶었는데, 채널이 모자라서 그만.
셰이더 손댄김에 전부터 손보고 싶었던 역광 볼드 코드를 집어넣어보자.

역광의 색은 배경을 완성한 후 씬 제어 컴포넌트에서 처리해줄 예정이다.
완성된 것 같으니 이제 다른 캐릭터에게도 삐죽을 심어주자.


밤 배경엔 백라이트를 바꿔주어 분위기를 맞출 수 있다. 역시 역광은 예쁘다.
이제 셰이더에서 할 수 있는 것은 다 한 것 같으니 다시 배경으로 돌아가자.
It’s amazing to see the development come through. So the spikes are just a blend shape? They are triggered in the game when the player gets hit?
I was curious about the way you created the yellow light when the player is hit. Please comment about that setup (why the body lit, but not the face, how did you fix that?)
Thanks!
Awesome blog!
감사합니다. 가시(Spike)는 블렌드 셰이프가 아니예요. 블렌더에서 임의의 점들을 선택해서 버텍스 컬러의 A채널에 저장해서 유니티로 넘긴 후, 유니티의 버텍스 셰이더에서 HitPoint를 중심으로 Position을 변경해준 겁니다. Vertex.pos – HitPoint.pos 는 곧 가시의 방향이니, 이 방향대로 버텍스의 위치를 더해주면 되겠죠. 가시가 표시되는 타이밍은 게임을 하며 시시각각 변할 거고요.
타격시 나오는 노란 빛은 단순한 NDotL연산입니다. 여기에 HitPoint를 중심으로 Distance연산 후에 이 정보를 NDotL과 곱하는 거죠. 얼굴에 이 빛이 표시되지 않던 문제는 그냥 코드를 덜 짜서 발생했던 문제였어요. (몸의 셰이더와 얼굴의 셰이더가 서로 다릅니다.)
도움이 되셨기를 바라요!