feat(environment): add painterly skies and living meadows

This commit is contained in:
Rijad Zuzo
2026-09-05 20:27:09 +02:00
parent 7899d36f03
commit ec16e2f2ca
71 changed files with 2280 additions and 213 deletions
+131 -11
View File
@@ -8,6 +8,8 @@ func _initialize() -> void:
func _run() -> void:
var viewport := root as Viewport
var original_msaa := viewport.msaa_3d
var camera := Camera3D.new()
camera.current = true
root.add_child(camera)
@@ -16,13 +18,14 @@ func _run() -> void:
await process_frame
await physics_frame
var viewport := root as Viewport
var environment: Environment = (
(world.get_node("WorldEnvironment") as WorldEnvironment).environment
)
var light := world.get_node("DirectionalLight3D") as DirectionalLight3D
var grass := world.get_node("TerrainRoot/Terrain3D/CozyGrassField") as Node3D
var grass_controller := world.get_node("TerrainRoot/GrassInteractionController") as Node
var meadow := world.get_node("PainterlyMeadow") as PainterlyMeadow
var balanced_meadow := meadow.get_presentation_stats()
var world_grass_material := grass.get("mesh_material_override") as ShaderMaterial
var world_process_material := grass.get("process_material") as ShaderMaterial
var world_sky: Sky = environment.sky
@@ -41,6 +44,10 @@ func _run() -> void:
+ " (found %.2f)" % balanced_render_scale
)
)
_check(
viewport.msaa_3d == mini(original_msaa, Viewport.MSAA_2X),
"Balanced should cap authored multisample antialiasing at 2x"
)
_check(
(
light.directional_shadow_max_distance <= JajceWorld.BALANCED_SHADOW_DISTANCE
@@ -54,6 +61,14 @@ func _run() -> void:
world_grass_material == grass_controller.get("grass_material"),
"Grass rendering and interaction should share this world's isolated material"
)
_check(
(
int(balanced_meadow["multimesh_batch_count"]) == 4
and int(balanced_meadow["flower_clump_count"]) in range(1, 1801)
and _meadow_has_finite_placements(meadow)
),
"Meadow batches should retain neutral instance colors, finite placement and their clump budget"
)
_check(
world.apply_presentation_quality(JajceWorld.PresentationQuality.HIGH),
@@ -63,6 +78,21 @@ func _run() -> void:
var high_particle_count := int(grass.get("particle_count"))
var high_render_scale := viewport.scaling_3d_scale
var high_shadow_distance := light.directional_shadow_max_distance
_check(
viewport.msaa_3d == original_msaa,
"High should restore the authored multisample antialiasing setting"
)
var high_meadow := meadow.get_presentation_stats()
_check(
(
int(high_meadow["visible_flower_clump_count"]) == int(high_meadow["flower_clump_count"])
and (
int(balanced_meadow["visible_flower_clump_count"])
< int(high_meadow["visible_flower_clump_count"])
)
),
"High should restore every flower clump while Balanced reduces meadow density"
)
_check(
high_particle_count in range(9000, 15001),
"High should restore the authored grass population"
@@ -94,6 +124,9 @@ func _run() -> void:
viewport.scaling_3d_scale <= JajceWorld.LOW_RENDER_SCALE + 0.001,
"Low should reduce 3D render resolution"
)
_check(
viewport.msaa_3d == Viewport.MSAA_DISABLED, "Low should disable multisample antialiasing"
)
_check(
(
environment.fog_enabled
@@ -120,6 +153,18 @@ func _run() -> void:
)
_check(not grass_controller.is_processing(), "Low should stop grass interaction scans")
_check(_not_any_grass_particle_emitting(grass), "Low should stop every grass particle emitter")
var low_meadow := meadow.get_presentation_stats()
_check(
(
int(low_meadow["visible_flower_clump_count"]) > 0
and (
int(low_meadow["visible_flower_clump_count"])
< int(balanced_meadow["visible_flower_clump_count"])
)
and low_meadow["flower_clump_count"] == high_meadow["flower_clump_count"]
),
"Low should retain a reduced flower population without regenerating placements"
)
_check(
(
world_grass_material != null
@@ -136,6 +181,7 @@ func _run() -> void:
_check(
(
is_equal_approx(viewport.scaling_3d_scale, high_render_scale)
and viewport.msaa_3d == original_msaa
and environment.glow_enabled
and (environment.volumetric_fog_enabled == world.call("_supports_volumetric_fog"))
and environment.adjustment_enabled
@@ -153,12 +199,19 @@ func _run() -> void:
),
"Returning to High should restore grass rendering and processing"
)
_check(
meadow.get_presentation_stats() == high_meadow,
"Returning to High should restore the same complete flower batches"
)
var world_base_scale := float(world.get("_authored_render_scale"))
world.free()
_check(
is_equal_approx(viewport.scaling_3d_scale, world_base_scale),
"An exiting world should restore the viewport scale it originally owned"
(
is_equal_approx(viewport.scaling_3d_scale, world_base_scale)
and viewport.msaa_3d == original_msaa
),
"An exiting world should restore the viewport scale and antialiasing it originally owned"
)
_check(
(
@@ -183,6 +236,7 @@ func _run() -> void:
_check(
(
fresh_world.get_active_presentation_quality() == JajceWorld.PresentationQuality.BALANCED
and viewport.msaa_3d == mini(original_msaa, Viewport.MSAA_2X)
and fresh_environment.fog_enabled
and not fresh_environment.volumetric_fog_enabled
and fresh_grass.visible
@@ -205,8 +259,11 @@ func _run() -> void:
var original_scale := float(fresh_world.get("_authored_render_scale"))
fresh_world.free()
_check(
is_equal_approx(viewport.scaling_3d_scale, original_scale),
"A sequential world should release its viewport-scale ownership"
(
is_equal_approx(viewport.scaling_3d_scale, original_scale)
and viewport.msaa_3d == original_msaa
),
"A sequential world should release its viewport scale and antialiasing ownership"
)
var older_owner := _create_presentation_only_world(JajceWorld.PresentationQuality.LOW)
@@ -216,19 +273,29 @@ func _run() -> void:
root.add_child(newer_owner)
await process_frame
_check(
is_equal_approx(float(newer_owner.get("_authored_render_scale")), original_scale),
"Concurrent owners should inherit the viewport base, not another owner's reduced scale"
(
is_equal_approx(float(newer_owner.get("_authored_render_scale")), original_scale)
and int(newer_owner.get("_authored_msaa")) == original_msaa
),
"Concurrent owners should inherit the viewport's base scale and antialiasing"
)
older_owner.free()
_check(
is_equal_approx(viewport.scaling_3d_scale, JajceWorld.BALANCED_RENDER_SCALE),
"A stale owner exiting should not overwrite the active owner's scale"
(
is_equal_approx(viewport.scaling_3d_scale, JajceWorld.BALANCED_RENDER_SCALE)
and viewport.msaa_3d == mini(original_msaa, Viewport.MSAA_2X)
),
"A stale owner exiting should preserve the active owner's scale and antialiasing"
)
newer_owner.free()
_check(
is_equal_approx(viewport.scaling_3d_scale, original_scale),
"The final viewport owner should restore the original scale on exit"
(
is_equal_approx(viewport.scaling_3d_scale, original_scale)
and viewport.msaa_3d == original_msaa
),
"The final viewport owner should restore the original scale and antialiasing on exit"
)
await _check_msaa_previous_owner_and_external_change(viewport)
var main_scene: Node = load("res://main.tscn").instantiate()
var time_dial := main_scene.get_node("UI/TimeDial") as Control
@@ -264,6 +331,32 @@ func _all_grass_particles_emitting(grass: Node3D) -> bool:
return true
func _meadow_has_finite_placements(meadow: PainterlyMeadow) -> bool:
var terrain := meadow.get_node(meadow.terrain_path) as Terrain3D
# The dummy headless renderer returns black for every instance-color readback.
var can_read_instance_colors := DisplayServer.get_name() != "headless"
for child in meadow.get_children():
var batch := child as MultiMeshInstance3D
if batch == null or batch.multimesh == null:
return false
if not batch.multimesh.use_colors or not batch.multimesh.use_custom_data:
return false
for index in batch.multimesh.instance_count:
if (
can_read_instance_colors
and not batch.multimesh.get_instance_color(index).is_equal_approx(Color.WHITE)
):
return false
var placement := batch.multimesh.get_instance_transform(index)
if not placement.is_finite():
return false
var point := batch.to_global(placement.origin)
var height := terrain.data.get_height(point)
if is_nan(height) or absf(point.y - height) > 0.025:
return false
return true
func _create_presentation_only_world(quality: int) -> JajceWorld:
var world: JajceWorld = load("res://world/jajce/JajceWorld.tscn").instantiate()
# Stable simulation-facing IDs deliberately allow only one loaded authority
@@ -273,6 +366,33 @@ func _create_presentation_only_world(quality: int) -> JajceWorld:
return world
func _check_msaa_previous_owner_and_external_change(viewport: Viewport) -> void:
var original_msaa := viewport.msaa_3d
viewport.msaa_3d = Viewport.MSAA_8X
var previous_owner := _create_presentation_only_world(JajceWorld.PresentationQuality.LOW)
root.add_child(previous_owner)
await process_frame
var active_owner := _create_presentation_only_world(JajceWorld.PresentationQuality.HIGH)
root.add_child(active_owner)
await process_frame
_check(
viewport.msaa_3d == Viewport.MSAA_8X,
"A High owner should inherit authored antialiasing even when the previous owner uses Low"
)
active_owner.free()
_check(
viewport.msaa_3d == Viewport.MSAA_DISABLED,
"An exiting active owner should restore the surviving previous owner's antialiasing"
)
viewport.msaa_3d = Viewport.MSAA_2X
previous_owner.free()
_check(
viewport.msaa_3d == Viewport.MSAA_2X,
"Releasing the final owner should preserve an external antialiasing change"
)
viewport.msaa_3d = original_msaa
func _not_any_grass_particle_emitting(grass: Node3D) -> bool:
var particles: Array = grass.get("particle_nodes")
for value in particles: