extends SceneTree ## Top-down + angled aerial of the arena with the crowd, plus axis markers, to locate ## the ruined section and any billboards left floating over it. ## godot --script tools/preview_topdown.gd ## Output: tools/preview/top.png (ortho top-down), tools/preview/aerial.png const OUT := "res://tools/preview" func _init() -> void: _run.call_deferred() func _run() -> void: DirAccess.make_dir_recursive_absolute(OUT) var scene := (load("res://scene.tscn") as PackedScene).instantiate() root.add_child(scene) current_scene = scene # Axis markers: red pillar at +X (east), green at +Z (south), so directions read. _marker(scene, Vector3(18, 5, 0), Color(1, 0.2, 0.2)) _marker(scene, Vector3(0, 5, 18), Color(0.2, 1, 0.2)) await create_timer(0.4).timeout var crowd := scene.get_node_or_null(^"CrowdBillboards") as MultiMeshInstance3D if crowd != null and crowd.multimesh != null: print("crowd instances = ", crowd.multimesh.instance_count) var top := Camera3D.new() top.projection = Camera3D.PROJECTION_ORTHOGONAL top.size = 46.0 scene.add_child(top) top.look_at_from_position(Vector3(0, 60, 0.01), Vector3.ZERO, Vector3(0, 0, -1)) top.current = true await create_timer(0.2).timeout _shot("top.png") var air := Camera3D.new() air.fov = 60.0 scene.add_child(air) air.look_at_from_position(Vector3(0, 26, 34), Vector3(0, 3, 0), Vector3.UP) air.current = true await create_timer(0.2).timeout _shot("aerial.png") quit(0) func _marker(scene: Node, pos: Vector3, col: Color) -> void: var m := MeshInstance3D.new() var box := BoxMesh.new() box.size = Vector3(1.5, 10.0, 1.5) var mat := StandardMaterial3D.new() mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED mat.albedo_color = col box.material = mat m.mesh = box scene.add_child(m) m.global_position = pos func _shot(name: String) -> void: var img := root.get_viewport().get_texture().get_image() if img != null: img.save_png(OUT + "/" + name) print("captured ", name)