본문 바로가기

날씨 및 시간 시스템의 기초

Directional Light와 Sky Light·대기 효과를 시간에 따라 제어하고 비가 전환되는 날씨 시스템을 구성합니다.

같은 마을도 해 질 녘의 붉은 하늘 아래에서 볼 때와 비 오는 밤에 볼 때는 전혀 다른 곳처럼 느껴집니다. 시간과 날씨가 바뀌면 화면의 분위기만 달라지는 것이 아니라, 밤에는 몰래 움직이기 쉬워지고 비가 오면 길이 미끄러워지는 식으로 게임플레이도 달라질 수 있습니다. 그런데 이런 변화를 만들려면 태양의 각도, 하늘의 빛, 구름, 비 효과, 소리를 함께 바꿔야 하고, 여러 블루프린트가 같은 조명을 건드리기 시작하면 서로의 값을 덮어쓰는 문제가 생깁니다.

이 글에서는 낮과 밤이 돌아가는 시간 시스템과, 비가 오고 그치는 간단한 날씨 시스템을 만듭니다. 시간과 날씨를 각자의 블루프린트가 관리하되, 조명에 최종 값을 쓰는 곳은 한 곳으로 모으는 구조를 익히는 것이 목표입니다.


날씨와 시간 시스템이 하는 일

날씨와 시간 시스템(weather and time system)은 게임 월드의 환경 조명, 대기 효과, 기상 현상을 동적으로 바꾸는 구조를 말합니다. 낮과 밤의 주기(day/night cycle)는 태양과 달의 위치를 시간에 따라 바꿔 월드의 조명을 바꾸고, 해돋이와 해넘이 같은 전환을 보여 줍니다. 날씨 변화(weather system)는 비, 눈, 안개, 천둥 번개 같은 기상 현상으로 환경을 바꾸고, 때로는 게임플레이에도 영향을 줍니다.

이런 시스템이 필요한 이유는 여러 가지입니다. 현실과 비슷한 환경 변화는 플레이어의 몰입을 높이고, 같은 레벨도 시간과 날씨에 따라 다르게 보이므로 시각적으로 덜 지루합니다. 게임플레이도 바뀝니다. 밤에는 시야가 좁아져 은신 플레이를 유도하거나 밤에만 나오는 적을 둘 수 있고, 비가 오면 시야가 흐려지거나 바닥이 미끄러워지거나 특정 스킬의 효율이 달라지게 할 수 있습니다. 특정 시간이나 날씨가 이야기의 중요한 배경이 되기도 합니다.


낮과 밤을 만드는 환경 액터

낮과 밤의 주기는 주로 Directional Light, Sky Light, Sky Atmosphere, Volumetric Cloud 액터의 속성을 시간에 따라 바꿔서 만듭니다. 템플릿과 레벨에 따라 이미 배치된 액터가 다르므로, 다음 액터가 있는지 확인하고 없는 것은 추가합니다.

Directional Light는 태양이나 달을 나타내는 광원입니다. 블루프린트에서 회전을 바꾸려면 Mobility가 Movable이어야 하고, Atmosphere Sun Light를 켜서 Sky Atmosphere가 이 광원을 태양으로 쓰게 합니다. 공식 문서에 따르면 광원이 여러 개라면 Atmosphere Sun Light Index로 구분하며, 보통 0번이 태양, 1번이 달입니다. Source Angle은 태양이 하늘에서 차지하는 각도와 그림자의 부드러움에 영향을 줍니다.

Sky Light는 하늘에서 오는 주변광을 캡처해 월드를 비춥니다. Source Type이 SLS Captured Scene이어야 Sky Atmosphere와 Volumetric Cloud의 색 변화를 반영하고, Stationary나 Movable 상태에서 Real Time Capture를 켜면 캡처가 계속 갱신됩니다. 이 글의 예제는 이 방식을 씁니다.

Sky Atmosphere는 지구의 대기를 시뮬레이션해 하늘의 색, 안개, 빛의 산란을 만들고, Volumetric Cloud는 실시간으로 움직이는 구름을 만듭니다. 구름은 성능에 영향을 줄 수 있습니다. Exponential Height Fog는 높이에 따라 짙어지는 안개를 만들며, 선택 사항이고 Sky Atmosphere와 함께 쓸 수 있습니다.


BP_DayNightCycle로 시간 흐르게 하기

이 환경 액터들을 제어할 블루프린트를 만듭니다. Actor를 부모 클래스로 하는 BP_DayNightCycle을 만들고, 다음 변수를 추가합니다.

변수타입과 기본값용도
DirectionalLightDirectional Light 오브젝트 참조레벨의 태양 또는 달 광원입니다. Instance Editable로 두어 배치한 뒤 직접 연결합니다.
SkyLightSky Light 오브젝트 참조주변광을 조절할 Sky Light입니다.
SkyAtmosphereSky Atmosphere 오브젝트 참조대기를 조절할 액터입니다.
VolumetricCloudVolumetric Cloud 오브젝트 참조구름을 조절할 액터입니다.
TimeOfDayFloat, 0.0, 범위 0.0~24.0현재 시간을 24시간 기준으로 나타냅니다.
DayCycleSpeedFloat, 1.0시간이 흐르는 속도입니다. 1.0이면 실제 시간과 같고, 클수록 빨리 흐릅니다.

Tick에서 시간 갱신하기

Event Tick에서는 먼저 TimeOfDay를 FMod(TimeOfDay + DeltaSeconds * DayCycleSpeed / 3600.0, 24.0)으로 갱신합니다. DeltaSeconds는 지난 프레임부터 흐른 실제 초이고 TimeOfDay는 시간 단위이므로, 초를 3600으로 나눠 시간으로 바꿉니다. 여기서는 속도가 음수가 아닌 경우만 다룹니다. FMod는 24로 나눈 나머지를 구하므로, 24시간을 넘었을 때 넘친 만큼을 남깁니다. 블루프린트에서는 이 나머지를 % (Float) 노드로 구합니다. C++ 함수 이름이 FMod인 블루프린트 노드는 Division (Whole and Remainder)인데, 이 노드의 Return Value는 나머지가 아니라 정수 몫이므로 이 노드를 쓴다면 Remainder 출력을 연결합니다. 24를 넘으면 무조건 0으로 되돌리는 방식과 달리, 23.9시간에 0.2시간을 더하면 0이 아니라 0.1시간이 됩니다.

다음으로 직접 만든 Update Sun Position 함수에서 DirectionalLight의 회전을 바꿉니다. TimeOfDay로 태양의 고도인 Pitch와 방위인 Yaw를 계산한 뒤 DirectionalLight에 Set Actor Rotation을 호출합니다. 가장 단순한 식은 Pitch = 90.0 - TimeOfDay * 15.0입니다. 하루 24시간에 360도를 도니 한 시간에 15도이며, 이 식으로는 6시에 0도, 12시에 -90도, 18시에 -180도가 됩니다. 방향광의 회전은 빛이 나아가는 방향이므로, 정오에 -90도이면 빛이 바로 위에서 아래로 내리쬡니다. 이것은 위도와 계절을 계산하는 실제 태양 위치 모델이 아니라 설명을 위한 단순한 식입니다. Yaw는 TimeOfDay에 따라 바꾸거나 고정해 둡니다.

주변광은 Update SkyLight 함수에서 다룹니다. 앞에서 Real Time Capture를 켰으므로 Tick마다 Recapture Sky를 반복 호출하지 않습니다. 수동 캡처 방식을 골랐을 때만 필요한 순간에 Sky Light 컴포넌트의 재캡처를 호출합니다. 시간대별 주변광의 세기는 Sky Light 컴포넌트의 Set Intensity로 조절합니다. 필요하다면 Update SkyAtmosphere나 Update VolumetricCloud 함수를 만들어 대기와 구름의 밀도, 색, 고도 같은 값도 TimeOfDay에 따라 바꿉니다.

이 함수들은 실행 선으로 이어져야 실제로 실행됩니다. Tick의 실행 선은 TimeOfDay 저장, 유효한 DirectionalLight 확인, Update Sun Position, 그리고 선택한 주변광 갱신 순서로 이어 줍니다. 순수 계산 노드를 배치해 두기만 해서는 값이 저장되거나 회전이 적용되지 않습니다. 아직 연결하지 않은 환경 액터의 참조는 먼저 유효한지 확인하고, 유효하지 않다면 그 액터의 갱신을 건너뜁니다.

하루가 넘어가는 순간 계산하기

시간 단위가 맞는지 숫자로 확인해 보겠습니다. TimeOfDay가 23.5이고, DeltaSeconds가 60, DayCycleSpeed가 60인 한 번의 갱신에서는 60 × 60 ÷ 3600 = 1시간을 더합니다. 24.5를 24로 나눈 나머지는 0.5이므로 새 시간은 0.5시간이고, 단순 태양식의 Pitch는 90 - 0.5 × 15 = 82.5도입니다. 실제로 한 프레임이 60초 걸린다는 뜻이 아니라, 입력과 단위를 정해 둔 계산 예입니다. 속도 60은 게임 시간이 실제 시간보다 60배 빨리 흐른다는 뜻입니다.

레벨에 배치하고 연결하기

BP_DayNightCycle을 레벨에 배치하고, 디테일 패널에서 미리 만든 변수 칸에 레벨의 Directional Light, Sky Light, Sky Atmosphere, Volumetric Cloud 액터를 끌어다 놓아 연결합니다. 이 칸은 변수를 Instance Editable로 두었을 때만 보입니다. 칸을 비워 두면 Tick에서 넣은 유효성 확인 때문에 오류 없이 그 액터의 갱신만 건너뛰므로, 플레이했는데 태양이 그대로라면 먼저 이 연결부터 확인합니다. 또 DayCycleSpeed의 기본값 1.0에서는 하루가 실제 24시간이라 태양이 멈춘 것처럼 보입니다. 시험할 때는 배치한 인스턴스에서 이 값을 60으로 바꿔 보면, 실제 1분마다 게임 시간이 1시간 흘러 태양이 15도씩 기웁니다.


BP_WeatherManager로 비 내리게 하기

날씨는 파티클 효과, 오디오, 그리고 환경 액터의 변화로 만듭니다. 여기서는 비를 예로 들며, 파티클은 UE5의 나이아가라(Niagara)를 씁니다. 이전 파티클 시스템인 캐스케이드(Cascade)는 에셋 타입이 다르므로 섞어 쓰지 않습니다.

Actor를 부모 클래스로 하는 BP_WeatherManager를 만들고 날씨의 종류와 강도를 담을 변수를 추가합니다. CurrentWeather는 현재 날씨로, Clear, Rain, Snow 값을 가진 열거형 EWeatherType을 씁니다. RainParticleSystem은 비 효과 에셋을 담는 Niagara System 오브젝트 참조이고, RainSound는 비 소리를 담는 Sound Base 오브젝트 참조, RainIntensity는 0.0에서 1.0 사이의 비 강도입니다. 그리고 BP_WeatherManager에 Niagara Component와 Audio Component를 추가하고, 둘 다 Auto Activate를 꺼서 처음부터 재생되지 않게 합니다.

BP_WeatherManager는 BP_DayNightCycle의 참조도 받아 둡니다. 비가 오면 햇빛을 어둡게 해야 하는데, 두 액터가 각자의 Tick에서 같은 광원의 강도를 설정하면 서로의 값을 덮어씁니다. 그래서 날씨 쪽은 조명에 곱할 날씨 계수만 전달하고, 최종 조명 적용은 BP_DayNightCycle 한 곳에서 하도록 나눕니다.

SetWeather 함수 만들기

날씨를 바꾸는 SetWeather 함수는 EWeatherType 열거형 NewWeatherType과 Float Intensity를 입력으로 받습니다. 먼저 CurrentWeather에 NewWeatherType을, RainIntensity에 Clamp(Intensity, 0, 1)을 저장하고, Switch on EWeatherType으로 분기합니다. 여기서는 Rain과 Clear만 구현하며, Snow는 눈 효과를 따로 준비하기 전에는 고르지 않습니다.

Rain 분기에서는 Niagara Component의 Set Asset에 RainParticleSystem을 연결하고 Activate를 호출합니다. 캐스케이드를 따로 쓴다면 Particle System 컴포넌트의 Set Template 경로로 만들어야 합니다. 소리는 Audio Component의 Set Sound로 RainSound를 지정하고 Play를 호출합니다. 비의 양은 나이아가라 에셋에 사용자 파라미터 User.RainIntensity를 만들어 스폰율에 연결해 두고, 블루프린트에서 Set Niagara Variable (Float)로 RainIntensity 값을 넘겨 바꿉니다. 사용자 파라미터를 만들어 Spawn Rate 같은 모듈 입력에 연결하는 방법은 언리얼 나이아가라 교재의 블루프린트 제어에서 다룹니다. 에셋 안에서 이 파라미터를 스폰율에 연결하지 않으면 이름을 맞춰 값을 넘겨도 비의 양은 바뀌지 않습니다. 조명은 BP_DayNightCycle에 날씨 계수를 넘겨 Directional Light 컴포넌트의 강도를 조절하게 하며, Sky Atmosphere에는 일반적인 Intensity 속성이 있다고 가정하지 않습니다. 날씨에 맞는 분위기는 PostProcess Volume의 Exposure나 Color Grading으로 더할 수 있습니다.

Clear 분기에서는 Niagara Component와 Audio Component를 Deactivate하거나 Stop하고, 조명을 원래대로 돌립니다. 비가 서서히 그치게 하려면 이벤트 그래프의 커스텀 이벤트에서 Timeline을 시작하고, Timeline의 Update가 현재 계수를 적용하는 함수를 호출하게 합니다. Timeline은 일반 함수 안에 넣을 수 없기 때문입니다. 날씨를 일정 간격으로 바꾸고 싶다면 Set Timer by Event를 쓰는데, 이 노드에는 입력이 없는 콜백 이벤트를 연결하고, 그 콜백이 날씨와 강도를 고른 뒤 입력이 있는 SetWeather를 호출하도록 구성합니다.

날씨 계수를 전달하는 최소 연결

이제 날씨 계수를 실제로 연결해 보겠습니다. BP_DayNightCycle에 Float 변수 WeatherLightFactor를 만들고 기본값을 1로 둡니다. 시간대별 태양 강도의 기본값은 BaseSunIntensity로 구하며, 선택한 광원과 같은 강도 단위를 씁니다. 그리고 Float 하나를 받아 이 계수에 저장하는 커스텀 함수 SetWeatherLightFactor를 만들고, BP_WeatherManager에 Instance Editable로 만든 참조에 레벨의 BP_DayNightCycle 인스턴스를 연결합니다.

이 실습에서는 Rain 분기가 Lerp(1.0, 0.4, RainIntensity)를 이 함수에 넘기고, Clear 분기가 1을 넘긴다고 정합니다. 비가 가장 세게 올 때 햇빛을 40%로 줄이겠다는 이 실습의 조명 디자인일 뿐, 실제 날씨에 대한 보편적인 물리식은 아닙니다. BP_DayNightCycle의 최종 갱신에서는 BaseSunIntensity × WeatherLightFactor를 계산해 Directional Light 컴포넌트의 Set Intensity로 적용합니다. 시간 기본값이 10이고 RainIntensity가 1이면 계수는 0.4이므로 최종 강도는 4이고, Clear로 바꾸면 계수가 1이 되어 최종 강도는 다시 10입니다. 이때 비가 올 때의 최종값 4에 다시 계수를 곱하는 것이 아니라, 언제나 시간 기본값에 현재 계수를 곱한다는 점이 중요합니다.

TIME · WEATHER · ONE APPLICATION POINT

시간과 날씨의 입력을 합쳐 조명은 한 곳에서 적용합니다

두 관리 액터가 각각 같은 광원 값을 설정하면 서로의 결과를 덮어쓸 수 있습니다. 본문처럼 날씨는 계수를 전달하고, DayNightCycle이 시간과 결합해 최종 조명을 적용합니다.

시간 기본값과 날씨 계수를 한 곳에서 결합시간 입력과날씨 입력이DayNightCycle최종계산으로각각전달되고같은광원에한번적용한다. 날씨관리자가광원을직접덮어쓰는선은없다. 본문선택식의Base8/계수0.7/최종5.6을읽는다. 두입력은서로실행하는순서가아니다.현재 시간 기본값Base = 8날씨 계수RainIntensity = 0.5Factor = 0.7DayNightCycleBase × Factor광원 최종 적용5.6 · 한 곳에서
시간 기본값과 날씨 계수를 한 곳에서 결합시간 입력과날씨 입력이DayNightCycle최종계산으로각각전달되고같은광원에한번적용한다. 날씨관리자가광원을직접덮어쓰는선은없다. 본문선택식의Base8/계수0.7/최종5.6을읽는다. 두입력은서로실행하는순서가아니다.현재 시간 기본값Base = 8날씨 계수RainIntensity = 0.5Factor = 0.7DayNightCycleBase × Factor광원 최종 적용5.6 · 한 곳에서

입력 A · DayNightCycle의 시간

DeltaSeconds × DayCycleSpeed를 3600으로 나눠 시간 단위로 더합니다. FMod(..., 24)는 넘친 나머지를 유지합니다.

단순 수치 예
23.9시간 + 0.2시간 = 24.1시간
24시간으로 순환한 결과
0.1시간 · 무조건 0으로 초기화하지 않습니다.

TimeOfDay로 태양 회전과 시간별 기본 조명 강도를 구합니다.

입력 B · WeatherManager의 상태

Rain/Clear와 Clamp한 RainIntensity를 저장합니다. 날씨 계수를 DayNightCycle에 전달합니다.

Rain
준비한 Niagara·오디오를 활성화하고 User.RainIntensity를 실제 스폰율에 연결합니다.
Clear
비 효과·소리를 멈추고 날씨 계수를 복원합니다.

두 액터의 Tick이 같은 Light 강도를 각각 덮어쓰지 않게 합니다.

최종 적용 · DayNightCycle 한 곳

결합 예시: 시간별 기본 강도 × 날씨 계수 → Directional Light Component의 최종 강도

태양 회전과 주변광도 이 제어 경로에서 갱신합니다. 이 예제는 Sky Light의 Real Time Capture를 켜며, Tick마다 Recapture Sky를 반복 호출하지 않습니다.

기준 상태와 각 클라이언트의 표현을 나눕니다

멀티플레이에서는 서버가 기준 시간·날씨·강도를 결정해 복제합니다. 각 클라이언트는 그 상태에서 조명과 Niagara 표현을 갱신합니다. 액터 Replicates만 켜서 모든 환경 속성이 자동 동기화되지는 않습니다.

90 − TimeOfDay × 15 회전은 본문의 단순 모델입니다. 실제 위도·계절의 태양 위치 계산을 뜻하지 않습니다.

위 그림은 시간과 날씨라는 두 입력을 BP_DayNightCycle의 최종 계산에서 합쳐, 같은 광원에 한 번만 적용하는 구조를 보여 줍니다. 입력 A는 BP_DayNightCycle의 시간으로, DeltaSeconds × DayCycleSpeed를 3600으로 나눠 시간 단위로 더하고 FMod(..., 24)로 넘친 나머지를 유지합니다. 그림의 단순 수치 예에서는 23.9시간에 0.2시간을 더한 24.1시간이 0.1시간으로 순환하며, 이 TimeOfDay로 태양의 회전과 시간별 기본 조명 강도를 구합니다. 입력 B는 BP_WeatherManager의 상태로, Rain이나 Clear와 범위를 제한한 RainIntensity를 저장하고 날씨 계수를 넘깁니다. Rain이면 준비한 Niagara와 오디오를 켜고 User.RainIntensity를 실제 스폰율에 연결하며, Clear면 비 효과와 소리를 멈추고 계수를 되돌립니다.

그림 가운데의 결합 예는 시간 기본값 8, RainIntensity 0.5에서 계수 0.7을 얻어 최종 강도 5.6을 한 곳에서 적용합니다. 날씨 관리자가 광원을 직접 덮어쓰는 선은 없으며, 두 입력은 서로를 실행하는 순서가 아니라 각자 값을 넘기는 관계입니다. 태양 회전과 주변광도 이 경로에서 갱신하고, Sky Light는 Real Time Capture를 켜 두었으므로 Tick마다 Recapture Sky를 호출하지 않습니다. 그림 아래에는 멀티플레이어에서 서버가 기준 시간, 날씨, 강도를 정해 복제하고 각 클라이언트가 그 상태에서 조명과 Niagara 표현을 갱신한다는 점, 그리고 90 − TimeOfDay × 15가 본문의 단순 모델이라는 점이 적혀 있습니다.

레벨에 배치하고 에셋 연결하기

BP_WeatherManager를 레벨에 배치하고, 디테일 패널에서 RainParticleSystem과 RainSound 변수에 알맞은 에셋을 연결합니다. 템플릿에 쓸 만한 에셋이 없다면 직접 준비하고, 사용자 파라미터와 반복 재생 설정이 되어 있는지 확인합니다.


더 다듬을 때 따질 것

성능부터 봅니다. 파티클, 볼류메트릭 클라우드, 스카이 애트모스피어는 성능에 큰 영향을 줄 수 있으므로 저사양 환경을 고려해 최적화해야 합니다. 날씨 변화를 부드럽게 하려면 FInterp To, Lerp, Timeline으로 값을 시간에 따라 서서히 바꿉니다.

멀티플레이어에서는 서버가 기준 시간, 날씨, 강도를 정하고, 게임 스테이트나 복제되는 관리 액터의 상태로 클라이언트에 전달합니다. 각 클라이언트는 그 값을 받아 자기 화면의 조명과 나이아가라 표현을 갱신합니다. 액터의 Replicates만 켠다고 파티클과 모든 환경 속성이 저절로 동기화되지는 않습니다.

날씨를 게임플레이와 연결할 수도 있습니다. 비가 오면 캐릭터의 이동 속도나 차량의 마찰을 줄이고, 안개나 밤에는 플레이어의 시야나 AI의 감지 거리를 줄이고, 비가 오면 물웅덩이가 생기거나 젖은 표면의 셰이더가 켜지게 할 수 있습니다. 날씨가 많아져 조명 강도, 파티클 스폰율, 소리 크기 같은 값이 늘어나면, 날씨별 값을 데이터 테이블로 관리하면 조정하기 쉬워집니다. 어느 경우든 시각 변화와 게임플레이 반응이 같은 기준 변수, 곧 TimeOfDay와 CurrentWeather, RainIntensity를 읽게 하면 관리가 쉬워집니다.


정리

  • 낮과 밤은 Directional Light의 회전을 시간에 따라 바꾸고, Sky Light, Sky Atmosphere, Volumetric Cloud가 그 변화를 하늘과 주변광에 반영해 만듭니다.
  • TimeOfDay는 FMod(TimeOfDay + DeltaSeconds * DayCycleSpeed / 3600.0, 24.0)으로 갱신해 초를 시간으로 바꾸고, 24시간을 넘은 나머지를 유지합니다.
  • Sky Light의 Real Time Capture를 켰다면 Tick마다 Recapture Sky를 호출하지 않습니다.
  • 비는 나이아가라 효과와 오디오로 만들고, 비의 양은 에셋의 사용자 파라미터를 스폰율에 연결해야 바뀝니다.
  • 날씨는 조명에 곱할 계수만 넘기고, 시간 기본값과 계수를 곱한 최종 조명은 BP_DayNightCycle 한 곳에서 적용합니다.
  • 멀티플레이어에서는 서버가 정한 시간과 날씨를 복제하고, 각 클라이언트가 표현을 갱신합니다.

연습 문제

1. 하루를 넘기는 갱신과 비 오는 날의 조명

TimeOfDay가 23.75, DeltaSeconds가 30, DayCycleSpeed가 120인 한 번의 갱신에서 새 시간과 단순 태양식의 Pitch를 계산해 보세요. 그 시점의 기본 강도가 8이고 RainIntensity가 0.5라면, 본문의 날씨 계수와 최종 강도는 얼마일까요? Clear로 바뀐 뒤에는 무엇을 되돌려야 할까요?

해설 보기

더해지는 시간은 30 × 120 ÷ 3600 = 1시간이므로 23.75 + 1 = 24.75이고, 24로 나눈 나머지인 0.75가 새 시간입니다. Pitch는 90 - 0.75 × 15 = 78.75도입니다.

날씨 계수는 Lerp(1.0, 0.4, 0.5) = 1 + (0.4 - 1) × 0.5 = 0.7이고, 최종 강도는 8 × 0.7 = 5.6입니다. Clear로 바뀌면 계수를 1로 되돌리므로, 같은 기본 강도라면 8을 적용합니다. 시간은 계속 흐르므로 예전에 저장해 둔 최종 강도를 되돌리는 것이 아니라, 지금 시간의 기본값과 지금의 계수를 한 적용 지점에서 다시 곱해야 합니다.

2. 깜빡이는 햇빛

BP_WeatherManager의 Tick에서 비가 오는 동안 Directional Light의 강도를 4로 설정하게 만들었습니다. BP_DayNightCycle의 Tick도 매 프레임 시간 기본값 10을 같은 광원에 설정합니다. 플레이해 보니 햇빛이 깜빡이거나, 비가 오는데도 밝게 보입니다. 왜 그럴까요?

해설 보기

두 액터가 매 프레임 같은 광원의 강도를 각자 설정하므로, 그 프레임에 어느 Tick이 나중에 실행되었는지에 따라 마지막 값이 4가 되기도 하고 10이 되기도 합니다. 두 액터의 Tick 순서는 정해져 있다고 기대할 수 없으므로 결과가 들쭉날쭉합니다.

본문처럼 날씨 관리자는 광원에 직접 쓰지 않고 SetWeatherLightFactor로 계수 0.4만 넘기고, BP_DayNightCycle이 BaseSunIntensity × WeatherLightFactor로 최종값 4를 계산해 한 번만 적용하게 바꿉니다. 그러면 광원에 값을 쓰는 곳이 하나뿐이라 순서 문제가 생기지 않습니다.

3. 24초 만에 끝나는 하루

어떤 개발자가 TimeOfDay를 FMod(TimeOfDay + DeltaSeconds * DayCycleSpeed, 24.0)으로 갱신했습니다. DayCycleSpeed가 1인데도 해가 아주 빠르게 돕니다. 하루가 실제로 몇 초 만에 지나갈까요? 어디를 고쳐야 할까요?

해설 보기

DeltaSeconds는 초 단위인데 TimeOfDay는 시간 단위입니다. 3600으로 나누지 않으면 실제 1초가 지날 때마다 TimeOfDay가 1시간씩 늘어나므로, 24시간이 실제 24초 만에 지나갑니다.

식에 / 3600.0을 넣어 FMod(TimeOfDay + DeltaSeconds * DayCycleSpeed / 3600.0, 24.0)으로 고칩니다. 그러면 DayCycleSpeed가 1일 때 게임의 하루가 실제 시간과 같은 24시간이 되고, 하루를 24분으로 만들고 싶다면 DayCycleSpeed를 60으로 두면 됩니다.

Directional Light의 Atmosphere Sun Light 설정과 대기 표현은 언리얼 엔진 공식 문서의 Sky Atmosphere 컴포넌트에서 확인할 수 있습니다.

다음 글 동적 환경 상호작용의 기본 구현에서는 플레이어의 행동에 따라 문이 열리고 물체가 부서지는 것처럼 월드가 반응하는 상호작용을 만듭니다.