120 lines
3.4 KiB
GDScript
120 lines
3.4 KiB
GDScript
extends SceneTree
|
|
|
|
const SCENE_PATH := "res://main.tscn"
|
|
const DEBUG_OUTPUT_PATH := "res://docs/baselines/simulation_garden_01_debug.png"
|
|
const CINEMATIC_OUTPUT_PATH := "res://docs/baselines/simulation_garden_01_cinematic.png"
|
|
const CAPTURE_SIZE := Vector2i(1280, 720)
|
|
const WARMUP_FRAMES := 540
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
|
|
|
|
func _run() -> void:
|
|
root.size = CAPTURE_SIZE
|
|
var scene := load(SCENE_PATH) as PackedScene
|
|
if scene == null:
|
|
push_error("Could not load %s" % SCENE_PATH)
|
|
quit(1)
|
|
return
|
|
|
|
var main_scene := scene.instantiate()
|
|
var simulation_manager := main_scene.get_node("SimulationManager")
|
|
simulation_manager.debug_logs = false
|
|
|
|
root.add_child(main_scene)
|
|
await process_frame
|
|
_apply_capture_camera(main_scene)
|
|
for _frame in WARMUP_FRAMES:
|
|
await process_frame
|
|
_apply_capture_camera(main_scene)
|
|
|
|
var active_npcs := main_scene.get_node("ActiveNPCs")
|
|
var demo_controller := main_scene.get_node("DemoController")
|
|
if simulation_manager.npcs.is_empty() or active_npcs.get_child_count() == 0:
|
|
push_error("Simulation Garden capture needs active NPCs")
|
|
quit(1)
|
|
return
|
|
|
|
if demo_controller.has_method("toggle_debug_overlay"):
|
|
if not demo_controller.debug_overlay_visible:
|
|
demo_controller.toggle_debug_overlay()
|
|
|
|
var debug_analysis := _capture(DEBUG_OUTPUT_PATH)
|
|
if debug_analysis.is_empty():
|
|
quit(1)
|
|
return
|
|
|
|
if demo_controller.has_method("toggle_debug_overlay") and demo_controller.debug_overlay_visible:
|
|
demo_controller.toggle_debug_overlay()
|
|
await process_frame
|
|
for _frame in 30:
|
|
await process_frame
|
|
|
|
var cinematic_analysis := _capture(CINEMATIC_OUTPUT_PATH)
|
|
if cinematic_analysis.is_empty():
|
|
quit(1)
|
|
return
|
|
|
|
print(
|
|
"[TOOL] Saved Simulation Garden captures | debug %s | cinematic %s"
|
|
% [debug_analysis, cinematic_analysis]
|
|
)
|
|
quit(0)
|
|
|
|
|
|
func _capture(output_path: String) -> Dictionary:
|
|
var image := root.get_texture().get_image()
|
|
if image == null or image.is_empty():
|
|
push_error("Simulation Garden capture produced no image")
|
|
return {}
|
|
|
|
var analysis := _analyze_image(image)
|
|
if analysis.get("range", 0.0) < 0.05:
|
|
push_error("Simulation Garden capture is too uniform: %s" % analysis)
|
|
return {}
|
|
|
|
var error := image.save_png(output_path)
|
|
if error != OK:
|
|
push_error("Could not save %s: %s" % [output_path, error_string(error)])
|
|
return {}
|
|
|
|
return analysis
|
|
|
|
|
|
func _analyze_image(image: Image) -> Dictionary:
|
|
var min_luma := INF
|
|
var max_luma := -INF
|
|
var total_luma := 0.0
|
|
var samples := 0
|
|
var step_x = maxi(1, image.get_width() / 64)
|
|
var step_y = maxi(1, image.get_height() / 36)
|
|
|
|
for y in range(0, image.get_height(), step_y):
|
|
for x in range(0, image.get_width(), step_x):
|
|
var color := image.get_pixel(x, y)
|
|
var luma := color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722
|
|
min_luma = minf(min_luma, luma)
|
|
max_luma = maxf(max_luma, luma)
|
|
total_luma += luma
|
|
samples += 1
|
|
|
|
return {
|
|
"size": "%sx%s" % [image.get_width(), image.get_height()],
|
|
"samples": samples,
|
|
"average_luma": total_luma / samples,
|
|
"range": max_luma - min_luma,
|
|
}
|
|
|
|
|
|
func _apply_capture_camera(main_scene: Node) -> void:
|
|
var camera_rig := main_scene.get_node("CameraRig")
|
|
if camera_rig.has_method("apply_presentation_preset"):
|
|
camera_rig.pitch_degrees = -42.0
|
|
camera_rig.apply_presentation_preset(Vector3(-2.0, 1.2, -0.5), 128.0, 0.95)
|
|
camera_rig.set_physics_process(false)
|
|
|
|
var camera := main_scene.get_node("CameraRig/Camera3D") as Camera3D
|
|
camera.fov = 62.0
|