153 lines
5.1 KiB
C++
153 lines
5.1 KiB
C++
// Copyright Pacificao. All Rights Reserved.
|
|
|
|
#include "AgrarianSkyLightingController.h"
|
|
|
|
#include "AgrarianGameState.h"
|
|
#include "AgrarianPerformanceStats.h"
|
|
#include "Components/DirectionalLightComponent.h"
|
|
#include "Components/ExponentialHeightFogComponent.h"
|
|
#include "Components/SceneComponent.h"
|
|
#include "Components/SkyLightComponent.h"
|
|
#include "Engine/World.h"
|
|
#include "ProfilingDebugging/CpuProfilerTrace.h"
|
|
|
|
AAgrarianSkyLightingController::AAgrarianSkyLightingController()
|
|
{
|
|
PrimaryActorTick.bCanEverTick = true;
|
|
bReplicates = false;
|
|
|
|
SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
|
|
RootComponent = SceneRoot;
|
|
|
|
SunLight = CreateDefaultSubobject<UDirectionalLightComponent>(TEXT("SunLight"));
|
|
SunLight->SetupAttachment(SceneRoot);
|
|
SunLight->SetIntensity(NoonSunIntensity);
|
|
SunLight->SetLightColor(FLinearColor(1.0f, 0.96f, 0.86f));
|
|
SunLight->SetMobility(EComponentMobility::Movable);
|
|
|
|
SkyLight = CreateDefaultSubobject<USkyLightComponent>(TEXT("SkyLight"));
|
|
SkyLight->SetupAttachment(SceneRoot);
|
|
SkyLight->SetIntensity(ClearSkyLightIntensity);
|
|
SkyLight->SetMobility(EComponentMobility::Movable);
|
|
|
|
HeightFog = CreateDefaultSubobject<UExponentialHeightFogComponent>(TEXT("HeightFog"));
|
|
HeightFog->SetupAttachment(SceneRoot);
|
|
HeightFog->SetFogDensity(ClearFogDensity);
|
|
HeightFog->SetMobility(EComponentMobility::Movable);
|
|
}
|
|
|
|
void AAgrarianSkyLightingController::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
RefreshSkyLighting();
|
|
}
|
|
|
|
void AAgrarianSkyLightingController::Tick(float DeltaSeconds)
|
|
{
|
|
Super::Tick(DeltaSeconds);
|
|
RefreshSkyLighting();
|
|
}
|
|
|
|
void AAgrarianSkyLightingController::RefreshSkyLighting()
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_AgrarianSkyLightingRefresh);
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianSkyLightingRefresh);
|
|
|
|
const UWorld* World = GetWorld();
|
|
const AAgrarianGameState* GameState = World ? World->GetGameState<AAgrarianGameState>() : nullptr;
|
|
if (!GameState)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const float SunriseHour = GameState->bHasActiveTileSolarData ? GameState->SunriseHourLocal : 6.0f;
|
|
const float SunsetHour = GameState->bHasActiveTileSolarData ? GameState->SunsetHourLocal : 20.0f;
|
|
CurrentSunAlpha = CalculateSunAlpha(GameState->WorldHours, SunriseHour, SunsetHour);
|
|
CurrentWeather = GameState->Weather;
|
|
CurrentCloudAlpha = CalculateWeatherCloudAlpha(
|
|
GameState->Weather,
|
|
GameState->ActiveWeatherInputs.CloudCoverPercent,
|
|
GameState->ActiveWeatherInputs.bHasProviderData);
|
|
|
|
const float WeatherLightMultiplier = FMath::Lerp(1.0f, 0.35f, CurrentCloudAlpha);
|
|
const float SunIntensity = FMath::Lerp(NightSunIntensity, NoonSunIntensity, CurrentSunAlpha) * WeatherLightMultiplier;
|
|
const float SkyIntensity = FMath::Lerp(NightSkyLightIntensity, ClearSkyLightIntensity, CurrentSunAlpha) * FMath::Lerp(1.0f, 0.55f, CurrentCloudAlpha);
|
|
const float FogDensity = FMath::Lerp(ClearFogDensity, StormFogDensity, CurrentCloudAlpha);
|
|
const float SunPitch = FMath::Lerp(-8.0f, -72.0f, CurrentSunAlpha);
|
|
|
|
if (SunLight)
|
|
{
|
|
SunLight->SetWorldRotation(FRotator(SunPitch, NorthYawDegrees, 0.0f));
|
|
SunLight->SetIntensity(SunIntensity);
|
|
SunLight->SetLightColor(CalculateSunColor(CurrentSunAlpha, CurrentCloudAlpha));
|
|
}
|
|
|
|
if (SkyLight)
|
|
{
|
|
SkyLight->SetIntensity(SkyIntensity);
|
|
}
|
|
|
|
if (HeightFog)
|
|
{
|
|
HeightFog->SetFogDensity(FogDensity);
|
|
}
|
|
}
|
|
|
|
float AAgrarianSkyLightingController::CalculateSunAlpha(float HourOfDay, float SunriseHour, float SunsetHour) const
|
|
{
|
|
const float NormalizedHour = FMath::Fmod(HourOfDay + 24.0f, 24.0f);
|
|
const float SafeSunrise = FMath::Fmod(SunriseHour + 24.0f, 24.0f);
|
|
const float SafeSunset = FMath::Fmod(SunsetHour + 24.0f, 24.0f);
|
|
const float DayLength = FMath::Max(0.1f, SafeSunset >= SafeSunrise ? SafeSunset - SafeSunrise : (24.0f - SafeSunrise) + SafeSunset);
|
|
|
|
float HoursSinceSunrise = NormalizedHour - SafeSunrise;
|
|
if (HoursSinceSunrise < 0.0f)
|
|
{
|
|
HoursSinceSunrise += 24.0f;
|
|
}
|
|
|
|
if (HoursSinceSunrise > DayLength)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
const float DayProgress = FMath::Clamp(HoursSinceSunrise / DayLength, 0.0f, 1.0f);
|
|
return FMath::Clamp(FMath::Sin(PI * DayProgress), 0.0f, 1.0f);
|
|
}
|
|
|
|
float AAgrarianSkyLightingController::CalculateWeatherCloudAlpha(EAgrarianWeatherType Weather, float ProviderCloudCoverPercent, bool bHasProviderCloudCover) const
|
|
{
|
|
float WeatherAlpha = 0.0f;
|
|
switch (Weather)
|
|
{
|
|
case EAgrarianWeatherType::Rain:
|
|
WeatherAlpha = 0.65f;
|
|
break;
|
|
case EAgrarianWeatherType::ColdWind:
|
|
WeatherAlpha = 0.45f;
|
|
break;
|
|
case EAgrarianWeatherType::Storm:
|
|
WeatherAlpha = 1.0f;
|
|
break;
|
|
default:
|
|
WeatherAlpha = 0.0f;
|
|
break;
|
|
}
|
|
|
|
if (bHasProviderCloudCover)
|
|
{
|
|
WeatherAlpha = FMath::Max(WeatherAlpha, FMath::Clamp(ProviderCloudCoverPercent / 100.0f, 0.0f, 1.0f));
|
|
}
|
|
|
|
return WeatherAlpha;
|
|
}
|
|
|
|
FLinearColor AAgrarianSkyLightingController::CalculateSunColor(float SunAlpha, float CloudAlpha) const
|
|
{
|
|
const FLinearColor DawnColor(1.0f, 0.62f, 0.38f);
|
|
const FLinearColor NoonColor(1.0f, 0.96f, 0.86f);
|
|
const FLinearColor StormColor(0.52f, 0.58f, 0.66f);
|
|
const FLinearColor TimeColor = FLinearColor::LerpUsingHSV(DawnColor, NoonColor, FMath::Clamp(SunAlpha, 0.0f, 1.0f));
|
|
return FLinearColor::LerpUsingHSV(TimeColor, StormColor, FMath::Clamp(CloudAlpha, 0.0f, 1.0f));
|
|
}
|