extends SceneTree ## Reproducible native-renderer character and runtime camera review. const OUTPUT := "res://docs/baselines/" const CAPTURE_SIZE := Vector2i(1600, 900) func _initialize() -> void: call_deferred("_run") func _run() -> void: root.size = CAPTURE_SIZE if OS.get_cmdline_user_args().has("--cast"): await _capture_cast() else: await _capture_world() quit(0) func _capture_world() -> void: var main := load("res://main.tscn").instantiate() as Node3D main.get_node("SimulationManager").set("debug_logs", false) root.add_child(main) await process_frame var manager := main.get_node("SimulationManager") manager.set_process(false) var cycle := main.get_node("JajceWorld/DayNightCycle") cycle.set_process(false) cycle.call("_apply_light_rotation", 0.40) cycle.call("_apply_environment", 0.40) var demo := main.get_node("DemoController") if demo.get("debug_overlay_visible"): demo.call("toggle_debug_overlay") for child in main.get_children(): if child is CanvasLayer: child.hide() var rig := main.get_node("CameraRig") as Node3D rig.set_physics_process(false) rig.set_process_unhandled_input(false) var player := main.get_node("Player") as CharacterBody3D for _frame in 30: await process_frame player.set_physics_process(false) var camera := root.get_camera_3d() camera.reparent(main) camera.global_position = player.global_position + Vector3(7.5, 5.5, 10.5) camera.look_at(player.global_position + Vector3(0, 1.1, 0)) camera.fov = 48.0 for _frame in 90: await process_frame await _save("storybook_gameplay.png") camera.global_position = Vector3(38, 24, 44) camera.look_at(Vector3(-4, 3, 0)) camera.fov = 53.0 for _frame in 60: await process_frame await _save("storybook_valley.png") var world := main.get_node("JajceWorld") as JajceWorld var samples: Array[Dictionary] = [] for quality in [ JajceWorld.PresentationQuality.HIGH, JajceWorld.PresentationQuality.BALANCED, JajceWorld.PresentationQuality.LOW ]: world.apply_presentation_quality(quality) for _frame in 60: await process_frame var frame_times: Array[float] = [] for _frame in 120: var start := Time.get_ticks_usec() await process_frame frame_times.append(float(Time.get_ticks_usec() - start) / 1000.0) frame_times.sort() ( samples . append( { "profile": world.get_active_presentation_quality_name(), "frame_wall_p50_ms": frame_times[60], "frame_wall_p95_ms": frame_times[114], "draw_calls": Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME), "primitives": Performance.get_monitor(Performance.RENDER_TOTAL_PRIMITIVES_IN_FRAME), "objects": Performance.get_monitor(Performance.RENDER_TOTAL_OBJECTS_IN_FRAME), "active_npcs": main.get_node("ActiveNPCs").get_child_count(), } ) ) var file := FileAccess.open(OUTPUT + "storybook_render_metrics.json", FileAccess.WRITE) ( file . store_string( ( ( JSON . stringify( { "renderer": RenderingServer.get_current_rendering_driver_name(), "resolution": "1600x900", "workload": "Paused static valley; wall-frame latency includes vsync, not isolated GPU time", "samples": samples }, "\t" ) ) + "\n" ) ) ) func _capture_cast() -> void: var stage := Node3D.new() root.add_child(stage) var environment := WorldEnvironment.new() environment.environment = Environment.new() var env := environment.environment env.background_mode = Environment.BG_COLOR env.background_color = Color("d8e3d5") env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR env.ambient_light_color = Color("bbd2d3") env.ambient_light_energy = 0.65 env.tonemap_mode = Environment.TONE_MAPPER_FILMIC stage.add_child(environment) var light := DirectionalLight3D.new() light.rotation_degrees = Vector3(-42, -32, 0) light.light_color = Color("fff0cd") light.light_energy = 1.3 light.shadow_enabled = true stage.add_child(light) var floor_mesh := MeshInstance3D.new() var plane := PlaneMesh.new() plane.size = Vector2(200, 200) var material := StandardMaterial3D.new() material.albedo_color = Color("bdcbb5") material.roughness = 1.0 plane.material = material floor_mesh.mesh = plane stage.add_child(floor_mesh) for index in 4: var actor := load("res://player/PlayerVisual.tscn").instantiate() as Node3D stage.add_child(actor) actor.set_process(false) AnimalAppearance.apply_to(actor, index) actor.get_node("Sword").hide() actor.position = Vector3((float(index) - 1.5) * 2.0, 0, 0) actor.rotation_degrees.y = -12.0 + float(index) * 5.0 var camera := Camera3D.new() stage.add_child(camera) camera.position = Vector3(2.2, 3.1, 10.5) camera.look_at(Vector3(0, 1.25, 0)) camera.projection = Camera3D.PROJECTION_ORTHOGONAL camera.size = 6.2 camera.current = true for _frame in 60: await process_frame await _save("storybook_cast.png") stage.queue_free() await process_frame func _save(filename: String) -> void: await RenderingServer.frame_post_draw var capture := root.get_texture().get_image() assert(not capture.is_empty()) var error := capture.save_png(OUTPUT + filename) assert(error == OK) print("[TOOL] Saved " + OUTPUT + filename)