载入中...
搜索中...
未找到
SkyRuntime.cpp
浏览该文件的文档.
2#include <algorithm>
3#include <cmath>
4#include <utility>
6#include "graphics/Graphics.h"
9
10namespace eve::daynight {
11namespace {
12using Light = graphics::SkyCelestialLight;
13Result<Light> solarLight(const SkySolarOrbit& orbit, double hour, const std::array<float, 3>& base) {
14 auto direction = orbit.direction(hour);
15 if (!direction) return Result<Light>::failure(direction.status());
16 // UDS Current Sun Light Intensity / Using Sky Atmosphere branch:
17 // cached light-forward Z [0.157,0.113] -> [0,base]. Our Y points towards the sun.
18 const double fraction = std::clamp((direction.value()[1] + .157) / (.157 - .113), 0.0, 1.0);
20 for (int axis = 0; axis < 3; ++axis) {
21 light.direction[axis] = static_cast<float>(direction.value()[axis]);
22 light.irradiance[axis] = static_cast<float>(base[axis] * fraction);
23 }
25}
26float dayPhase(double hour) { return std::min(static_cast<float>(hour / 24.0), std::nextafter(1.f, 0.f)); }
28 return Diagnostic::error(DiagnosticCode::StaleHandle, "Sky graphics provider retired", "sky.runtime");
29}
30} // namespace
32 const auto multiplier = [](double value) { return std::isfinite(value) && value >= 0 && value <= 1000; };
33 if (!std::isfinite(phase) || std::abs(phase) > 1e6 || !multiplier(speed) || !multiplier(timeScale) ||
34 !multiplier(windMultiplier))
36 Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid cloud motion controls", "sky.motion"));
37 return Result<void>::success();
38}
42 std::array<float, 3> base;
43 Light light;
45 double sourceTime = 0, morphRate = 0, morphPeriod = 1, cloudTime = 0;
46 float wispsMorphPhase = 0;
48 const double time =
50 if (!std::isfinite(time))
51 return Result<std::pair<double, float>>::failure(
52 Diagnostic::error(DiagnosticCode::InvalidArgument, "Cloud time overflow", "sky.motion"));
53 double phase = std::fmod(time * morphRate / morphPeriod, 1.0);
54 if (phase < 0) phase += 1;
55 float gpuPhase = static_cast<float>(phase);
56 if (gpuPhase >= 1) gpuPhase = 0;
57 return Result<std::pair<double, float>>::success({time, gpuPhase});
58 }
59 std::weak_ptr<const void> lifetime;
60 std::unique_ptr<graphics::SkyAtmospherePass> atmosphere;
61 Impl(SkyTimeline time, SkySolarOrbit solar, std::array<float, 3> irradiance)
62 : timeline(std::move(time)), orbit(std::move(solar)), base(irradiance) {}
63};
64SkyRuntime::SkyRuntime() = default;
65SkyRuntime::~SkyRuntime() = default;
66
69 const graphics::SkyAtmosphereParameters& atmosphere,
70 const graphics::SkyWispsLayer* wisps) {
71 using Prepared = Result<std::unique_ptr<SkyRuntime>>;
72 auto motionValid = settings.cloudMotion.validate();
73 if (!motionValid) return Prepared::failure(motionValid.status());
74 auto timeline = SkyTimeline::create(settings.clock, settings.weather);
75 if (!timeline) return Prepared::failure(timeline.status());
76 auto orbit = SkySolarOrbit::create(settings.sunPitchDegrees, settings.sunYawDegrees);
77 if (!orbit) return Prepared::failure(orbit.status());
78 for (const float value : settings.sunIrradiance)
79 if (!std::isfinite(value) || value < 0)
80 return Prepared::failure(Diagnostic::error(
81 DiagnosticCode::InvalidArgument, "Solar irradiance must be finite and nonnegative", "sky.runtime"));
82 auto light = solarLight(orbit.value(), timeline.value().frame().hour, settings.sunIrradiance);
83 if (!light) return Prepared::failure(light.status());
84 auto pass = graphics::SkyAtmospherePass::prepare(graphics, atmosphere, wisps);
85 if (!pass) return Prepared::failure(pass.status());
86 auto result = std::unique_ptr<SkyRuntime>(new SkyRuntime());
87 result->impl_ =
88 std::make_unique<Impl>(std::move(timeline).takeValue(), std::move(orbit).takeValue(), settings.sunIrradiance);
89 result->impl_->motion = settings.cloudMotion;
90 if (wisps) {
91 result->impl_->sourceTime = wisps->cloudTime;
92 result->impl_->morphRate = wisps->morphRate;
93 result->impl_->morphPeriod = wisps->morphPeriod;
94 }
95 auto cloud = result->impl_->cloudSample(0);
96 if (!cloud) return Prepared::failure(cloud.status());
97 auto applied =
98 pass.value()->setFrame({light.value(), cloud.value().second, dayPhase(result->impl_->timeline.frame().hour)});
99 if (!applied) return Prepared::failure(applied.status());
100 result->impl_->cloudTime = cloud.value().first;
101 result->impl_->wispsMorphPhase = cloud.value().second;
102 result->impl_->light = light.value();
103 result->impl_->lifetime = graphics.resourceLifetime();
104 result->impl_->atmosphere = std::move(pass).takeValue();
105 return Prepared::success(std::move(result));
106}
107
109 if (impl_->lifetime.expired()) return Result<void>::failure(retired());
110 auto candidate = impl_->timeline;
111 auto advanced = candidate.advance(duration);
112 if (!advanced) return advanced;
113 auto light = solarLight(impl_->orbit, candidate.frame().hour, impl_->base);
114 if (!light) return Result<void>::failure(light.status());
115 auto cloud = impl_->cloudSample(candidate.frame().elapsedSeconds);
116 if (!cloud) return Result<void>::failure(cloud.status());
117 auto applied = impl_->atmosphere->setFrame({light.value(), cloud.value().second, dayPhase(candidate.frame().hour)});
118 if (!applied) return applied;
119 impl_->timeline = std::move(candidate);
120 impl_->light = light.value();
121 impl_->cloudTime = cloud.value().first;
122 impl_->wispsMorphPhase = cloud.value().second;
123 return Result<void>::success();
124}
126 if (impl_->lifetime.expired()) return Result<void>::failure(retired());
127 return impl_->timeline.transitionTo(target, duration);
128}
130 SkyRuntimeFrame result;
131 result.simulation = impl_->timeline.frame();
132 result.cloudTime = impl_->cloudTime;
133 result.wispsMorphPhase = impl_->wispsMorphPhase;
134 for (int axis = 0; axis < 3; ++axis) {
135 result.sunDirection[axis] = impl_->light.direction[axis];
136 result.sunIrradiance[axis] = impl_->light.irradiance[axis];
137 }
138 return result;
139}
141 if (impl_->lifetime.expired()) return Result<void>::failure(retired());
142 return impl_->atmosphere->attach();
143}
144void SkyRuntime::detach() noexcept { impl_->atmosphere->detach(); }
145} // namespace eve::daynight
LogicalId target
double value
float duration
float phase
Definition CaveMesh.cpp:58
bool retired
RoadLaneDirection direction
Light3D::Data * light
TerrainThermalSettings settings
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Signed, fixed-resolution simulation duration in nanoseconds.
Definition Time.h:43
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Owns independent sky simulation and its prepared atmospheric contributor.
Definition SkyRuntime.h:46
static Result< std::unique_ptr< SkyRuntime > > prepare(graphics::Graphics &graphics, const SkyRuntimeSettings &settings, const graphics::SkyAtmosphereParameters &atmosphere, const graphics::SkyWispsLayer *wisps=nullptr)
Validate settings and prepare all atmospheric resources before publication.
Result< void > attach()
Attach the prepared main-view and reflection contributors, idempotently.
Result< void > advance(Duration duration)
Advance one simulation clock and atomically publish solar lighting/cloud phase; invalid time preserve...
Result< void > transitionTo(const SkyWeather &target, Duration duration)
Start a validated weather transition without advancing simulation time.
SkyRuntimeFrame frame() const noexcept
Copy current simulation and solar lighting without advancing either.
void detach() noexcept
Unregister both contributors; simulation and prepared resources remain owned.
Non-astronomical daily solar orbit, matching the reference's manual pitch/yaw mode.
static Result< SkySolarOrbit > create(double pitchDegrees, double yawDegrees)
Prepare a daily orbit with pitch [-90,90] and yaw [-360,360] degrees.
Owns one independent sky clock, weather transition and integrated cloud travel.
Definition SkyTimeline.h:42
static Result< SkyTimeline > create(const SkyClock &clock, const SkyWeather &weather)
Construct validated state. Clock hours are [0,24), speed [0,24] hours/second.
std::weak_ptr< const void > resourceLifetime() const
Observe this provider's resource lifetime without extending it.
static Result< std::unique_ptr< SkyAtmospherePass > > prepare(Graphics &graphics, const SkyAtmosphereParameters &parameters, const SkyWispsLayer *wisps=nullptr)
Prepare an independent atmospheric program and immutable coefficient buffer.
eve::Diagnostic Diagnostic
int axis(int64_t a, size_t rank)
Axis.
Source cloud-time controls; phase is additive, speed is source time per injected second.
Definition SkyRuntime.h:15
EVENGINE_API_WORLD Result< void > validate() const
Reject nonfinite values, phase outside +/-1e6 and multipliers outside [0,1000].
Copied simulation and evaluated solar lighting used by every view.
Definition SkyRuntime.h:30
std::array< double, 3 > sunDirection
Definition SkyRuntime.h:34
std::array< float, 3 > sunIrradiance
Definition SkyRuntime.h:35
Independent runtime settings; not a serialized profile or a legacy DayNight override.
Definition SkyRuntime.h:21
std::weak_ptr< const void > lifetime
std::unique_ptr< graphics::SkyAtmospherePass > atmosphere
Impl(SkyTimeline time, SkySolarOrbit solar, std::array< float, 3 > irradiance)
Result< std::pair< double, float > > cloudSample(double seconds) const
std::array< float, 3 > base
Independent sky weather values; distances are metres and wind is metres/second.
Definition SkyTimeline.h:10
Spherical atmospheric coefficients in inverse kilometres and kilometre heights.
Borrowed authored thin-cloud layer, consumed synchronously by sky preparation.