[GAS] 어두운 던전에서 캐릭터가 사라질 때

2026. 5. 4. 17:47·Dev./UE 언리얼 엔진
반응형

 

던전은 어두워야 한다. 그러나 플레이어 캐릭터까지 완전히 묻히면 게임플레이 문제가 된다.

이번 이슈는 캐릭터 전면이 너무 어둡게 표현되는 문제에서 시작한다.

현실 조명 기준으로는 자연스러운 결과일 수 있다.

그러나 게임에서는 플레이어가 자신의 캐릭터를 즉시 읽을 수 있어야 한다.

이 글은 어두운 분위기를 유지하면서 캐릭터만 살짝 보정하는 UGS_CharacterFillLightComponent 구현 과정을 정리한다.

 

이 글을 읽으면 다음 내용을 얻을 수 있다.

  • 어두운 던전에서 캐릭터 가독성이 무너지는 원인을 파악한다.
  • Light Channel(라이트가 영향을 줄 대상을 나누는 조명 그룹)로 환경 조명과 캐릭터 조명을 분리하는 방법을 이해한다.
  • Fill Light(어두운 면을 부드럽게 메우는 보조광)와 Rim Light(캐릭터 외곽선을 살리는 테두리광)를 구성한다.
  • Unreal Engine 5에서 조명 단위, 생성 시점, 메시 채널 문제를 어떻게 트러블슈팅하는지 확인한다.


문제 정의: 캐릭터는 보여야 한다

던전 내부에서 Ambient Light(방 전체에 깔리는 기본 밝기)가 매우 낮아지자 캐릭터 얼굴과 몸통이 거의 보이지 않았다.

횃불과 벽의 색감은 정상인데, 플레이어 메시 전면이 검게 무너졌다.

 

이 문제는 전체 밝기를 올리면 쉽게 해결되는 것처럼 보인다.

그러나 그렇게 하면 던전의 긴장감도 함께 사라진다.

따라서 해결 목표는 환경을 밝히는 것이 아니라, 플레이어 캐릭터만 읽히도록 만드는 것이다.

이 지점에서 조명 문제는 단순한 비주얼 문제가 아니라 게임플레이 가독성 문제가 된다.


해결 방향: 환경 조명과 캐릭터 조명을 분리한다

핵심 전략은 캐릭터 전용 조명을 만든 뒤, 환경과 서로 간섭하지 않게 분리하는 것이다.

이를 위해 Unreal Engine의 Light Channel을 사용한다.

 

Light Channel은 조명과 메시 사이의 연결 규칙이다.

일상적인 비유로 말하면, 같은 방에 있어도 특정 스피커의 소리를 특정 이어폰에서만 듣게 하는 방식과 비슷하다.

라이트가 존재하더라도 메시가 그 채널을 받지 않으면 영향을 받지 않는다.

 

이번 설계는 다음 원칙을 따른다.

  • 던전 탐험의 어두운 분위기는 유지한다.
  • 플레이어 캐릭터에만 살짝 거짓 조명을 적용한다.
  • 환경 라이트와 캐릭터 라이트를 Light Channel 1로 분리한다.
  • 횃불, 벽, 바닥 같은 환경 라이트는 기존 Channel 0만 사용한다.
  • 캐릭터 메시에는 Channel 0과 Channel 1을 모두 켠다.

이 방식은 정확한 물리 조명보다 플레이어 인지성을 우선한다.


블루프린트 구조: BP_Seeker_Merci에 전용 컴포넌트를 붙인다

해결책은 BP_Seeker_Merci에 GS_CharacterFillLight 컴포넌트를 추가하는 방식으로 구성한다.

BP_Seeker_Merci (Self)
├── Anim State Component (AnimState)           [C++]
├── Camera Manager Component (CameraManager)   [C++]
├── Character Movement (CharMoveComp)          [C++]
├── Capsule Component (CollisionCylinder)      [C++]
│   ├── Arrow Component (Arrow)
│   ├── Mesh (CharacterMesh0)                  [C++]
│   │   ├── VisualMesh                         ← bAutoApplyMeshChannels로 자동 처리
│   │   └── SpringArm → Camera
├── GS_CharacterFillLight                      ← 추가한 캐릭터 조명 보정 컴포넌트
├── GS_BowCamera / GS_SeekerControl / GS_PresentationCamera
├── Health Component / Motion Matching / MotionWarping / PresentationPose

메시의 Light Channel 설정은 다음과 같이 정리한다.

메시 또는 라이트 Channel 0 Channel 1 비고
VisualMesh 켬 켬 실제 렌더 메시이므로 필수다.
CharacterMesh0 켬 켬 Skeletal Mesh Asset이 할당된 경우 필요하다.
환경 라이트 켬 끔 횃불 등 기존 조명은 변경하지 않는다.
Fill/Rim Light 끔 켬 캐릭터 전용 조명으로만 사용한다.

bAutoApplyMeshChannels = true가 기본값이면 BeginPlay에서 Owner의 모든 SkeletalMesh(뼈대 애니메이션이 있는 캐릭터 메시)에 Channel 1을 자동 적용한다. 따라서 블루프린트에서 별도 초기화 노드를 연결하지 않아도 된다.


구현: UGS_CharacterFillLightComponent

구현 파일은 다음 위치에 둔다.

Source/GAS/Public/Character/Component/GS_CharacterFillLightComponent.h
Source/GAS/Private/Character/Component/GS_CharacterFillLightComponent.cpp

이 컴포넌트는 두 개의 조명을 생성한다.

  • Fill Light는 UPointLightComponent로 만든다.
    • Point Light(전구처럼 사방으로 퍼지는 점 조명)는 얼굴과 전면부를 부드럽게 밝히기 좋다.
  • Rim Light는 USpotLightComponent로 만든다.
    • Spot Light(손전등처럼 방향과 콘 범위가 있는 조명)는 뒤쪽 어깨와 머리 윤곽을 살리기 좋다.

Rim을 Spot Light로 만든 이유는 기능뿐 아니라 디버깅 경험 때문이다.

에디터 뷰포트에서 방향 화살표가 보이면 Fill과 Rim을 빠르게 구분할 수 있다.

컴포넌트의 주요 기능은 다음과 같다.

기능 설명
OnRegister 생성 에디터, PIE, 런타임 모두에서 라이트를 생성한다. 블루프린트 뷰포트에서 즉시 확인 가능하다.
Light Channel 분리 Fill과 Rim 모두 Channel 1만 사용한다. 환경광 Channel 0과 분리한다.
ELightUnits::Unitless UE5 물리 단위 대신 게임 튜닝용 단위를 사용한다.
bAutoApplyMeshChannels BeginPlay에서 모든 SkeletalMesh에 Channel 1을 자동 적용한다.
PostEditChangeProperty 디테일 패널 값 변경 시 뷰포트에 즉시 반영한다.
DrawDebugVisualization 값 변경 시 5초간 Fill 구체와 Rim 구체·콘을 시각화한다.
MakeUniqueObjectName 중복 생성 시 라이트 이름 충돌을 방지한다.
SetEnvironmentBrightness(0~1) 주변 밝기에 따라 조명 강도를 동적으로 조절한다.

공개 API는 다음과 같다.

// 메시 Light Channel 수동 설정
// bAutoApplyMeshChannels = false인 경우 사용한다.
void InitializeWithMesh(USkeletalMeshComponent* TargetMesh);

// 환경 밝기 기반 동적 강도 조절
// 0.0 = 완전 어두운 던전 → MaxIntensity
// 1.0 = 횃불 근처 → MinIntensity 수렴
void SetEnvironmentBrightness(float Brightness);

// 직접 접근용 API
UPointLightComponent* GetFillLight() const;
USpotLightComponent*  GetRimLight()  const;

트러블슈팅 1: 플레이하면 빛이 전혀 나오지 않는다

조명을 만들었는데도 캐릭터가 밝아지지 않는 문제가 있었다.

원인은 메시가 Channel 0만 수신하고 있었기 때문이다.

조명이 Channel 1에만 존재하면, 메시도 Channel 1을 받아야 한다.

이 조건이 맞지 않으면 조명은 정상 생성되어도 화면에서는 아무 변화가 없다.

해결은 bAutoApplyMeshChannels = true로 자동화한다.

 

이 값이 켜져 있으면 BeginPlay에서 Owner의 모든 SkeletalMeshComponent(Unreal에서 스켈레탈 메시를 렌더링하는 컴포넌트)를 찾아 Channel 1을 자동 적용한다.

 

따라서 BP_Seeker_Merci의 EventBeginPlay에서 InitializeWithMesh를 따로 호출할 필요가 없다.


트러블슈팅 2: 에디터 뷰포트에서 라이트가 보이지 않는다

초기 구현은 BeginPlay에서만 라이트를 생성했다.

이 방식은 플레이 중에는 동작하지만, 블루프린트 뷰포트에서 즉시 확인하기 어렵다.

 

해결은 생성 시점을 OnRegister로 옮기는 것이다.

OnRegister는 컴포넌트가 에디터, PIE, 런타임에 등록될 때 호출된다.

 

이 변경 후에는 컴포넌트를 추가하고 컴파일하면 Fill/Rim 라이트 아이콘이 즉시 보인다.


트러블슈팅 3: 강도를 올려도 변화가 거의 없다

Unreal Engine 5의 조명은 기본적으로 Candelas(현실 조명의 밝기를 나타내는 물리 단위)를 사용한다.

이는 사실적인 렌더링에는 좋지만, 캐릭터 보정용 게임 조명에는 튜닝 감각이 맞지 않을 수 있다.

 

이번 문제에서는 Intensity를 올려도 기대한 만큼 얼굴이 밝아지지 않았다.

물리 단위 기반 조명에서는 값의 스케일이 직관적이지 않았기 때문이다.

 

해결은 ELightUnits::Unitless를 사용하는 것이다.

Unitless를 쓰면 1.0~5.0 정도의 값으로도 조명 보정 결과를 빠르게 읽을 수 있다.


트러블슈팅 4: 라이트 이름 충돌이 발생한다

에디터에서 컴포넌트가 반복 등록되면 고정 이름으로 생성한 라이트가 충돌할 수 있다.

같은 Owner 안에서 같은 이름의 서브오브젝트를 다시 만들려 했기 때문이다.

 

해결은 MakeUniqueObjectName을 사용하는 것이다.

이 함수는 같은 이름이 이미 존재할 때 안전한 고유 이름을 만든다.

에디터 반복 작업과 PIE 재실행에서도 안정성을 확보한다.


트러블슈팅 5: Fill과 Rim을 구분하기 어렵다

초기에는 Fill과 Rim을 모두 Point Light로 만들었다.

기능적으로는 가능하지만, 에디터에서 두 라이트를 구분하기 어렵다.

 

해결은 Rim을 USpotLightComponent로 바꾸는 것이다.

Spot Light는 방향을 가진다.

덕분에 에디터에서 방향 화살표가 표시되고, Rim이 캐릭터 뒤쪽에서 어느 방향을 향하는지 즉시 확인할 수 있다.


Fill Light 기본값

Fill Light는 캐릭터 얼굴과 전면이 완전히 묻히지 않도록 만드는 조명이다. 분위기를 망치지 않아야 하므로 밝게 때리는 조명이 아니라, 어두운 면을 살짝 들어 올리는 조명으로 설계한다.

항목 값 이유
Type Point Light 얼굴과 상체를 부드럽게 밝힌다.
Intensity 3.0 Unitless 분위기를 유지하면서 얼굴 가독성을 확보한다.
MinIntensity 0.3 횃불 근처에서도 얼굴 완전 암전을 방지한다.
Color (1.0, 0.88, 0.68) 따뜻한 앰버 색으로 횃불 반사처럼 섞인다.
AttenuationRadius 120 좁은 던전 통로에서 벽 번짐을 줄인다.
RelativeOffset (40, 0, 70) 얼굴에 더 가깝게 둔다.
Light Channel Channel 1 only 환경광과 분리한다.
Cast Shadow false 성능 비용과 의도치 않은 그림자를 줄인다.

Attenuation Radius(빛이 영향을 주는 거리)는 크게 잡을수록 넓게 퍼진다.

캐릭터 전용 보정에서는 너무 넓게 잡으면 주변 벽까지 의도치 않게 밝아 보일 수 있으므로 절제한다.

Relative Offset(부모 컴포넌트를 기준으로 한 상대 위치)은 캐릭터 앞쪽과 얼굴 높이를 기준으로 잡는다.

조명의 목적이 캐릭터 전면 가독성이기 때문이다.


Rim Light 기본값

Rim Light는 캐릭터의 외곽선을 배경에서 분리하는 조명이다.

어두운 던전에서는 캐릭터와 벽이 같은 어둠으로 붙어 보이기 쉽다. Rim은 이 경계를 끊어준다.

항목 값 이유
Type Spot Light 어깨와 머리 윤곽을 방향성 있게 비춘다.
Intensity 5.0 Unitless Rim이 Fill보다 강해야 실루엣이 살아난다.
MinIntensity 1.0 어느 환경에서도 윤곽 정의를 유지한다.
Color (0.5, 0.72, 1.0) 쿨블루 색으로 주황 횃불과 보색 대비를 만든다.
AttenuationRadius 150 Fill보다 넓게 어깨와 머리를 커버한다.
RelativeOffset (-70, 0, 90) 후면 위쪽에서 윤곽에 닿도록 둔다.
RelativeRotation Pitch -40° 후면 위에서 캐릭터 중심을 향하게 한다.
InnerConeAngle 15° 집중된 림 라이트를 만든다.
OuterConeAngle 35° 과한 번짐을 막는다.
Light Channel Channel 1 only 환경광과 분리한다.
Cast Shadow false 성능 비용을 줄인다.

Cone Angle(스포트라이트가 퍼지는 각도)은 Rim Light의 품질을 크게 좌우한다.

Inner Cone은 중심부의 강한 영역이고, Outer Cone은 바깥으로 부드럽게 사라지는 영역이다.

Outer가 너무 넓으면 캐릭터 조명이 아니라 공간 조명처럼 보인다.

 

중요한 점은 특정 숫자 하나가 정답이 아니라, Fill은 얼굴 가독성, Rim은 실루엣 분리를 담당한다는 역할 분리다.


블루프린트 적용 순서

실제 적용 순서는 다음과 같다.

1. BP_Seeker_Merci를 연다.
2. 컴포넌트 패널에서 "+ 추가"를 누른다.
3. GS Character Fill Light Component를 추가한다.
4. 컴파일한다.
5. 뷰포트에서 Fill/Rim 라이트 아이콘을 확인한다.
6. 디테일 패널의 Character Fill Light 카테고리에서 값을 조정한다.
7. 값 변경 시 5초간 표시되는 디버그 구체와 콘을 확인한다.
8. bAutoApplyMeshChannels = true 상태를 확인한다.
9. 플레이테스트에서 캐릭터 전면과 실루엣이 읽히는지 확인한다.

이 과정에서 EventBeginPlay에 별도 초기화 노드를 추가하지 않는다.

컴포넌트가 메시 채널 적용을 자동 처리하기 때문이다.

 

동적 밝기 조절: 횃불 근처에서는 조명을 줄인다

캐릭터 전용 조명은 항상 같은 강도로 켜져 있으면 부자연스러울 수 있다.

완전히 어두운 방에서는 강하게 필요하지만, 횃불 근처에서는 약해져야 한다.

이를 위해 SetEnvironmentBrightness(0~1) API를 사용한다.

// 완전히 어두운 방에서는 MaxIntensity에 가깝게 보정한다.
SetEnvironmentBrightness(0.0f);

// 횃불 근처처럼 밝은 곳에서는 MinIntensity에 수렴한다.
SetEnvironmentBrightness(0.8f);

이 값은 환경 밝기를 0에서 1 사이로 정규화한 값이다.

정규화를 하면 다양한 방, 횃불, 포스트 프로세스 환경에서도 같은 로직으로 조명 강도를 제어할 수 있다.

이 구조는 Diablo 4처럼 던전 깊이나 주변 밝기에 따라 캐릭터 조명을 자동 보정하는 방식으로 확장할 수 있다.


디버깅 경험도 설계의 일부다

조명은 숫자만으로 판단하기 어렵다.

에디터에서 바꾼 값이 즉시 보이고, 조명의 위치와 범위를 눈으로 확인할 수 있어야 반복 작업이 빨라진다.

그래서 컴포넌트는 PostEditChangeProperty와 DrawDebugVisualization을 포함한다.

PostEditChangeProperty는 에디터 디테일 패널에서 값이 바뀔 때 호출되는 함수다.

이 함수 덕분에 Intensity, Color, Offset 같은 값을 바꾸는 즉시 뷰포트에 반영한다.

 

DrawDebugVisualization은 Fill을 주황 구체로, Rim을 하늘색 구체와 콘으로 5초간 표시한다.

이 시각화는 디버그용이지만, 실제 작업에서는 생산성 기능에 가깝다. 조명 범위를 눈으로 확인하면 튜닝 시간이 크게 줄어든다.


성능 최적화 관점에서 본 선택

이번 구현은 단지 보기 좋게 만드는 작업이 아니다. 성능 최적화도 함께 고려한다.

 

첫째, Fill과 Rim 모두 Cast Shadow = false로 둔다.

캐릭터 보정 조명은 그림자를 만드는 목적이 아니다.

그림자를 켜면 추가 비용이 발생하고, 캐릭터 위에 의도치 않은 어두운 결과가 생길 수 있다.

 

둘째, Light Channel로 영향 대상을 캐릭터로 제한한다.

조명이 환경 전체에 영향을 주지 않으므로 시각적 부작용을 줄인다.

 

셋째, AttenuationRadius를 제한한다.

캐릭터 전용 조명이 던전 벽과 바닥까지 넓게 번지는 상황을 줄인다.

 

넷째, 동적 강도 조절을 둔다.

밝은 곳에서는 조명 강도가 MinIntensity에 가까워지므로 과한 보정을 피한다.

최종 트러블슈팅 요약

증상 원인 해결
플레이 시 빛이 전혀 나오지 않는다 메시가 Channel 0만 수신한다 bAutoApplyMeshChannels = true로 SkeletalMesh에 Channel 1을 자동 적용한다.
에디터 뷰포트에서 라이트가 보이지 않는다 BeginPlay에서만 라이트를 생성한다 OnRegister에서 생성해 에디터에서도 보이게 한다.
강도를 높여도 변화가 거의 없다 UE5 기본 단위가 Candelas다 ELightUnits::Unitless로 바꿔 게임 튜닝 단위를 사용한다.
라이트 이름 충돌이 발생한다 고정 이름으로 중복 생성한다 MakeUniqueObjectName을 사용한다.
Fill/Rim 구분이 어렵다 두 라이트가 모두 Point Light다 Rim을 Spot Light로 변경해 방향 화살표를 표시한다.

Before / After

반응형

'Dev. > UE 언리얼 엔진' 카테고리의 다른 글

AI를 Unreal Editor 안으로: UnrealAgent  (0) 2026.06.15
[GAS] UE 5 멀티플레이어 미니맵 : DX12 투명화 버그와 GPU 크래시 문제  (0) 2026.05.26
[GAS] 포탈 Niagara VFX 개선 방향 기록  (1) 2026.04.05
[GAS] Runtime Retarget ABP 적용 후 모션이 나오지 않던 문제  (0) 2026.04.05
[GAS] VFX 최적화 컴포넌트 붙였다가, BP 구조 문제를 만났다...  (1) 2026.04.05
'Dev./UE 언리얼 엔진' 카테고리의 다른 글
  • AI를 Unreal Editor 안으로: UnrealAgent
  • [GAS] UE 5 멀티플레이어 미니맵 : DX12 투명화 버그와 GPU 크래시 문제
  • [GAS] 포탈 Niagara VFX 개선 방향 기록
  • [GAS] Runtime Retarget ABP 적용 후 모션이 나오지 않던 문제
raindrovvv
raindrovvv
raindrovvv 님의 블로그 입니다.
  • raindrovvv
    raindrovvv 님의 블로그
    raindrovvv
  • 전체
    오늘
    어제
    • 분류 전체보기 (188) N
      • Dev. (181) N
        • AI 인공지능 (38) N
        • UE 언리얼 엔진 (87)
        • Unity 유니티 (0)
        • Wwise 와이즈 (7)
        • 게임 네트워크 (8)
        • 그래픽스 Graphics (22)
        • 프로젝트 (9)
        • 기타 개발 관련 (10)
      • Computer Science (0)
        • 하드웨어 HW (0)
        • 소프트웨어 SW (0)
        • 통신 (0)
        • 데이터 (0)
      • 블로그 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Git
    Wwise
    생산성
    dev
    unrealengine
    깃
    게임개발
    에이전트
    언리얼
    언리얼엔진
    바이브코딩
    트러블슈팅
    UE
    인디게임
    그래픽스
    Unreal
    TA
    devlog
    네트워크
    AI
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.3
raindrovvv
[GAS] 어두운 던전에서 캐릭터가 사라질 때
상단으로

티스토리툴바