Add first pass sky lighting
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
// Copyright Pacificao. All Rights Reserved.
|
||||
|
||||
#include "AgrarianSkyLightingController.h"
|
||||
|
||||
#include "AgrarianGameState.h"
|
||||
#include "Components/DirectionalLightComponent.h"
|
||||
#include "Components/ExponentialHeightFogComponent.h"
|
||||
#include "Components/SceneComponent.h"
|
||||
#include "Components/SkyLightComponent.h"
|
||||
#include "Engine/World.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()
|
||||
{
|
||||
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));
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright Pacificao. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "AgrarianTypes.h"
|
||||
#include "AgrarianSkyLightingController.generated.h"
|
||||
|
||||
class UDirectionalLightComponent;
|
||||
class UExponentialHeightFogComponent;
|
||||
class USceneComponent;
|
||||
class USkyLightComponent;
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class AAgrarianSkyLightingController : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AAgrarianSkyLightingController();
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Sky")
|
||||
TObjectPtr<USceneComponent> SceneRoot;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Sky")
|
||||
TObjectPtr<UDirectionalLightComponent> SunLight;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Sky")
|
||||
TObjectPtr<USkyLightComponent> SkyLight;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Sky")
|
||||
TObjectPtr<UExponentialHeightFogComponent> HeightFog;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Sky")
|
||||
float NoonSunIntensity = 8.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Sky")
|
||||
float NightSunIntensity = 0.03f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Sky")
|
||||
float ClearSkyLightIntensity = 1.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Sky")
|
||||
float NightSkyLightIntensity = 0.08f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Sky")
|
||||
float ClearFogDensity = 0.008f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Sky")
|
||||
float StormFogDensity = 0.05f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Sky")
|
||||
float NorthYawDegrees = -35.0f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Sky")
|
||||
float CurrentSunAlpha = 0.0f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Sky")
|
||||
float CurrentCloudAlpha = 0.0f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Sky")
|
||||
EAgrarianWeatherType CurrentWeather = EAgrarianWeatherType::Clear;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Agrarian|Sky")
|
||||
void RefreshSkyLighting();
|
||||
|
||||
protected:
|
||||
float CalculateSunAlpha(float HourOfDay, float SunriseHour, float SunsetHour) const;
|
||||
float CalculateWeatherCloudAlpha(EAgrarianWeatherType Weather, float ProviderCloudCoverPercent, bool bHasProviderCloudCover) const;
|
||||
FLinearColor CalculateSunColor(float SunAlpha, float CloudAlpha) const;
|
||||
};
|
||||
Reference in New Issue
Block a user