1
0
Fork 0
fgdata/Nasal/hdr.nas
2024-01-08 18:26:24 +01:00

289 lines
11 KiB
Text

# Copyright (C) 2023 Fernando García Liñán
# SPDX-License-Identifier: GPL-2.0-or-later
#-------------------------------------------------------------------------------
# Utilities for the HDR Pipeline
#
# Shaders usually need to be fed uniforms that are either too expensive to
# compute on the GPU or can be precomputed once per frame. In this file we
# transform values from already existing properties into data that can be used
# by the shaders directly.
#-------------------------------------------------------------------------------
################################################################################
# Atmosphere
################################################################################
setlistener("/environment/aerosols/type", func(p) {
var type = p.getValue();
if (type == 7) { # Rural
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[0]", 5.0393e-23);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[1]", 8.0765e-23);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[2]", 1.3823e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[3]", 2.3383e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[0]", 2.6004e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[1]", 2.4844e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[2]", 2.8362e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[3]", 2.7494e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-base-density", 8.544e18);
setprop("/sim/rendering/hdr/atmos/aerosol-relative-background-density", 2.340824e-16);
setprop("/sim/rendering/hdr/atmos/aerosol-scale-height", 0.73);
} else { # Urban (default)
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[0]", 2.8722e-24);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[1]", 4.6168e-24);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[2]", 7.9706e-24);
setprop("/sim/rendering/hdr/atmos/aerosol-absorption-cross-section[3]", 1.3578e-23);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[0]", 1.5908e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[1]", 1.7711e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[2]", 2.0942e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-scattering-cross-section[3]", 2.4033e-22);
setprop("/sim/rendering/hdr/atmos/aerosol-base-density", 1.3681e17);
setprop("/sim/rendering/hdr/atmos/aerosol-relative-background-density", 1.4619e-17);
setprop("/sim/rendering/hdr/atmos/aerosol-scale-height", 0.73);
}
}, 1, 0);
setlistener("/environment/aerosols/turbidity", func(p) {
setprop("/sim/rendering/hdr/atmos/aerosol-turbidity", p.getValue());
}, 1, 0);
setlistener("/environment/ground-albedo", func(p) {
var albedo = p.getValue();
# Use the same albedo value for all wavelengths
for (var i = 0; i < 4; i += 1) {
setprop("/sim/rendering/hdr/atmos/ground-albedo[" ~ i ~ "]", albedo);
}
}, 1, 0);
# Update fog density when the visibility changes
setlistener("/environment/visibility-m", func {
var max = 30000000.0;
var visibility = getprop("/environment/visibility-m");
var vis = math.min(visibility, max);
setprop("/sim/rendering/hdr/atmos/fog-density", max*math.pow(0.99937, vis));
}, 1, 0);
setlistener("/environment/fog-height-falloff", func(p) {
setprop("/sim/rendering/hdr/atmos/fog-scale-height", p.getValue());
}, 1, 0);
setlistener("/environment/fog-height-offset", func(p) {
setprop("/sim/rendering/hdr/atmos/fog-height-offset", p.getValue());
}, 1, 0);
# Ozone concentration depends on the month of the year
setlistener("/sim/time/utc/month", func {
var ozone_mean_monthly_dobson = [
347.0, # January
370.0, # February
381.0, # March
384.0, # April
372.0, # May
352.0, # June
333.0, # July
317.0, # August
298.0, # September
285.0, # October
290.0, # November
315.0 # December
];
var month = getprop("/sim/time/utc/month") or 1;
var index = math.clamp(month - 1, 0, 11);
setprop("/sim/rendering/hdr/atmos/ozone-mean-dobson", ozone_mean_monthly_dobson[index]);
}, 1, 0);
################################################################################
# Environment map
################################################################################
var envmap_frame_listener = nil;
var envmap_updating = false;
var envmap_current_face = 0;
var envmap_prefiltering_active = false;
var envmap_instant_update_active = false;
var envmap_reset_internal_variables = func {
if (envmap_frame_listener != nil) {
removelistener(envmap_frame_listener);
envmap_frame_listener = nil;
}
envmap_updating = false;
envmap_current_face = 0;
envmap_prefiltering_active = false;
envmap_instant_update_active = false;
}
var envmap_set_render_face = func(face, active) {
setprop("/sim/rendering/hdr/envmap/should-render-face-" ~ face, active);
}
var envmap_set_render_all_faces = func(active) {
for (var i = 0; i < 6; i += 1) {
envmap_set_render_face(i, active);
}
}
var envmap_set_prefilter = func(active) {
setprop("/sim/rendering/hdr/envmap/should-prefilter", active);
}
# Update all the faces of the environment cubemap in a single frame
var envmap_update_instant_callback = func {
if (!envmap_instant_update_active) {
# This is the first time this callback has been called so enable
# rendering for all faces.
envmap_set_render_all_faces(true);
envmap_set_prefilter(true);
envmap_instant_update_active = true;
} else {
# This is the second time this callback has been called. Disable
# rendering for all faces.
envmap_set_render_all_faces(false);
envmap_set_prefilter(false);
envmap_reset_internal_variables();
}
}
# Update a single cubemap face each frame. The prefiltering step is also done
# in a separate step, totalling 7 frames to update the entire environment map.
var envmap_update_progressive_callback = func {
if (envmap_prefiltering_active) {
# Last frame we activated the prefiltering, which is the last step.
# Now disable it and reset all variables for the next update cycle.
envmap_set_prefilter(false);
envmap_reset_internal_variables();
return;
}
if (envmap_current_face < 6) {
# Render the current face
envmap_set_render_face(envmap_current_face, true);
}
if (envmap_current_face > 0) {
# Stop rendering the previous face
envmap_set_render_face(envmap_current_face - 1, false);
}
if (envmap_current_face < 6) {
# Go to next face and update it next frame
envmap_current_face += 1;
} else {
# We have finished updating all faces. Reset the face counter and
# prefilter the envmap.
envmap_current_face = 0;
envmap_prefiltering_active = true;
envmap_set_prefilter(true);
}
}
var update_envmap = func(instant = false) {
if (getprop("/sim/rendering/hdr/envmap/update-continuously"))
return;
if (envmap_updating) {
# We were already updating the envmap. If the requested update is
# instant, cancel the ongoing update and start over. If it is a
# progressive update, let the ongoing one finish and do nothing.
if (instant) {
envmap_set_render_all_faces(false);
envmap_set_prefilter(false);
envmap_reset_internal_variables();
envmap_updating = true;
} else {
return;
}
} else {
envmap_updating = true;
}
var callback = instant ? envmap_update_instant_callback
: envmap_update_progressive_callback;
# We use a listener to the frame signal because it is guaranteed to be
# fired at a defined moment, while a settimer() with interval 0 might
# not if subsystems are re-ordered.
envmap_frame_listener = setlistener("/sim/signals/frame", callback);
}
# Continuous update
setlistener("/sim/rendering/hdr/envmap/update-continuously", func(p) {
if (p.getValue()) {
envmap_set_render_all_faces(true);
envmap_set_prefilter(true);
envmap_reset_internal_variables();
} else {
envmap_set_render_all_faces(false);
envmap_set_prefilter(false);
}
}, 1, 0);
# Manual update
setlistener("/sim/rendering/hdr/envmap/force-update", func(p) {
if (p.getValue()) {
update_envmap(true);
p.setValue(false);
}
}, 0, 0);
# Automatically update the envmap every so often
var envmap_timer = maketimer(getprop("/sim/rendering/hdr/envmap/update-rate-s"),
func {
update_envmap(false);
});
envmap_timer.simulatedTime = true;
# Start updating when the FDM is initialized
setlistener("/sim/signals/fdm-initialized", func {
update_envmap(true);
envmap_timer.start();
# Do a single update after 5 seconds when most of the scenery is loaded
settimer(func {
update_envmap(true);
}, 5);
});
# If the update rate is modified at runtime, force an envmap update and restart
# the timer with the new period.
setlistener("/sim/rendering/hdr/envmap/update-rate-s", func(p) {
if (envmap_timer.isRunning) {
update_envmap(false);
envmap_timer.restart(p.getValue());
}
});
# Update the envmap at a much faster rate when time warp is active
var envmap_warp_listener = nil;
var prev_warp = getprop("/sim/time/warp");
var envmap_warp_listener_callback = func {
removelistener(envmap_warp_listener);
envmap_warp_timer.start();
}
var envmap_warp_timer_callback = func {
# Check if the time warp has ended so we can stop updating the envmap so
# regularly.
var current_warp = getprop("/sim/time/warp");
if (current_warp == prev_warp) {
# Time warp has ended, so stop the timer and reattach the listener
envmap_warp_timer.stop();
envmap_warp_listener = setlistener("/sim/time/warp",
envmap_warp_listener_callback, 0, 0);
# Do a final update to make sure the envmap corresponds to the new
# time of day.
update_envmap(true);
} else {
# Time warp is still going so store the previous warp value and update
# the envmap.
prev_warp = current_warp;
update_envmap(true);
}
}
var envmap_warp_timer = maketimer(0.5, envmap_warp_timer_callback);
envmap_warp_timer.simulatedTime = true;
envmap_warp_listener = setlistener("/sim/time/warp",
envmap_warp_listener_callback, 0, 0);
# Update the envmap when the view changes
setlistener("/sim/current-view/view-number", func {
update_envmap(true);
}, 0, 0);