Add default light profile for PortMaster
This commit is contained in:
parent
a62cce6404
commit
a3e0830bd1
16 changed files with 454 additions and 42 deletions
|
|
@ -140,30 +140,52 @@ following in the installed game:
|
||||||
- A single button never cancels auto-map.
|
- A single button never cancels auto-map.
|
||||||
- Holding both bumpers together for 1.25 seconds cancels auto-map.
|
- Holding both bumpers together for 1.25 seconds cancels auto-map.
|
||||||
|
|
||||||
## Low-end performance profile
|
## PortMaster performance profile
|
||||||
|
|
||||||
The launcher keeps the normal game profile on unknown and stronger hardware.
|
Every PortMaster launch defaults to the light performance profile, regardless
|
||||||
It enables the low-end profile only when the Linux device tree reports one of
|
of device family. This reflects the low-end hardware that makes up most of the
|
||||||
the identifiers used by Allwinner H616/H700 XX handhelds:
|
PortMaster ecosystem and keeps the canonical package conservative by default.
|
||||||
|
|
||||||
- `allwinner,h616`
|
The light profile passes these Godot options:
|
||||||
- `sun50iw9p1`
|
|
||||||
- `allwinner,sun50i-h700`
|
|
||||||
|
|
||||||
The low-end profile passes these Godot options:
|
|
||||||
|
|
||||||
- `--single-window`
|
- `--single-window`
|
||||||
- `--disable-vsync`
|
- `--disable-vsync`
|
||||||
- `--max-fps 30`
|
- `--max-fps 30`
|
||||||
- `--audio-output-latency 40`
|
- `--audio-output-latency 40`
|
||||||
|
|
||||||
It also passes `NETFISHING_LOW_END=1`. The game renders the 3D world at 75%
|
It also passes `NETFISHING_PERFORMANCE_PROFILE=light` and
|
||||||
linear resolution with nearest-neighbor scaling, reducing 3D pixel work by
|
`NETFISHING_LOW_END=1`. The game renders the 3D world at 50% linear resolution
|
||||||
about 44% while the separately rendered UI retains its canonical resolution.
|
with nearest-neighbor scaling, reducing 3D pixel work by 75% while the
|
||||||
|
separately rendered UI retains its canonical resolution. The light profile
|
||||||
|
also:
|
||||||
|
|
||||||
Do not use Godot's low processor mode for this profile. It reduces idle CPU
|
- disables the additional full-screen world-pixelation pass;
|
||||||
usage by sleeping between updates and is not a game-performance optimization.
|
- replaces animated depth-aware water shaders with opaque, per-vertex water;
|
||||||
|
- disables ocean surface motion;
|
||||||
|
- reduces rain to 256 particles simulated at 15 FPS; and
|
||||||
|
- replaces procedural sky clouds and 81 moving local cloud patches with one
|
||||||
|
flat cloud ceiling.
|
||||||
|
|
||||||
Before adding a device family, record its exact NUL-separated device-tree
|
The normal profile retains the full visual presentation.
|
||||||
`compatible` value from hardware. Do not infer detection from a retail product
|
|
||||||
name alone.
|
To opt a capable device into the normal profile, create the persistent file
|
||||||
|
`netfishing/conf/performance_profile` containing exactly:
|
||||||
|
|
||||||
|
```text
|
||||||
|
normal
|
||||||
|
```
|
||||||
|
|
||||||
|
On a typical muOS installation, the full path is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/mnt/mmc/ports/netfishing/conf/performance_profile
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the file to `light`, or remove it, to restore the default. An externally
|
||||||
|
provided `NETFISHING_PERFORMANCE_PROFILE=normal` or `light` environment value
|
||||||
|
takes precedence over the persistent file. Invalid values safely fall back to
|
||||||
|
the light profile and are reported in `netfishing/log.txt`.
|
||||||
|
|
||||||
|
Do not use Godot's low processor mode for the light profile. It reduces idle
|
||||||
|
CPU usage by sleeping between updates and is not a game-performance
|
||||||
|
optimization.
|
||||||
|
|
|
||||||
16
main/main.gd
16
main/main.gd
|
|
@ -39,6 +39,9 @@ const PixelationResetOverlayType = preload(
|
||||||
const WorldPixelationPostprocessType = preload(
|
const WorldPixelationPostprocessType = preload(
|
||||||
"res://main/world_pixelation_postprocess.gd"
|
"res://main/world_pixelation_postprocess.gd"
|
||||||
)
|
)
|
||||||
|
const RuntimePerformanceProfileType = preload(
|
||||||
|
"res://main/runtime_performance_profile.gd"
|
||||||
|
)
|
||||||
const NetworkSessionType = preload("res://network/network_session.gd")
|
const NetworkSessionType = preload("res://network/network_session.gd")
|
||||||
const DiscoveryClientType = preload("res://network/discovery_client.gd")
|
const DiscoveryClientType = preload("res://network/discovery_client.gd")
|
||||||
const DedicatedServerConfigType = preload(
|
const DedicatedServerConfigType = preload(
|
||||||
|
|
@ -235,6 +238,7 @@ var _data_folder_dialog: FileDialog
|
||||||
var _data_folder_picker_generation: int = 0
|
var _data_folder_picker_generation: int = 0
|
||||||
var _restore_data_setup_after_picker: bool = false
|
var _restore_data_setup_after_picker: bool = false
|
||||||
var _application_initialized := false
|
var _application_initialized := false
|
||||||
|
var _performance_profile: RuntimePerformanceProfileType
|
||||||
var _pending_existing_root_path := ""
|
var _pending_existing_root_path := ""
|
||||||
var _local_recovery_attempt_id: String = ""
|
var _local_recovery_attempt_id: String = ""
|
||||||
var _dedicated_runtime: bool = false
|
var _dedicated_runtime: bool = false
|
||||||
|
|
@ -244,10 +248,17 @@ var _rain_ambience: RainAmbienceType
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
_performance_profile = RuntimePerformanceProfileType.from_environment()
|
||||||
_dedicated_runtime = _is_dedicated_server_runtime()
|
_dedicated_runtime = _is_dedicated_server_runtime()
|
||||||
if _dedicated_runtime:
|
if _dedicated_runtime:
|
||||||
call_deferred("_start_dedicated_server")
|
call_deferred("_start_dedicated_server")
|
||||||
return
|
return
|
||||||
|
_world_pixelation.set_light_performance_profile(
|
||||||
|
_performance_profile.is_light()
|
||||||
|
)
|
||||||
|
_test_world.set_light_performance_profile(
|
||||||
|
_performance_profile.is_light()
|
||||||
|
)
|
||||||
DisplayServer.window_set_title("NETfishing")
|
DisplayServer.window_set_title("NETfishing")
|
||||||
_rain_ambience = RainAmbienceType.new()
|
_rain_ambience = RainAmbienceType.new()
|
||||||
_rain_ambience.name = "RainAmbience"
|
_rain_ambience.name = "RainAmbience"
|
||||||
|
|
@ -441,6 +452,7 @@ func _initialize_application(dedicated: bool) -> void:
|
||||||
_world_weather,
|
_world_weather,
|
||||||
_player,
|
_player,
|
||||||
Callable(_player, "get_active_gameplay_camera"),
|
Callable(_player, "get_active_gameplay_camera"),
|
||||||
|
_performance_profile.is_light(),
|
||||||
)
|
)
|
||||||
if not _world_time.natural_time_advanced.is_connected(
|
if not _world_time.natural_time_advanced.is_connected(
|
||||||
_on_natural_time_advanced
|
_on_natural_time_advanced
|
||||||
|
|
@ -1324,9 +1336,7 @@ func _apply_world_pixelation(pixel_size: int) -> void:
|
||||||
var root_viewport: Viewport = get_viewport()
|
var root_viewport: Viewport = get_viewport()
|
||||||
root_viewport.scaling_3d_mode = Viewport.SCALING_3D_MODE_NEAREST
|
root_viewport.scaling_3d_mode = Viewport.SCALING_3D_MODE_NEAREST
|
||||||
root_viewport.scaling_3d_scale = (
|
root_viewport.scaling_3d_scale = (
|
||||||
0.75
|
_performance_profile.get_world_render_scale()
|
||||||
if OS.get_environment("NETFISHING_LOW_END") == "1"
|
|
||||||
else 1.0
|
|
||||||
)
|
)
|
||||||
root_viewport.msaa_3d = Viewport.MSAA_DISABLED
|
root_viewport.msaa_3d = Viewport.MSAA_DISABLED
|
||||||
root_viewport.screen_space_aa = Viewport.SCREEN_SPACE_AA_DISABLED
|
root_viewport.screen_space_aa = Viewport.SCREEN_SPACE_AA_DISABLED
|
||||||
|
|
|
||||||
50
main/runtime_performance_profile.gd
Normal file
50
main/runtime_performance_profile.gd
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
class_name RuntimePerformanceProfile
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
const PROFILE_ENVIRONMENT_VARIABLE: String = (
|
||||||
|
"NETFISHING_PERFORMANCE_PROFILE"
|
||||||
|
)
|
||||||
|
const LEGACY_LIGHT_ENVIRONMENT_VARIABLE: String = "NETFISHING_LOW_END"
|
||||||
|
const NORMAL_PROFILE: StringName = &"normal"
|
||||||
|
const LIGHT_PROFILE: StringName = &"light"
|
||||||
|
const NORMAL_WORLD_RENDER_SCALE: float = 1.0
|
||||||
|
const LIGHT_WORLD_RENDER_SCALE: float = 0.5
|
||||||
|
|
||||||
|
var _profile_name: StringName = NORMAL_PROFILE
|
||||||
|
|
||||||
|
|
||||||
|
static func from_environment() -> RuntimePerformanceProfile:
|
||||||
|
return from_name(
|
||||||
|
StringName(OS.get_environment(PROFILE_ENVIRONMENT_VARIABLE)),
|
||||||
|
OS.get_environment(LEGACY_LIGHT_ENVIRONMENT_VARIABLE) == "1",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
static func from_name(
|
||||||
|
profile_name: StringName,
|
||||||
|
legacy_light_requested: bool = false,
|
||||||
|
) -> RuntimePerformanceProfile:
|
||||||
|
var profile := RuntimePerformanceProfile.new()
|
||||||
|
if profile_name == LIGHT_PROFILE or (
|
||||||
|
profile_name.is_empty() and legacy_light_requested
|
||||||
|
):
|
||||||
|
profile._profile_name = LIGHT_PROFILE
|
||||||
|
else:
|
||||||
|
profile._profile_name = NORMAL_PROFILE
|
||||||
|
return profile
|
||||||
|
|
||||||
|
|
||||||
|
func get_profile_name() -> StringName:
|
||||||
|
return _profile_name
|
||||||
|
|
||||||
|
|
||||||
|
func is_light() -> bool:
|
||||||
|
return _profile_name == LIGHT_PROFILE
|
||||||
|
|
||||||
|
|
||||||
|
func get_world_render_scale() -> float:
|
||||||
|
return (
|
||||||
|
LIGHT_WORLD_RENDER_SCALE
|
||||||
|
if is_light()
|
||||||
|
else NORMAL_WORLD_RENDER_SCALE
|
||||||
|
)
|
||||||
1
main/runtime_performance_profile.gd.uid
Normal file
1
main/runtime_performance_profile.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://8vm104r2264h
|
||||||
|
|
@ -5,6 +5,7 @@ extends CanvasLayer
|
||||||
|
|
||||||
var _pixel_size: int = PlayerSettings.DEFAULT_WORLD_PIXEL_SIZE
|
var _pixel_size: int = PlayerSettings.DEFAULT_WORLD_PIXEL_SIZE
|
||||||
var _gameplay_active: bool = false
|
var _gameplay_active: bool = false
|
||||||
|
var _light_performance_profile: bool = false
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
@ -26,6 +27,15 @@ func set_gameplay_active(active: bool) -> void:
|
||||||
_refresh_grid()
|
_refresh_grid()
|
||||||
|
|
||||||
|
|
||||||
|
func set_light_performance_profile(enabled: bool) -> void:
|
||||||
|
_light_performance_profile = enabled
|
||||||
|
_refresh_grid()
|
||||||
|
|
||||||
|
|
||||||
|
func is_light_performance_profile() -> bool:
|
||||||
|
return _light_performance_profile
|
||||||
|
|
||||||
|
|
||||||
func get_grid_size() -> Vector2i:
|
func get_grid_size() -> Vector2i:
|
||||||
return PlayerSettings.get_world_grid_size(
|
return PlayerSettings.get_world_grid_size(
|
||||||
_pixel_size,
|
_pixel_size,
|
||||||
|
|
@ -38,6 +48,7 @@ func _refresh_grid() -> void:
|
||||||
return
|
return
|
||||||
var effect_enabled: bool = (
|
var effect_enabled: bool = (
|
||||||
_gameplay_active
|
_gameplay_active
|
||||||
|
and not _light_performance_profile
|
||||||
and _pixel_size != PlayerSettings.MIN_WORLD_PIXEL_SIZE
|
and _pixel_size != PlayerSettings.MIN_WORLD_PIXEL_SIZE
|
||||||
)
|
)
|
||||||
_screen_grid.visible = effect_enabled
|
_screen_grid.visible = effect_enabled
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,10 @@ The package requires an ARM64 device, two analog sticks, GLIBC 2.28 or newer,
|
||||||
and the \`weston_pkg_0.2\` runtime.
|
and the \`weston_pkg_0.2\` runtime.
|
||||||
|
|
||||||
Save data and device-local configuration remain under \`netfishing/conf/\`.
|
Save data and device-local configuration remain under \`netfishing/conf/\`.
|
||||||
See \`netfishing/licenses/\` for bundled credits and license information.
|
PortMaster launches use the light performance profile by default. Put the word
|
||||||
|
\`normal\` in \`netfishing/conf/performance_profile\` to opt a capable device
|
||||||
|
into the normal rendering profile. See \`netfishing/licenses/\` for bundled
|
||||||
|
credits and license information.
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|
@ -162,6 +165,10 @@ grep -q '"version": 4' "${STAGE_ROOT}/port.json"
|
||||||
grep -q '"name": "netfishing.zip"' "${STAGE_ROOT}/port.json"
|
grep -q '"name": "netfishing.zip"' "${STAGE_ROOT}/port.json"
|
||||||
grep -q '^# PORTMASTER: netfishing.zip, NETfishing.sh$' \
|
grep -q '^# PORTMASTER: netfishing.zip, NETfishing.sh$' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/NETfishing.sh"
|
||||||
|
grep -Fq 'PROFILE_PATH="$CONFDIR/performance_profile"' \
|
||||||
|
"${STAGE_ROOT}/NETfishing.sh"
|
||||||
|
grep -Fq 'NETFISHING_PERFORMANCE_PROFILE=light' \
|
||||||
|
"${STAGE_ROOT}/NETfishing.sh"
|
||||||
if grep -q 'GPTOKEYB' "${STAGE_ROOT}/NETfishing.sh"; then
|
if grep -q 'GPTOKEYB' "${STAGE_ROOT}/NETfishing.sh"; then
|
||||||
echo "GPTOKEYB must not be enabled for NETfishing." >&2
|
echo "GPTOKEYB must not be enabled for NETfishing." >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
|
|
@ -78,17 +78,36 @@ fi
|
||||||
|
|
||||||
NETFISHING_GODOT_OPTIONS=()
|
NETFISHING_GODOT_OPTIONS=()
|
||||||
NETFISHING_GAME_ENVIRONMENT=()
|
NETFISHING_GAME_ENVIRONMENT=()
|
||||||
DEVICE_COMPATIBILITY=""
|
PERFORMANCE_PROFILE="${NETFISHING_PERFORMANCE_PROFILE:-}"
|
||||||
if [[ -r /proc/device-tree/compatible ]]; then
|
PROFILE_PATH="$CONFDIR/performance_profile"
|
||||||
DEVICE_COMPATIBILITY="$(tr '\0' ' ' </proc/device-tree/compatible)"
|
if [[ -z "$PERFORMANCE_PROFILE" && -r "$PROFILE_PATH" ]]; then
|
||||||
elif [[ -r /sys/firmware/devicetree/base/compatible ]]; then
|
IFS= read -r PERFORMANCE_PROFILE < "$PROFILE_PATH" || true
|
||||||
DEVICE_COMPATIBILITY="$(
|
PERFORMANCE_PROFILE="${PERFORMANCE_PROFILE%$'\r'}"
|
||||||
tr '\0' ' ' </sys/firmware/devicetree/base/compatible
|
|
||||||
)"
|
|
||||||
fi
|
fi
|
||||||
case "$DEVICE_COMPATIBILITY" in
|
case "$PERFORMANCE_PROFILE" in
|
||||||
*allwinner,h616*|*sun50iw9p1*|*allwinner,sun50i-h700*)
|
normal)
|
||||||
NETFISHING_GAME_ENVIRONMENT+=("NETFISHING_LOW_END=1")
|
NETFISHING_GAME_ENVIRONMENT+=(
|
||||||
|
"NETFISHING_PERFORMANCE_PROFILE=normal"
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
light|"")
|
||||||
|
NETFISHING_GAME_ENVIRONMENT+=(
|
||||||
|
"NETFISHING_PERFORMANCE_PROFILE=light"
|
||||||
|
"NETFISHING_LOW_END=1"
|
||||||
|
)
|
||||||
|
NETFISHING_GODOT_OPTIONS+=(
|
||||||
|
--single-window
|
||||||
|
--disable-vsync
|
||||||
|
--max-fps 30
|
||||||
|
--audio-output-latency 40
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown performance profile '$PERFORMANCE_PROFILE'; using light." >&2
|
||||||
|
NETFISHING_GAME_ENVIRONMENT+=(
|
||||||
|
"NETFISHING_PERFORMANCE_PROFILE=light"
|
||||||
|
"NETFISHING_LOW_END=1"
|
||||||
|
)
|
||||||
NETFISHING_GODOT_OPTIONS+=(
|
NETFISHING_GODOT_OPTIONS+=(
|
||||||
--single-window
|
--single-window
|
||||||
--disable-vsync
|
--disable-vsync
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ readonly -a QUICK_TESTS=(
|
||||||
|
|
||||||
readonly -a RUNTIME_TESTS=(
|
readonly -a RUNTIME_TESTS=(
|
||||||
"tests/inventory_notepad_art_validation.gd"
|
"tests/inventory_notepad_art_validation.gd"
|
||||||
|
"tests/light_performance_profile_validation.gd"
|
||||||
"tests/logbook_runtime_validation.gd"
|
"tests/logbook_runtime_validation.gd"
|
||||||
"tests/player_experience_ui_validation.gd"
|
"tests/player_experience_ui_validation.gd"
|
||||||
"tests/title_credits_validation.gd"
|
"tests/title_credits_validation.gd"
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,12 @@ func _validate_low_end_profile_contract() -> void:
|
||||||
var launcher: String = FileAccess.get_file_as_string(
|
var launcher: String = FileAccess.get_file_as_string(
|
||||||
"res://scripts/portmaster/NETfishing.sh"
|
"res://scripts/portmaster/NETfishing.sh"
|
||||||
)
|
)
|
||||||
assert(launcher.contains("allwinner,h616"))
|
assert(launcher.contains("NETFISHING_PERFORMANCE_PROFILE:-"))
|
||||||
assert(launcher.contains("sun50iw9p1"))
|
assert(launcher.contains("$CONFDIR/performance_profile"))
|
||||||
|
assert(launcher.contains("normal)"))
|
||||||
|
assert(launcher.contains("light|\"\")"))
|
||||||
|
assert(launcher.contains("NETFISHING_PERFORMANCE_PROFILE=normal"))
|
||||||
|
assert(launcher.contains("NETFISHING_PERFORMANCE_PROFILE=light"))
|
||||||
assert(launcher.contains("NETFISHING_LOW_END=1"))
|
assert(launcher.contains("NETFISHING_LOW_END=1"))
|
||||||
assert(launcher.contains("--max-fps 30"))
|
assert(launcher.contains("--max-fps 30"))
|
||||||
assert(launcher.contains("--audio-output-latency 40"))
|
assert(launcher.contains("--audio-output-latency 40"))
|
||||||
|
|
|
||||||
108
tests/light_performance_profile_validation.gd
Normal file
108
tests/light_performance_profile_validation.gd
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
const MainScene: PackedScene = preload("res://main/main.tscn")
|
||||||
|
const RuntimePerformanceProfileType = preload(
|
||||||
|
"res://main/runtime_performance_profile.gd"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
call_deferred("_run")
|
||||||
|
|
||||||
|
|
||||||
|
func _run() -> void:
|
||||||
|
_validate_profile_resolution()
|
||||||
|
OS.set_environment(
|
||||||
|
RuntimePerformanceProfileType.PROFILE_ENVIRONMENT_VARIABLE,
|
||||||
|
"light",
|
||||||
|
)
|
||||||
|
root.size = Vector2i(640, 480)
|
||||||
|
var main: Node = MainScene.instantiate()
|
||||||
|
root.add_child(main)
|
||||||
|
for _frame: int in 4:
|
||||||
|
await process_frame
|
||||||
|
if not bool(main.get("_application_initialized")):
|
||||||
|
main.call("_activate_selected_data_path", "", true)
|
||||||
|
for _frame: int in 8:
|
||||||
|
await process_frame
|
||||||
|
assert(bool(main.get("_application_initialized")))
|
||||||
|
_validate_main_profile(main)
|
||||||
|
_validate_minimal_weather(main)
|
||||||
|
main.queue_free()
|
||||||
|
for _frame: int in 4:
|
||||||
|
await process_frame
|
||||||
|
OS.unset_environment(
|
||||||
|
RuntimePerformanceProfileType.PROFILE_ENVIRONMENT_VARIABLE
|
||||||
|
)
|
||||||
|
print("Light performance profile validation: PASS")
|
||||||
|
quit()
|
||||||
|
|
||||||
|
|
||||||
|
func _validate_profile_resolution() -> void:
|
||||||
|
var normal := RuntimePerformanceProfileType.from_name(&"normal")
|
||||||
|
var light := RuntimePerformanceProfileType.from_name(&"light")
|
||||||
|
var legacy := RuntimePerformanceProfileType.from_name(&"", true)
|
||||||
|
assert(not normal.is_light())
|
||||||
|
assert(is_equal_approx(normal.get_world_render_scale(), 1.0))
|
||||||
|
assert(light.is_light())
|
||||||
|
assert(is_equal_approx(light.get_world_render_scale(), 0.5))
|
||||||
|
assert(legacy.is_light())
|
||||||
|
|
||||||
|
|
||||||
|
func _validate_main_profile(main: Node) -> void:
|
||||||
|
var profile: RuntimePerformanceProfile = main.get("_performance_profile")
|
||||||
|
assert(profile != null and profile.is_light())
|
||||||
|
assert(is_equal_approx(root.scaling_3d_scale, 0.5))
|
||||||
|
var pixelation: Node = main.get_node("%WorldPixelationPostprocess")
|
||||||
|
assert(bool(pixelation.call("is_light_performance_profile")))
|
||||||
|
pixelation.call("set_gameplay_active", true)
|
||||||
|
var screen_grid := pixelation.get_node("ScreenGrid") as ColorRect
|
||||||
|
assert(screen_grid != null and not screen_grid.visible)
|
||||||
|
|
||||||
|
var pond := main.get_node(
|
||||||
|
"TestWorld/Regions/StarterIslandRegion/WaterBodies/Pond/VisualWater"
|
||||||
|
) as MeshInstance3D
|
||||||
|
var ocean := main.get_node(
|
||||||
|
"TestWorld/Regions/StarterIslandRegion/WaterBodies/Ocean/VisualWater"
|
||||||
|
) as MeshInstance3D
|
||||||
|
assert(pond.material_override is StandardMaterial3D)
|
||||||
|
assert(ocean.material_override is StandardMaterial3D)
|
||||||
|
assert(not pond.material_override is ShaderMaterial)
|
||||||
|
assert(not ocean.material_override is ShaderMaterial)
|
||||||
|
assert(not ocean.is_processing())
|
||||||
|
|
||||||
|
|
||||||
|
func _validate_minimal_weather(main: Node) -> void:
|
||||||
|
var visuals: WorldTimeVisualController = main.get_node(
|
||||||
|
"%WorldTimeVisualController"
|
||||||
|
)
|
||||||
|
var rain := visuals.get_node("LocalRain") as GPUParticles3D
|
||||||
|
assert(rain.amount == WorldTimeVisualController.LIGHT_RAIN_PARTICLE_AMOUNT)
|
||||||
|
assert(rain.fixed_fps == WorldTimeVisualController.LIGHT_RAIN_FIXED_FPS)
|
||||||
|
var clouds := visuals.get_node("LocalStormClouds") as LocalStormCloudLayer
|
||||||
|
assert(clouds.get_patch_count() == 1)
|
||||||
|
var ceiling := clouds.get_node("CloudCeiling") as MeshInstance3D
|
||||||
|
assert(ceiling != null and ceiling.mesh is PlaneMesh)
|
||||||
|
assert(ceiling.material_override == null)
|
||||||
|
assert((ceiling.mesh as PlaneMesh).material is StandardMaterial3D)
|
||||||
|
|
||||||
|
visuals.apply_weather_immediately(WorldWeatherService.Weather.RAINY)
|
||||||
|
assert(rain.emitting and rain.amount_ratio > 0.99)
|
||||||
|
assert(clouds.visible and clouds.get_storm_amount() > 0.87)
|
||||||
|
var cloud_material := (
|
||||||
|
(ceiling.mesh as PlaneMesh).material as StandardMaterial3D
|
||||||
|
)
|
||||||
|
assert(cloud_material.albedo_color.a < 0.65)
|
||||||
|
var test_world := main.get_node("TestWorld") as TestWorld
|
||||||
|
var runtime_environment := (
|
||||||
|
test_world.get_world_environment().environment as Environment
|
||||||
|
)
|
||||||
|
var sky_material := (
|
||||||
|
runtime_environment.sky.sky_material as ShaderMaterial
|
||||||
|
)
|
||||||
|
assert(is_zero_approx(float(
|
||||||
|
sky_material.get_shader_parameter("cloud_coverage")
|
||||||
|
)))
|
||||||
|
assert(is_zero_approx(float(
|
||||||
|
sky_material.get_shader_parameter("cloud_opacity")
|
||||||
|
)))
|
||||||
1
tests/light_performance_profile_validation.gd.uid
Normal file
1
tests/light_performance_profile_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c6xqcslinxd1a
|
||||||
|
|
@ -13,6 +13,9 @@ const DISTANCE_FADE_START: float = 240.0
|
||||||
const DISTANCE_FADE_END: float = 300.0
|
const DISTANCE_FADE_END: float = 300.0
|
||||||
const WRAP_RADIUS: float = FIELD_HALF_EXTENT
|
const WRAP_RADIUS: float = FIELD_HALF_EXTENT
|
||||||
const MAXIMUM_OPACITY: float = 1.0
|
const MAXIMUM_OPACITY: float = 1.0
|
||||||
|
const LIGHT_CEILING_SIZE: float = 520.0
|
||||||
|
const LIGHT_CEILING_ALTITUDE: float = 20.0
|
||||||
|
const LIGHT_MAXIMUM_OPACITY: float = 0.72
|
||||||
const BASE_VELOCITY := Vector2(0.825, -0.45)
|
const BASE_VELOCITY := Vector2(0.825, -0.45)
|
||||||
const BODY_OUTLINE: Array[Vector2] = [
|
const BODY_OUTLINE: Array[Vector2] = [
|
||||||
Vector2(-6.9, -0.8),
|
Vector2(-6.9, -0.8),
|
||||||
|
|
@ -50,12 +53,23 @@ var _target: Node3D
|
||||||
var _material: ShaderMaterial
|
var _material: ShaderMaterial
|
||||||
var _multimesh: MultiMesh
|
var _multimesh: MultiMesh
|
||||||
var _cloud_mesh: MultiMeshInstance3D
|
var _cloud_mesh: MultiMeshInstance3D
|
||||||
|
var _light_cloud_mesh: MeshInstance3D
|
||||||
|
var _light_material: StandardMaterial3D
|
||||||
var _drift_offset := Vector2.ZERO
|
var _drift_offset := Vector2.ZERO
|
||||||
var _storm_amount: float = 0.0
|
var _storm_amount: float = 0.0
|
||||||
|
var _light_performance_profile: bool = false
|
||||||
|
|
||||||
|
|
||||||
func setup(target: Node3D) -> void:
|
func setup(
|
||||||
|
target: Node3D,
|
||||||
|
light_performance_profile: bool = false,
|
||||||
|
) -> void:
|
||||||
_target = target
|
_target = target
|
||||||
|
_light_performance_profile = light_performance_profile
|
||||||
|
if _light_performance_profile:
|
||||||
|
_build_light_cloud_ceiling()
|
||||||
|
_update_light_position()
|
||||||
|
else:
|
||||||
_build_cloud_field()
|
_build_cloud_field()
|
||||||
_update_cloud_transforms()
|
_update_cloud_transforms()
|
||||||
set_process(true)
|
set_process(true)
|
||||||
|
|
@ -65,8 +79,19 @@ func set_storm_amount(amount: float, color: Color) -> void:
|
||||||
_storm_amount = clampf(amount, 0.0, 1.0)
|
_storm_amount = clampf(amount, 0.0, 1.0)
|
||||||
var should_be_visible: bool = _storm_amount > 0.001
|
var should_be_visible: bool = _storm_amount > 0.001
|
||||||
if should_be_visible and not visible:
|
if should_be_visible and not visible:
|
||||||
|
if _light_performance_profile:
|
||||||
|
_update_light_position()
|
||||||
|
else:
|
||||||
_update_cloud_transforms()
|
_update_cloud_transforms()
|
||||||
visible = should_be_visible
|
visible = should_be_visible
|
||||||
|
if _light_performance_profile:
|
||||||
|
if _light_material != null:
|
||||||
|
var light_color: Color = color
|
||||||
|
light_color.a = (
|
||||||
|
_storm_amount * LIGHT_MAXIMUM_OPACITY
|
||||||
|
)
|
||||||
|
_light_material.albedo_color = light_color
|
||||||
|
return
|
||||||
if _material == null:
|
if _material == null:
|
||||||
return
|
return
|
||||||
_material.set_shader_parameter("weather_opacity", _storm_amount)
|
_material.set_shader_parameter("weather_opacity", _storm_amount)
|
||||||
|
|
@ -78,12 +103,19 @@ func get_storm_amount() -> float:
|
||||||
|
|
||||||
|
|
||||||
func get_patch_count() -> int:
|
func get_patch_count() -> int:
|
||||||
return GRID_AXIS_COUNT * GRID_AXIS_COUNT
|
return (
|
||||||
|
1
|
||||||
|
if _light_performance_profile
|
||||||
|
else GRID_AXIS_COUNT * GRID_AXIS_COUNT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if not visible or _target == null or not is_instance_valid(_target):
|
if not visible or _target == null or not is_instance_valid(_target):
|
||||||
return
|
return
|
||||||
|
if _light_performance_profile:
|
||||||
|
_update_light_position()
|
||||||
|
return
|
||||||
_drift_offset += BASE_VELOCITY * delta
|
_drift_offset += BASE_VELOCITY * delta
|
||||||
_drift_offset = Vector2(
|
_drift_offset = Vector2(
|
||||||
_wrap_axis(_drift_offset.x),
|
_wrap_axis(_drift_offset.x),
|
||||||
|
|
@ -128,6 +160,37 @@ func _build_cloud_field() -> void:
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _build_light_cloud_ceiling() -> void:
|
||||||
|
_light_material = StandardMaterial3D.new()
|
||||||
|
_light_material.resource_name = "light_cloud_ceiling"
|
||||||
|
_light_material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
|
_light_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
_light_material.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||||
|
_light_material.albedo_color = Color(0.22, 0.25, 0.26, 0.0)
|
||||||
|
var ceiling_mesh := PlaneMesh.new()
|
||||||
|
ceiling_mesh.size = Vector2.ONE * LIGHT_CEILING_SIZE
|
||||||
|
ceiling_mesh.material = _light_material
|
||||||
|
_light_cloud_mesh = MeshInstance3D.new()
|
||||||
|
_light_cloud_mesh.name = "CloudCeiling"
|
||||||
|
_light_cloud_mesh.position.y = LIGHT_CEILING_ALTITUDE
|
||||||
|
_light_cloud_mesh.mesh = ceiling_mesh
|
||||||
|
_light_cloud_mesh.cast_shadow = (
|
||||||
|
GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||||
|
)
|
||||||
|
add_child(_light_cloud_mesh)
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _update_light_position() -> void:
|
||||||
|
if _target == null or not is_instance_valid(_target):
|
||||||
|
return
|
||||||
|
global_position = Vector3(
|
||||||
|
_target.global_position.x,
|
||||||
|
0.0,
|
||||||
|
_target.global_position.z,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func _build_cloud_body_mesh() -> ArrayMesh:
|
func _build_cloud_body_mesh() -> ArrayMesh:
|
||||||
var outline := PackedVector2Array(BODY_OUTLINE)
|
var outline := PackedVector2Array(BODY_OUTLINE)
|
||||||
var surface_tool := SurfaceTool.new()
|
var surface_tool := SurfaceTool.new()
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,14 @@ const FOLIAGE_MATERIAL_NAMES: Array[StringName] = [
|
||||||
&"leaf_light",
|
&"leaf_light",
|
||||||
&"leaf_dark",
|
&"leaf_dark",
|
||||||
]
|
]
|
||||||
|
const NORMAL_SALT_WATER_MATERIAL: Material = preload(
|
||||||
|
"res://world/materials/stylized_water.tres"
|
||||||
|
)
|
||||||
|
const NORMAL_FRESH_WATER_MATERIAL: Material = preload(
|
||||||
|
"res://world/materials/stylized_water_fresh.tres"
|
||||||
|
)
|
||||||
|
const LIGHT_SALT_WATER_COLOR := Color(0.11, 0.345, 0.435)
|
||||||
|
const LIGHT_FRESH_WATER_COLOR := Color(0.18, 0.46, 0.50)
|
||||||
|
|
||||||
@export_group("Owned Nodes")
|
@export_group("Owned Nodes")
|
||||||
@export_node_path("MeshInstance3D")
|
@export_node_path("MeshInstance3D")
|
||||||
|
|
@ -60,6 +68,48 @@ func get_saltwater_shoreline_mesh() -> MeshInstance3D:
|
||||||
return get_node_or_null(^"ShorelineRibbons/Ocean") as MeshInstance3D
|
return get_node_or_null(^"ShorelineRibbons/Ocean") as MeshInstance3D
|
||||||
|
|
||||||
|
|
||||||
|
func set_light_performance_profile(enabled: bool) -> void:
|
||||||
|
var pond := get_node_or_null(
|
||||||
|
^"WaterBodies/Pond/VisualWater"
|
||||||
|
) as MeshInstance3D
|
||||||
|
var ocean := get_node_or_null(
|
||||||
|
^"WaterBodies/Ocean/VisualWater"
|
||||||
|
) as MeshInstance3D
|
||||||
|
if pond != null:
|
||||||
|
pond.material_override = (
|
||||||
|
_create_light_water_material(
|
||||||
|
LIGHT_FRESH_WATER_COLOR,
|
||||||
|
&"light_fresh_water",
|
||||||
|
)
|
||||||
|
if enabled
|
||||||
|
else NORMAL_FRESH_WATER_MATERIAL
|
||||||
|
)
|
||||||
|
if ocean != null:
|
||||||
|
ocean.material_override = (
|
||||||
|
_create_light_water_material(
|
||||||
|
LIGHT_SALT_WATER_COLOR,
|
||||||
|
&"light_salt_water",
|
||||||
|
)
|
||||||
|
if enabled
|
||||||
|
else NORMAL_SALT_WATER_MATERIAL
|
||||||
|
)
|
||||||
|
var surface_motion := ocean as WaterSurfaceMotion
|
||||||
|
if surface_motion != null:
|
||||||
|
surface_motion.set_motion_enabled(not enabled)
|
||||||
|
|
||||||
|
|
||||||
|
func _create_light_water_material(
|
||||||
|
color: Color,
|
||||||
|
material_name: StringName,
|
||||||
|
) -> StandardMaterial3D:
|
||||||
|
var material := StandardMaterial3D.new()
|
||||||
|
material.resource_name = str(material_name)
|
||||||
|
material.albedo_color = color
|
||||||
|
material.roughness = 1.0
|
||||||
|
material.shading_mode = BaseMaterial3D.SHADING_MODE_PER_VERTEX
|
||||||
|
return material
|
||||||
|
|
||||||
|
|
||||||
func get_spawn_surface_triangles(
|
func get_spawn_surface_triangles(
|
||||||
material_names: Array[StringName],
|
material_names: Array[StringName],
|
||||||
minimum_global_y: float,
|
minimum_global_y: float,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ func get_sun() -> DirectionalLight3D:
|
||||||
return _sun
|
return _sun
|
||||||
|
|
||||||
|
|
||||||
|
func set_light_performance_profile(enabled: bool) -> void:
|
||||||
|
_starter_island.set_light_performance_profile(enabled)
|
||||||
|
|
||||||
|
|
||||||
func get_fishable_water_regions() -> Array[FishableWaterRegion]:
|
func get_fishable_water_regions() -> Array[FishableWaterRegion]:
|
||||||
var waters: Array[FishableWaterRegion] = []
|
var waters: Array[FishableWaterRegion] = []
|
||||||
for region: WorldRegion in _get_regions():
|
for region: WorldRegion in _get_regions():
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@ func _process(_delta: float) -> void:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func set_motion_enabled(enabled: bool) -> void:
|
||||||
|
set_process(enabled and amplitude > 0.0)
|
||||||
|
if not enabled:
|
||||||
|
position.y = _base_height
|
||||||
|
|
||||||
|
|
||||||
static func get_default_height_offset() -> float:
|
static func get_default_height_offset() -> float:
|
||||||
return calculate_height_offset(
|
return calculate_height_offset(
|
||||||
_current_time_seconds(),
|
_current_time_seconds(),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ class_name WorldTimeVisualController
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
const UPDATE_INTERVAL_SECONDS: float = 0.1
|
const UPDATE_INTERVAL_SECONDS: float = 0.1
|
||||||
|
const LIGHT_UPDATE_INTERVAL_SECONDS: float = 0.25
|
||||||
const SUN_YAW_DEGREES: float = -32.0
|
const SUN_YAW_DEGREES: float = -32.0
|
||||||
const WEATHER_TRANSITION_SECONDS: float = 10.0
|
const WEATHER_TRANSITION_SECONDS: float = 10.0
|
||||||
const RAIN_EMITTER_OFFSET := Vector3(0.0, 7.0, 0.0)
|
const RAIN_EMITTER_OFFSET := Vector3(0.0, 7.0, 0.0)
|
||||||
|
|
@ -11,6 +12,8 @@ const RAIN_VISIBILITY_AABB := AABB(
|
||||||
Vector3(27.0, 12.0, 27.0),
|
Vector3(27.0, 12.0, 27.0),
|
||||||
)
|
)
|
||||||
const RAIN_PARTICLE_AMOUNT: int = 2240
|
const RAIN_PARTICLE_AMOUNT: int = 2240
|
||||||
|
const LIGHT_RAIN_PARTICLE_AMOUNT: int = 256
|
||||||
|
const LIGHT_RAIN_FIXED_FPS: int = 15
|
||||||
const RAIN_VELOCITY_MIN: float = 16.0
|
const RAIN_VELOCITY_MIN: float = 16.0
|
||||||
const RAIN_VELOCITY_MAX: float = 20.0
|
const RAIN_VELOCITY_MAX: float = 20.0
|
||||||
const RAIN_DROP_SIZE := Vector3(0.014, 0.34, 0.014)
|
const RAIN_DROP_SIZE := Vector3(0.014, 0.34, 0.014)
|
||||||
|
|
@ -92,6 +95,7 @@ var _weather_to: WorldWeatherService.Weather = (
|
||||||
WorldWeatherService.Weather.SUNNY
|
WorldWeatherService.Weather.SUNNY
|
||||||
)
|
)
|
||||||
var _weather_transition: float = 1.0
|
var _weather_transition: float = 1.0
|
||||||
|
var _light_performance_profile: bool = false
|
||||||
|
|
||||||
|
|
||||||
func setup(
|
func setup(
|
||||||
|
|
@ -101,6 +105,7 @@ func setup(
|
||||||
weather_service: WorldWeatherService = null,
|
weather_service: WorldWeatherService = null,
|
||||||
rain_target: Node3D = null,
|
rain_target: Node3D = null,
|
||||||
rain_camera_provider: Callable = Callable(),
|
rain_camera_provider: Callable = Callable(),
|
||||||
|
light_performance_profile: bool = false,
|
||||||
) -> void:
|
) -> void:
|
||||||
_time_service = time_service
|
_time_service = time_service
|
||||||
_weather_service = weather_service
|
_weather_service = weather_service
|
||||||
|
|
@ -108,6 +113,7 @@ func setup(
|
||||||
_sun = sun
|
_sun = sun
|
||||||
_rain_target = rain_target
|
_rain_target = rain_target
|
||||||
_rain_camera_provider = rain_camera_provider
|
_rain_camera_provider = rain_camera_provider
|
||||||
|
_light_performance_profile = light_performance_profile
|
||||||
if not _prepare_runtime_environment():
|
if not _prepare_runtime_environment():
|
||||||
set_process(false)
|
set_process(false)
|
||||||
return
|
return
|
||||||
|
|
@ -135,7 +141,12 @@ func _process(delta: float) -> void:
|
||||||
1.0,
|
1.0,
|
||||||
)
|
)
|
||||||
_elapsed += delta
|
_elapsed += delta
|
||||||
if _elapsed < UPDATE_INTERVAL_SECONDS:
|
var update_interval: float = (
|
||||||
|
LIGHT_UPDATE_INTERVAL_SECONDS
|
||||||
|
if _light_performance_profile
|
||||||
|
else UPDATE_INTERVAL_SECONDS
|
||||||
|
)
|
||||||
|
if _elapsed < update_interval:
|
||||||
return
|
return
|
||||||
_elapsed = 0.0
|
_elapsed = 0.0
|
||||||
_apply_time(_time_service.get_time_hours())
|
_apply_time(_time_service.get_time_hours())
|
||||||
|
|
@ -187,10 +198,16 @@ func _prepare_runtime_environment() -> bool:
|
||||||
func _prepare_rain() -> void:
|
func _prepare_rain() -> void:
|
||||||
_rain = GPUParticles3D.new()
|
_rain = GPUParticles3D.new()
|
||||||
_rain.name = "LocalRain"
|
_rain.name = "LocalRain"
|
||||||
_rain.amount = RAIN_PARTICLE_AMOUNT
|
_rain.amount = (
|
||||||
|
LIGHT_RAIN_PARTICLE_AMOUNT
|
||||||
|
if _light_performance_profile
|
||||||
|
else RAIN_PARTICLE_AMOUNT
|
||||||
|
)
|
||||||
_rain.amount_ratio = 0.0
|
_rain.amount_ratio = 0.0
|
||||||
_rain.lifetime = 1.25
|
_rain.lifetime = 1.25
|
||||||
_rain.fixed_fps = 30
|
_rain.fixed_fps = (
|
||||||
|
LIGHT_RAIN_FIXED_FPS if _light_performance_profile else 30
|
||||||
|
)
|
||||||
_rain.local_coords = false
|
_rain.local_coords = false
|
||||||
_rain.visibility_aabb = RAIN_VISIBILITY_AABB
|
_rain.visibility_aabb = RAIN_VISIBILITY_AABB
|
||||||
var process_material := ParticleProcessMaterial.new()
|
var process_material := ParticleProcessMaterial.new()
|
||||||
|
|
@ -220,7 +237,7 @@ func _prepare_storm_clouds() -> void:
|
||||||
_storm_clouds = LocalStormCloudLayerType.new()
|
_storm_clouds = LocalStormCloudLayerType.new()
|
||||||
_storm_clouds.name = "LocalStormClouds"
|
_storm_clouds.name = "LocalStormClouds"
|
||||||
add_child(_storm_clouds)
|
add_child(_storm_clouds)
|
||||||
_storm_clouds.setup(_rain_target)
|
_storm_clouds.setup(_rain_target, _light_performance_profile)
|
||||||
|
|
||||||
|
|
||||||
func _apply_time(time_hours: float) -> void:
|
func _apply_time(time_hours: float) -> void:
|
||||||
|
|
@ -259,6 +276,33 @@ func _apply_time(time_hours: float) -> void:
|
||||||
var fog_color: Color = _blended_color(
|
var fog_color: Color = _blended_color(
|
||||||
NIGHT_FOG, DAY_FOG, WARM_FOG, daylight, warmth
|
NIGHT_FOG, DAY_FOG, WARM_FOG, daylight, warmth
|
||||||
)
|
)
|
||||||
|
if _light_performance_profile:
|
||||||
|
var simple_cloud_color := _blended_color(
|
||||||
|
NIGHT_CLOUD_SHADOW,
|
||||||
|
DAY_CLOUD_SHADOW,
|
||||||
|
WARM_CLOUD_SHADOW,
|
||||||
|
daylight,
|
||||||
|
warmth,
|
||||||
|
)
|
||||||
|
var simple_overcast: float = _weather_value(
|
||||||
|
0.0,
|
||||||
|
0.55,
|
||||||
|
0.82,
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
sky_top = sky_top.lerp(simple_cloud_color, simple_overcast)
|
||||||
|
sky_horizon = sky_horizon.lerp(
|
||||||
|
simple_cloud_color.lightened(0.08),
|
||||||
|
simple_overcast,
|
||||||
|
)
|
||||||
|
ground_bottom = ground_bottom.lerp(
|
||||||
|
simple_cloud_color.darkened(0.12),
|
||||||
|
simple_overcast * 0.65,
|
||||||
|
)
|
||||||
|
ground_horizon = ground_horizon.lerp(
|
||||||
|
simple_cloud_color,
|
||||||
|
simple_overcast * 0.75,
|
||||||
|
)
|
||||||
var foggy_fog_amount: float = _weather_value(0.0, 0.0, 0.0, 1.0)
|
var foggy_fog_amount: float = _weather_value(0.0, 0.0, 0.0, 1.0)
|
||||||
var rain_fog_amount: float = _weather_value(0.0, 0.0, 1.0, 0.0)
|
var rain_fog_amount: float = _weather_value(0.0, 0.0, 1.0, 0.0)
|
||||||
var fog_daylight_amount: float = daylight * foggy_fog_amount
|
var fog_daylight_amount: float = daylight * foggy_fog_amount
|
||||||
|
|
@ -399,6 +443,8 @@ func _apply_water_environment(
|
||||||
foggy_horizon_occlusion: float,
|
foggy_horizon_occlusion: float,
|
||||||
fog_render_color: Color,
|
fog_render_color: Color,
|
||||||
) -> void:
|
) -> void:
|
||||||
|
if _light_performance_profile:
|
||||||
|
return
|
||||||
var water_tint := _blended_color(
|
var water_tint := _blended_color(
|
||||||
NIGHT_WATER_TINT,
|
NIGHT_WATER_TINT,
|
||||||
Color.WHITE,
|
Color.WHITE,
|
||||||
|
|
@ -561,6 +607,15 @@ func _apply_sky_clouds(daylight: float, warmth: float) -> void:
|
||||||
daylight,
|
daylight,
|
||||||
warmth,
|
warmth,
|
||||||
)
|
)
|
||||||
|
if _light_performance_profile:
|
||||||
|
_sky_material.set_shader_parameter("cloud_coverage", 0.0)
|
||||||
|
_sky_material.set_shader_parameter("cloud_opacity", 0.0)
|
||||||
|
if _storm_clouds != null:
|
||||||
|
_storm_clouds.set_storm_amount(
|
||||||
|
_weather_value(0.0, 0.42, 0.88, 0.0),
|
||||||
|
lower_cloud_color,
|
||||||
|
)
|
||||||
|
return
|
||||||
_sky_material.set_shader_parameter(
|
_sky_material.set_shader_parameter(
|
||||||
"cloud_coverage",
|
"cloud_coverage",
|
||||||
_weather_value(0.0, 0.58, 0.985, 0.0),
|
_weather_value(0.0, 0.58, 0.985, 0.0),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue