데칼 시스템으로 혈흔과 흔적을 설계하는 법

데칼의 투영 원리와 수명 관리, 셰이더 처리까지 살펴보며 혈흔과 발자국을 안정적으로 구현한다. Unity와 Unreal에서 공통으로 적용할 수 있는 성능 기준도 함께 정리한다.

✓ 복사 완료!
챕터VFX & 파티클 시스템
난이도중급
상태● 검토 완료
대상 엔진
UnityUnreal Engine
최종 업데이트
데칼 시스템으로 혈흔과 흔적을 설계하는 법

데칼이 흔적 연출에 적합한 이유

혈흔, 발자국, 탄흔은 월드의 표면에 붙어 보여야 하지만 대부분 별도의 메시를 만들 필요는 없다. 데칼은 작은 텍스처를 주변 지오메트리에 투영해 표면의 색상, 노멀, 거칠기 같은 속성을 덮어쓰거나 섞는 방식이다. 벽과 바닥의 굴곡을 따라 흔적을 남길 수 있어 파편 메시보다 제작 비용이 낮다.

다만 데칼을 무제한으로 생성하면 드로우 콜, 오버드로우, 메모리 사용량이 빠르게 늘어난다. 따라서 표현 품질만큼 생성 조건과 제거 정책을 먼저 설계해야 한다.

흔적 생성 흐름

피격 지점이나 발 위치에서 레이캐스트로 표면 정보를 얻고 그 결과를 기준으로 데칼을 배치한다. 표면 법선에 맞춰 회전해야 벽과 경사면에서도 자연스럽다.

flowchart LR
    A[이벤트 발생] --> B[레이캐스트로 충돌 표면 탐색]
    B --> C{유효한 표면인가?}
    C -- 아니오 --> D[생성하지 않음]
    C -- 예 --> E[위치·법선·재질 확인]
    E --> F[데칼 풀에서 인스턴스 대여]
    F --> G[크기·회전·수명 설정]
    G --> H[시간 또는 거리 조건으로 반환]

혈흔은 총알 충돌처럼 한 번에 남는 흔적과 캐릭터가 이동하며 떨어뜨리는 흔적으로 나눠 생각하면 좋다. 전자는 충돌 법선과 충격 방향이 중요하고 후자는 이동 거리와 시간 간격이 중요하다.

벽과 바닥에 법선 방향으로 투영된 혈흔 데칼 예시

배치 규칙 만들기

표면 법선으로 회전 정렬하기

데칼의 투영 축이 로컬 전방 축이라고 가정하면 표면 법선을 향하도록 회전시킨다. 여기에 법선 축 주변의 무작위 회전을 더하면 반복감이 줄어든다.

Vector3 normal = hit.normal;
Quaternion align = Quaternion.LookRotation(-normal);
float randomRoll = Random.Range(0f, 360f);
Quaternion rotation = align * Quaternion.AngleAxis(randomRoll, Vector3.forward);

decalTransform.SetPositionAndRotation(hit.point + normal * 0.002f, rotation);

표면에서 아주 조금 띄우는 오프셋은 깊이 충돌로 인한 깜빡임을 줄인다. 값이 너무 크면 벽에서 떠 보이므로 데칼 시스템의 투영 방향과 깊이 설정에 맞춰 작은 값으로 조정한다.

발자국과 피방울의 간격 제어

매 프레임 데칼을 생성하면 캐릭터가 조금만 움직여도 흔적이 겹친다. 마지막 생성 위치와 현재 위치의 거리를 비교해 일정 거리 이상 이동했을 때만 생성한다. 피방울은 걸음마다 정확히 떨어지기보다 거리 조건과 확률을 함께 사용하면 더 자연스럽다.

bool ShouldDropTrail(const FVector& currentPosition)
{
    const float distance = FVector::Distance(currentPosition, LastTrailPosition);
    if (distance < MinTrailSpacing)
    {
        return false;
    }

    return FMath::FRand() <= DropChance;
}

경사면에서 발자국이 과도하게 늘어나는 것을 막으려면 법선의 위쪽 성분을 확인한다. 벽에 가까운 표면은 발자국 대상에서 제외하고 혈흔은 벽에도 남기도록 규칙을 분리하는 편이 좋다.

재질과 셰이더에서 처리할 항목

데칼 텍스처는 색상만 준비하기보다 알파와 마스크를 적극적으로 활용하는 편이 좋다. 가장자리 알파는 흐릿한 번짐을 만들고 별도 마스크는 중앙 농도나 젖은 부분을 제어한다.

혈흔 재질에서 자주 사용하는 요소는 다음과 같다.

  • 색상: 혈액 색상과 가장자리의 건조한 색 변화를 표현한다.
  • 노멀: 얇은 응고 덩어리나 액체 표면의 미세한 굴곡을 더한다.
  • 거칠기: 젖은 혈흔은 낮게, 마른 혈흔은 높게 설정한다.
  • 페이드: 수명 또는 카메라 거리에 따라 알파를 낮춘다.

투명 알파 블렌딩은 겹친 영역의 오버드로우 비용이 커질 수 있다. 가능한 경우 마스크 기반 컷아웃 또는 디더링 페이드를 검토하고 화면을 크게 덮는 데칼은 피한다. 프로젝트의 렌더 파이프라인이 지원한다면 DBuffer 또는 GBuffer 데칼의 제약도 확인해야 한다. 지원하는 재질 채널과 투명 오브젝트에 대한 적용 여부가 다를 수 있다.

거칠기와 노멀 차이로 젖은 혈흔과 마른 혈흔을 구분한 재질 예시

수명 관리와 오브젝트 풀링

흔적은 시간이 지나면 사라져야 할 뿐 아니라 화면과 멀어졌을 때도 정리 대상이 되어야 한다. 가장 단순한 정책은 최대 개수를 정하고 새 데칼이 필요할 때 가장 오래된 데칼을 재사용하는 방식이다.

public DecalInstance Acquire()
{
    if (available.Count > 0)
    {
        return available.Dequeue();
    }

    DecalInstance oldest = active[0];
    active.RemoveAt(0);
    oldest.gameObject.SetActive(false);
    return oldest;
}

public void Release(DecalInstance instance)
{
    instance.gameObject.SetActive(false);
    active.Remove(instance);
    available.Enqueue(instance);
}

풀의 최대 개수는 장면 규모와 카메라 특성에 따라 정한다. 실내 전투처럼 카메라가 자주 되돌아가는 게임은 오래된 흔적도 어느 정도 유지해야 한다. 반대로 빠르게 이동하는 오픈 월드에서는 거리 기반 제거가 더 효과적이다. 중요한 연출용 혈흔은 일반 데칼과 별도 우선순위를 두어 먼저 제거되지 않게 만들 수 있다.

엔진별 확인 사항

Unity에서는 사용 중인 렌더 파이프라인에 맞는 Decal Projector와 Decal Shader를 확인한다. URP와 HDRP는 데칼 기능과 설정 위치가 다르므로 프로젝트 설정에서 데칼 지원 여부, 레이어, 재질 영향을 먼저 점검해야 한다.

Unreal Engine에서는 Decal Actor 또는 Decal Component의 Sort Order, Decal Blend Mode, Fade Screen Size를 확인한다. 같은 표면에 여러 데칼이 겹칠 때는 Sort Order로 우선순위를 정하되 이를 과도하게 세분화하면 관리가 어려워진다.

두 엔진 모두 데칼이 스켈레탈 메시나 투명 재질에 기대한 대로 투영되지 않을 수 있다. 캐릭터 몸에 붙는 피는 일반 데칼보다 메시 파츠, 머티리얼 파라미터, 렌더 타깃 마스크가 더 적합한 경우가 많다.

점검 목록

구현을 마무리할 때는 다음을 실제 플레이 장면에서 확인한다.

  • 경사면과 벽에서 회전 및 투영 방향이 자연스러운가
  • 같은 텍스처가 반복되어 보이지 않도록 크기, 회전, 색상 변형이 있는가
  • 데칼 최대 개수에 도달했을 때 중요한 흔적이 의도치 않게 사라지지 않는가
  • 전투가 길어진 상황에서도 프레임 시간과 오버드로우가 허용 범위에 있는가
  • 조명과 포스트 프로세싱 환경에서 혈흔이 지나치게 검거나 빛나지 않는가

데칼은 작은 기능처럼 보이지만 전투의 밀도와 공간의 기억을 만드는 중요한 도구다. 생성 규칙, 재질 표현, 제거 정책을 하나의 시스템으로 다루면 보기 좋은 혈흔을 넘어 안정적으로 유지되는 흔적 연출을 만들 수 있다.