bmh/FlightSimulation/Plugins/CesiumForUnreal_5.4/Source/CesiumRuntime/Public/CesiumSunSky.h
2025-02-07 22:52:32 +08:00

547 lines
18 KiB
C++

// Copyright 2020-2024 CesiumGS, Inc. and Contributors
#pragma once
#include "CoreMinimal.h"
#include "CesiumGeoreference.h"
#include "Components/DirectionalLightComponent.h"
#include "Components/SkyAtmosphereComponent.h"
#include "Components/SkyLightComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/DirectionalLight.h"
#include "GameFramework/Actor.h"
#include "CesiumSunSky.generated.h"
class UCesiumGlobeAnchorComponent;
/**
* A globe-aware sun sky actor. If the georeference is set to CartographicOrigin
* (aka Longitude/Latitude/Height) mode, then this actor will automatically
* sync its longitude and latitude properties with the georeference's, and
* recalculate the sun position whenever those properties change.
*
* Note: because we use `Planet Center at Component Transform`
* for the SkyAtmosphere transform mode, this actor's location will be forced
* to the Earth's center if the georeference is set to CartographicOrigin.
*/
UCLASS()
class CESIUMRUNTIME_API ACesiumSunSky : public AActor {
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACesiumSunSky();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Components)
USceneComponent* Scene;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Components)
USkyLightComponent* SkyLight;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Components)
UDirectionalLightComponent* DirectionalLight;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Components)
USkyAtmosphereComponent* SkyAtmosphere;
/**
* The Globe Anchor Component that precisely ties this Actor to the Globe.
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Components)
UCesiumGlobeAnchorComponent* GlobeAnchor;
/**
* Gets the time zone, represented as hours offset from GMT.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time",
meta = (ClampMin = -12, ClampMax = 14))
double TimeZone = -5.0;
/**
* The current solar time represented as hours from midnight.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time",
meta = (UIMin = 4, UIMax = 22, ClampMin = 0, ClampMax = 23.9999))
double SolarTime = 13.0;
/**
* The day of the month.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time",
meta = (ClampMin = 1, ClampMax = 31))
int32 Day = 21;
/**
* The month of the year, where 1 is January and 12 is December.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time",
meta = (ClampMin = 1, ClampMax = 12))
int32 Month = 9;
/**
* The year.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time",
meta = (UIMin = 1800, UIMax = 2200, ClampMin = 0, ClampMax = 4000))
int32 Year = 2019;
/**
* Offset in the sun's position. Should be set to -90 for the sun's position
* to be accurate in the Unreal reference frame.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
BlueprintReadWrite,
Category = "Cesium|Date and Time",
meta = (ClampMin = -360, ClampMax = 360))
double NorthOffset = -90.0;
/**
* Enables adjustment of the Solar Time for Daylight Saving Time (DST).
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time|Daylight Savings")
bool UseDaylightSavingTime = true;
protected:
/**
* THIS PROPERTY IS DEPRECATED.
*
* Get the Georeference instance from the Globe Anchor Component instead.
*/
UPROPERTY(
BlueprintReadOnly,
Category = "Cesium",
BlueprintGetter = GetGeoreference,
Meta =
(DeprecatedProperty,
DeprecationMessage =
"Get the Georeference instance from the Globe Anchor Component instead."))
ACesiumGeoreference* Georeference_DEPRECATED;
/**
* Gets the Georeference Actor associated with this instance. It is obtained
* from the Globe Anchor Component.
*/
UFUNCTION(BlueprintGetter, Category = "Cesium")
ACesiumGeoreference* GetGeoreference() const;
/**
* Set the Date at which DST starts in the current year.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time|Daylight Savings",
meta = (ClampMin = 1, ClampMax = 12),
meta = (EditCondition = "UseDaylightSavingTime"))
int32 DSTStartMonth = 3;
/**
* Set the Date at which DST starts in the current year.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time|Daylight Savings",
meta = (ClampMin = 1, ClampMax = 31),
meta = (EditCondition = "UseDaylightSavingTime"))
int32 DSTStartDay = 10;
/**
* Set the Date at which DST ends in the current year.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time|Daylight Savings",
meta = (ClampMin = 1, ClampMax = 12),
meta = (EditCondition = "UseDaylightSavingTime"))
int32 DSTEndMonth = 11;
/**
* Set the Date at which DST ends in the current year.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time|Daylight Savings",
meta = (ClampMin = 1, ClampMax = 31),
meta = (EditCondition = "UseDaylightSavingTime"))
int32 DSTEndDay = 3;
/**
* Hour of the DST Switch for both beginning and end.
*
* After changing this value from Blueprints or C++, you must call UpdateSun
* for it to take effect.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
Category = "Cesium|Date and Time|Daylight Savings",
meta = (ClampMin = 0, ClampMax = 23),
meta = (EditCondition = "UseDaylightSavingTime"))
int32 DSTSwitchHour = 2;
/**
* Updates the atmosphere automatically given current player pawn's longitude,
* latitude, and height. Fixes artifacts seen with the atmosphere rendering
* when flying high above the surface, or low to the ground in high latitudes.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cesium|Atmosphere")
bool UpdateAtmosphereAtRuntime = true;
/**
* When the player pawn is below this height, which is expressed in kilometers
* above the ellipsoid, this Actor will use an atmosphere ground radius that
* is calculated to be at or below the terrain surface at the player pawn's
* current location. This avoids a gap between the bottom of the atmosphere
* and the top of the terrain when zoomed in close to the terrain surface.
*
* Above CircumscribedGroundThreshold, this Actor will use an atmosphere
* ground radius that is guaranteed to be above the terrain surface anywhere
* on Earth. This avoids artifacts caused by terrain poking through the
* atmosphere when viewing the Earth from far away.
*
* At player pawn heights in between InscribedGroundThreshold and
* CircumscribedGroundThreshold, this Actor uses a linear interpolation
* between the two ground radii.
*
* This value is automatically scaled according to the CesiumGeoreference
* Scale and the Actor scale.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
meta = (EditCondition = "UpdateAtmosphereAtRuntime"),
Category = "Cesium|Atmosphere")
double InscribedGroundThreshold = 30.0;
/**
* When the player pawn is above this height, which is expressed in kilometers
* above the ellipsoid, this Actor will use an atmosphere ground radius that
* is guaranteed to be above the terrain surface anywhere on Earth. This
* avoids artifacts caused by terrain poking through the atmosphere when
* viewing the Earth from far away.
*
* Below InscribedGroundThreshold, this Actor will use an atmosphere
* ground radius that is calculated to be at or below the terrain surface at
* the player pawn's current location. This avoids a gap between the bottom of
* the atmosphere and the top of the terrain when zoomed in close to the
* terrain surface.
*
* At heights in between InscribedGroundThreshold and
* CircumscribedGroundThreshold, this Actor uses a linear interpolation
* between the two ground radii.
*
* This value is automatically scaled according to the CesiumGeoreference
* Scale and the Actor scale.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
meta = (EditCondition = "UpdateAtmosphereAtRuntime"),
Category = "Cesium|Atmosphere")
double CircumscribedGroundThreshold = 100.0;
/**
* The height at which to place the bottom of the atmosphere when the player
* pawn is above the CircumscribedGroundThreshold. This is expressed as a
* height in kilometers above the maximum radius of the ellipsoid (usually
* WGS84). To avoid dark splotchy artifacts in the atmosphere when zoomed out
* far from the globe, this value must be above the greatest height achieved
* by any part of the tileset.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadWrite,
meta = (EditCondition = "UpdateAtmosphereAtRuntime"),
Category = "Cesium|Atmosphere")
double CircumscribedGroundHeight = 0.0;
/**
* The height of the atmosphere layer above the ground, in kilometers. This
* value is automatically scaled according to the CesiumGeoreference Scale and
* the Actor scale. However, Unreal Engine's SkyAtmosphere has a hard-coded
* minimum effective value of 0.1, so the atmosphere will look too thick when
* the globe is scaled down drastically.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadOnly,
interp,
Category = "Cesium|Atmosphere",
meta = (UIMin = 1.0, UIMax = 200.0, ClampMin = 0.1, SliderExponent = 2.0))
float AtmosphereHeight = 60.0f;
/**
* Makes the aerial perspective look thicker by scaling distances from view
* to surfaces (opaque and translucent). This value is automatically scaled
* according to the CesiumGeoreference Scale and the Actor scale.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadOnly,
interp,
Category = "Cesium|Atmosphere",
meta =
(DisplayName = "Aerial Perspective View Distance Scale",
UIMin = 0.0,
UIMax = 3.0,
ClampMin = 0.0,
SliderExponent = 2.0))
float AerialPerspectiveViewDistanceScale = 1.0f;
/**
* The altitude in kilometers at which Rayleigh scattering effect is reduced
* to 40%. This value is automatically scaled according to the
* CesiumGeoreference Scale and the Actor scale.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadOnly,
interp,
Category = "Cesium|Atmosphere",
meta =
(UIMin = 0.01, UIMax = 20.0, ClampMin = 0.001, SliderExponent = 5.0))
float RayleighExponentialDistribution = 8.0f;
/**
* The altitude in kilometers at which Mie effects are reduced to 40%. This
* value is automatically scaled according to the CesiumGeoreference Scale and
* the Actor scale.
*/
UPROPERTY(
EditAnywhere,
BlueprintReadOnly,
interp,
Category = "Cesium|Atmosphere",
meta =
(UIMin = 0.01, UIMax = 10.0, ClampMin = 0.001, SliderExponent = 5.0))
float MieExponentialDistribution = 1.2f;
/**
* False: Use Directional Light component inside CesiumSunSky.
* True: Use the assigned Directional Light in the level.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cesium|Sun")
bool UseLevelDirectionalLight = false;
/**
* Reference to a manually assigned Directional Light in the level.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cesium|Sun")
ADirectionalLight* LevelDirectionalLight;
/**
* The current sun elevation in degrees above the horizontal, as viewed from
* the Georeference origin.
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Sun")
double Elevation = 0.f;
/**
* The current sun elevation, corrected for atmospheric diffraction, in
* degrees above the horizontal, as viewed from the Georeference origin.
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Sun")
double CorrectedElevation = 0.f;
/**
* The current sun azimuth in degrees clockwise from North toward East, as
* viewed from the Georeference origin.
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Sun")
double Azimuth = 0.f;
/**
* A switch to toggle between desktop and mobile rendering code paths.
* This will NOT be automatically set when running on mobile, so make sure
* to check this setting before building on mobile platforms.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Cesium|Mobile")
bool UseMobileRendering;
/**
* Mobile platforms currently do not support the SkyAtmosphereComponent.
* In lieu of that, use the engine BP_Sky_Sphere class, or a derived class.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cesium|Mobile")
TSubclassOf<AActor> SkySphereClass;
/**
* Reference to BP_Sky_Sphere or similar actor (mobile only)
*/
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Cesium|Mobile")
AActor* SkySphereActor;
/**
* Default intensity of directional light that's spawned for mobile rendering.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Cesium|Mobile")
double MobileDirectionalLightIntensity = 6.f;
public:
UFUNCTION(
CallInEditor,
BlueprintCallable,
BlueprintNativeEvent,
Category = "Cesium")
void UpdateSun();
void UpdateSun_Implementation();
UFUNCTION(CallInEditor, BlueprintCallable, Category = "Cesium")
void UpdateAtmosphereRadius();
/**
* Adjusts the time zone of this CesiumSunSky to an estimate based on the
* given longitude.
*
* The time zone is naively calculated from the longitude, where every
* 15 degrees equals 1 hour. This may not necessarily match the official
* time zone at a given location within that longitude.
*
* This method will call @ref UpdateSun automatically.
*
* @param InLongitude The longitude that the calculated time zone will be
* based on in degrees in the range [-180, 180].
*/
UFUNCTION(CallInEditor, BlueprintCallable, Category = "Cesium")
void EstimateTimeZoneForLongitude(double InLongitude);
/**
* Convert solar time to Hours:Minutes:Seconds. Copied the implementation
* from the engine SunSkyBP class.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Sun)
static void GetHMSFromSolarTime(
double InSolarTime,
int32& Hour,
int32& Minute,
int32& Second);
/**
* Check whether the current time and date (based on this class instance's
* properties) falls within Daylight Savings Time. Copied the implementation
* from the engine SunSkyBP class.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Sun)
bool IsDST(
bool DSTEnable,
int32 InDSTStartMonth,
int32 InDSTStartDay,
int32 InDSTEndMonth,
int32 InDSTEndDay,
int32 InDSTSwitchHour) const;
// Begin AActor Interface
/**
* Gets called when the actor is first created, and when properties are
* changed at edit-time. Refreshes the actor's position w/r/t the georeference
* and handles mobile-specific setup if needed.
*/
virtual void OnConstruction(const FTransform& Transform) override;
// End AActor Interface
protected:
/**
* Modifies the sky atmosphere's ground radius, which represents the Earth's
* radius in the SkyAtmosphere rendering model. Only changes if there's a >0.1
* difference, to reduce redraws.
*
* @param Sky A pointer to the SkyAtmosphereComponent
* @param Radius The radius in kilometers.
*/
UFUNCTION(BlueprintCallable, Category = "Cesium")
void
SetSkyAtmosphereGroundRadius(USkyAtmosphereComponent* Sky, double Radius);
/**
* Update MobileSkySphere by calling its RefreshMaterial function
*/
UFUNCTION(BlueprintCallable, Category = "Mobile")
void UpdateSkySphere();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Serialize(FArchive& Ar) override;
virtual void Tick(float DeltaSeconds) override;
virtual void PostLoad() override;
virtual bool ShouldTickIfViewportsOnly() const override;
#if WITH_EDITOR
virtual void
PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
private:
void _spawnSkySphere();
double _computeScale() const;
// Sets Directional Light Component in Sky Sphere actor
void _setSkySphereDirectionalLight();
void _setSkyAtmosphereVisibility(bool bVisible);
// Determines whether mobile sky sphere will be spawned during OnConstruction.
bool _wantsSpawnMobileSkySphere;
void _handleTransformUpdated(
USceneComponent* InRootComponent,
EUpdateTransformFlags UpdateTransformFlags,
ETeleportType Teleport);
FDelegateHandle _transformUpdatedSubscription;
};