TECHARTNOMAD | TECHARTFLOWIO.COM

TECH.ART.FLOW.IO

[번역] UE5 Shell-Fur 모발 렌더링 구현

jplee 2025. 10. 23. 13:37

저자: 주웬(朱文)

들어가며

G-Fur 플러그인

안녕하세요. 이번 글에서는 UE5.1 환경에서 Shell-Fur 방식을 활용한 털 렌더링 구현 과정을 공유하고자 합니다.

작년 헤어 렌더링 작업을 진행하면서 동물 털을 표현하는 흥미로운 방법을 접하게 되었습니다. Mesh를 여러 층으로 겹쳐 쌓고, 각 층을 외부로 확장한 뒤 노이즈 텍스처를 활용하여 모발 효과를 시뮬레이션하는 방식입니다.

구현 방식 비교

주요 구현 방식으로는 다음과 같은 방법들이 있습니다:

1. SkeletalMesh를 다중으로 복제하는 방식

  • 문제점: 좋은 품질을 위해서는 수십 개의 레이어가 필요하며, 각 레이어마다 애니메이션을 업데이트해야 하고 GPU에서 동적 배칭이 되지 않아 성능 부담이 큽니다.

2. 커스텀 배칭을 통해 DrawCall 감소

  • 문제점: 관련 자료가 주로 Unity 위주이며, Unreal에서 Pass를 추가하는 것은 엔진 수정이 많이 필요합니다.

3. InstancedStaticMesh 활용 (본 글의 접근 방식)

  • 장점: 각 레이어가 StaticMesh이며, InstancedStaticMesh가 자동으로 배칭을 처리하여 CPU 성능이 크게 향상됩니다.
  • 단점: GPU 버텍스 애니메이션을 위해 두 장의 텍스처가 필요하고, WorldPositionOffset을 사용하므로 GPU 연산과 메모리 부담이 증가합니다.

구현 결과

1.1 정적 모발 구체

기본적인 모발 구체의 렌더링 결과입니다.

1.2 라이팅 효과

다양한 조명 조건에서의 모발 표현을 확인할 수 있습니다.

1.3 바람 효과가 적용된 모발 구체

바람에 반응하는 동적인 모발 시뮬레이션입니다.

1.4 GPU 버텍스 애니메이션 기반 여우 꼬리

본 글의 핵심 부분입니다. GPU 버텍스 애니메이션을 활용하여 StaticMesh에 애니메이션 효과를 구현했습니다. 모발이 움직이지 않으면 다른 효과들이 무의미하기 때문에 이 부분이 매우 중요합니다.

1.5 ISMC 자동 배칭

InstancedStaticMeshComponent의 자동 배칭 기능을 확인할 수 있습니다.


구현 원리 및 단계

2.1 Shell-Fur 모발 렌더링

구현 원리

Shell-Fur는 고전적인 알고리즘으로, "Generating Fur in DirectX or OpenGL Easily" 논문에서 소개된 방법입니다.

주요 과정은 다음과 같습니다:

  1. 모델을 여러 층(MaxLayers)으로 복제합니다
  2. 각 층은 현재 레이어 번호(StaticLayers)와 레이어 간 간격(LayerStep)에 따라 버텍스 노멀 방향으로 일정 거리(StaticLayers * LayerStep)만큼 확장됩니다
  3. 노이즈 텍스처를 샘플링하여, 정규화된 노멀 확장 거리와 노이즈 샘플 결과를 비교하여 표시 여부를 결정합니다

UE5 구현

1. InstancedStaticMesh를 통한 다중 인스턴스 생성

블루프린트로 구현하였습니다. Actor를 생성하고 InstancedStaticMeshComponent(이하 ISMC)를 추가합니다.

성능 절약을 위해 그림자 투사 기능을 비활성화합니다.

BeginPlay에서 반복문을 통해 여러 인스턴스를 생성합니다.

주요 함수 설명:

AddInstance 함수: ISMC의 인스턴스를 생성합니다

SetCustomDataValue 함수: CustomData를 설정합니다. 이 데이터는 머티리얼에서 PerInstanceCustomData 노드를 통해 읽어올 수 있으며, 이를 활용하여 GPU 버텍스 애니메이션 제어 및 각 인스턴스에 레이어 정보를 전달합니다.

함수 파라미터:

  • CustomDataIndex: 각 인스턴스는 여러 CustomData를 가질 수 있으며, 이 ID로 특정 CustomData를 지정합니다
  • CustomDataValue: CustomData의 값

현재는 하나의 CustomData만 사용하며, 그 값은 레이어 번호입니다.

UpdateInstanceTransform 함수: 각 인스턴스의 위치를 설정합니다. 여기서는 모두 동일한 위치로 설정합니다.

2. Shell-Fur 모발 머티리얼 생성

다중 레이어 Mesh가 준비되었으니, ISMC의 CustomData에 접근할 수 있는 머티리얼을 만듭니다.

머티리얼 BlendMode 설정이 필요하며, WorldPositionOffset을 통해 각 레이어가 노멀 방향으로 확장되는 효과를 구현합니다.

Unreal은 PBR 기반이므로 Metallic과 Specular를 낮추고 Roughness를 높게 설정합니다. BaseColor를 지정하면 초기 구현이 완료됩니다.

초기 결과

모발 구체의 기본 형태가 구현되었지만, 발광하는 듯한 부자연스러운 모습입니다. ISMC의 그림자 투사를 비활성화했기 때문이며, 다음 단계에서 렌더링과 물리 효과를 추가로 구현하겠습니다.


2.2 AO 시뮬레이션

2.2.1 구현 원리

이전 단계에서 발광하는 모발 구체가 만들어졌는데, 이는 비현실적입니다. 그림자 투사를 비활성화했기 때문에 AO를 시뮬레이션하여 레이어 간 깊이감을 표현해야 합니다.

  • 베이스 색상보다 어두운 내부 색상(InsideColor)을 추가합니다
  • 현재 모발 레이어(StaticLayers)와 전체 레이어 수(MaxLayer)의 비율을 Lerp의 Alpha 값으로 사용하여, 레이어가 증가할수록 내부 색상에서 모발 색상으로 전환됩니다
  • 최종 결과를 BaseColor 노드에 출력합니다

Alpha = Saturate(StaticLayers / MaxLayer)
BaseColor = Lerp(InsideColor, BaseColor, Alpha)

특수한 상황 처리가 필요한 경우:

  1. 짧은 털로 인한 전체적인 어두움 문제
  2. 피부 색상과 모발 내부 색상의 혼합 문제

2.2.2 UE5 구현

머티리얼 그래프에서 위 로직을 구현합니다.

2.2.3 구현 결과

AO 추가 전후 비교를 통해 뚜렷한 깊이감 향상을 확인할 수 있습니다.


2.3 모발 타입 시뮬레이션

2.3.1 구현 원리

  1. 다양한 노이즈 텍스처: 노이즈 텍스처를 교체하여 다양한 모발 타입을 구현할 수 있습니다
  2. Tiling 파라미터: 2.1절에서 구현한 Multi-Fur 알고리즘에 Tiling 파라미터를 추가하여 모발 밀도를 조절할 수 있습니다
  3. 커브를 통한 두께 제어: 현재 모발은 뿌리에서 끝까지 선형적으로 가늘어지는데(StaticLayers / MaxLayer), 커브를 추가하여 두께 변화를 제어할 수 있습니다

2.3.2 UE5 구현

Curve와 CurveAtlas 리소스를 생성합니다.

CurveAtlas에 Curve를 바인딩하고, 머티리얼에서 CurveAtlasRowParameter 노드를 생성하여 Curve와 CurveAtlas를 할당합니다.

비교를 위해 세 가지 커브를 준비하여 각각 R, G, B 채널로 출력합니다.

2.3.3 구현 결과

1. 노이즈 텍스처 비교

다양한 노이즈 텍스처를 통한 모발 패턴 변화를 확인할 수 있습니다.

2. Tiling 계수 비교

Tiling 값에 따른 모발 밀도 차이를 비교할 수 있습니다.

3. Alpha 커브 비교

서로 다른 커브를 통한 모발 두께 변화를 확인할 수 있습니다.


2.4 UV 오프셋

모발이 계속 부풀어 있는 상태를 개선하기 위해, 레이어에 따라 UV를 오프셋하는 방법을 사용합니다. 각 레이어가 노이즈 텍스처를 샘플링할 때 특정 방향으로 일정량 오프셋을 적용합니다.

float2 uvoffset = StaticLayers * UVOffsetVector.xy * 0.1;
OpacityMask = SampleTexture(NoiseTexture, TexCoord[0] + uvoffset).r;

2.4.1 UE5 구현

해당 모듈 출력을 2.1절의 NoiseTexture UV 입력 노드에 연결합니다.

2.4.2 구현 결과

UVOffset의 오프셋 방향을 조정하여 다양한 효과를 얻을 수 있습니다.


2.5 Fresnel 기반 윤곽광

2.5.1 원리

모발 구체는 부위별 두께에 따라 투과도가 다릅니다. 일반적으로 모발이 희박한 부분이 밀집된 부분보다 투과도가 높습니다. 모발 구체의 경우 가장자리가 더 밝아야 합니다.

Fresnel 방정식을 사용하여 모발 구체 가장자리의 하이라이트 윤곽광 효과를 시뮬레이션할 수 있습니다.

Fresnel 방정식 (Fresnel-Schlick 근사 사용)

2.5.2 UE5 구현

다행히 UE에서 Fresnel 방정식 노드를 직접 제공하므로 하이라이트 구현이 간단합니다.

모듈의 출력을 Emissive Color에 연결합니다.

2.5.3 구현 결과

왼쪽은 비윤곽 조명이고 오른쪽은 윤곽선 조명입니다

윤곽광 추가 전후를 비교하면 가장자리의 밝기 차이를 확인할 수 있습니다.


2.6 서브서피스 스캐터링

2.6.1 구현 원리

여기서는 비교적 간단한 Fast Subsurface Scattering을 구현합니다.

주요 수식:

float3 L = gi.light.dir;
float3 V = viewDir;
float3 N = s.Normal;

float3 H = normalize(L + N * _Distortion);
float I = pow(saturate(dot(V, -H)), _Power) * _Scale;

2.6.2 UE5 구현

해당 모듈을 EmissiveColor에 출력합니다.

2.6.3 구현 결과

카메라를 점광원 방향으로 향하게 하면, 모발 구체를 투과하는 서브서피스 스캐터링 효과를 확인할 수 있습니다.


2.7 이방성(Anisotropic) 하이라이트

고전적인 Kajiya-Kay 모델을 사용하여 이방성 하이라이트를 시뮬레이션합니다.

2.7.1 UE5 구현

상륙하지 않는 프로젝트, 아무렇지도 않게 연결됨

머티리얼 그래프에서 공식을 직접 연결하여 구현합니다.

2.7.2 구현 결과

이방성 하이라이트가 적용된 모발 렌더링 결과를 확인할 수 있습니다.


2.8 중력 시뮬레이션

2.8.1 구현 원리

포물선 공식을 사용하여 모발에 대한 중력 효과를 시뮬레이션합니다:

S1 = N * StaticLayers * LayerStep;
S2 = 0.5 * g * pow(StaticLayers * LayerStep / GravityParam) * (0,0,-1)
WorldPositionOffset = S1 + S2

2.8.2 UE5 구현

머티리얼 그래프에서 위 공식을 구현합니다.

구현 결과

UV 오프셋 효과와 비교했을 때, 중력 시뮬레이션 효과가 더 자연스럽습니다.

상단이 UV 오프셋 효과, 하단이 중력 시뮬레이션 효과입니다.

위쪽 가장자리는 UV 오프셋이고 아래쪽 가장자리는 시뮬레이션된 중력입니다


2.9 바람 효과 시뮬레이션

UE에서 제공하는 SimpleGrassWind 머티리얼 노드를 직접 사용하며, 모발 레이어 번호를 Alpha 값으로 사용하여 선형 보간을 수행합니다. 이를 통해 모발 끝부분이 더 많은 힘을 받고, 뿌리 부분은 더 적은 힘을 받도록 합니다.

2.9.1 UE5 구현

2.1 부분의 WorldPositionOffset 구현을 제거하고(위 모듈에 통합되었음), 이 모듈을 WorldPositionOffset 노드에 연결합니다.

2.9.2 구현 결과

바람에 반응하는 동적인 모발 움직임을 확인할 수 있습니다.


2.10 정적 모델에 애니메이션 적용 (GPU 버텍스 애니메이션)

지금까지 다양한 효과를 구현했지만, 모델이 움직이지 않으면 실제 요구사항을 충족할 수 없습니다. 예를 들어 움직이는 털이 많은 여우 꼬리를 만들려면 애니메이션이 필수입니다.

GPU 버텍스 애니메이션이 이 문제를 완벽하게 해결할 수 있습니다.

애니메이션이 포함된 모델을 준비하고, 2.1-2.10에서 구현한 머티리얼을 이 모델에 적용합니다.

UE5.0 버전 이상에서 정상 작동하는 AnimToTexture 플러그인을 통해 버텍스 애니메이션을 내보냅니다.

플러그인은 두 가지 알고리즘(BoneAnimation, VertexAnimation)을 제공하며, 비교 결과 VertexAnimation이 더 나은 효과를 보였습니다.

버텍스 애니메이션 재생을 제어하기 위해 5개의 CustomData가 도입되었으며, Actor에서 SetCustomDataValue를 통해 설정해야 합니다.

최종적으로 버텍스 애니메이션이 적용된 모발 모델을 구현할 수 있습니다.


발견된 문제점

  1. AO 시뮬레이션 효과에서 짧은 털의 경우 전체 색상이 과도하게 어두워지는 문제
  2. AO 시뮬레이션에서 피부와 모발 내부 색상의 혼합이 고려되지 않음 (대부분의 동물은 모발과 피부 색상에 차이가 있음)
  3. 커브를 통한 모발 타입 제어에서도 짧은 털의 색상이 과도하게 어두워지는 문제
  4. 이방성 하이라이트 효과가 미흡함 (공식 복원에 오류가 있을 가능성)
  5. Unreal은 SkeletalMesh의 동적 배칭을 지원하지 않음

마치며

이번 글에서는 UE5에서 InstancedStaticMesh와 GPU 버텍스 애니메이션을 활용한 Shell-Fur 모발 렌더링 구현 과정을 살펴보았습니다.

도움이 되셨다면 좋겠습니다. 감사합니다.


원문.

(DM 45개 / 메시지 21개) [UE5 연습] 쉘 퍼 헤어 렌더링 - Zhihu