extends SceneTree ## Photograph Sakura Crossing from a fixed set of authored viewpoints. ## ## godot --path . --windowed --resolution 1600x900 \ ## -s res://debug/sakura_detail_capture.gd -- ## ## `visual_capture.gd` shoots the real game through a real match, which is the ## right regression tool but the wrong review tool: it spawns the player at ## random, so half its frames are of a rooftop or a wall and no two runs compare. ## Reviewing DETAIL needs the opposite — the same handful of angles every time, ## chosen because each one is where a particular piece of work has to hold up. const SCENE := "res://scenes/maps/sakura_crossing/sakura_crossing.tscn" const SETTLE_FRAMES := 120 ## [name, eye, look_at, fov] const VIEWS := [ ["crossing", Vector3(0, 1.7, 20.0), Vector3(0, 2.2, -16.0), 70.0], ["shopfront", Vector3(-30.0, 1.7, -29.0), Vector3(-24.0, 3.2, -22.0), 62.0], ["shopping_street", Vector3(-4.0, 1.7, -30.0), Vector3(46.0, 4.0, -30.0), 68.0], ["station", Vector3(30.0, 2.6, 14.0), Vector3(46.0, 2.4, 9.0), 66.0], ["platform", Vector3(52.0, 2.2, 8.8), Vector3(30.0, 2.6, 8.4), 66.0], ["torii", Vector3(-22.0, 1.7, 34.0), Vector3(-22.0, 3.0, 56.0), 68.0], ["alley", Vector3(-52.0, 1.7, -11.2), Vector3(10.0, 2.6, -11.2), 70.0], ["footbridge", Vector3(-40.0, 7.6, 8.0), Vector3(30.0, 3.0, -1.0), 72.0], ["road_paint", Vector3(0.0, 1.7, 16.0), Vector3(0.0, 0.0, 6.0), 66.0], ["houses", Vector3(-8.0, 1.7, 26.0), Vector3(-24.0, 3.0, 33.0), 66.0], ["aerial", Vector3(-30.0, 150.0, 150.0), Vector3(20.0, 0.0, -10.0), 62.0], ["rail_curve", Vector3(40.0, 18.0, 30.0), Vector3(95.0, 2.0, -22.0), 66.0], ["east_district", Vector3(64.0, 1.8, 30.0), Vector3(64.0, 3.0, 78.0), 68.0], ["east_street", Vector3(20.0, 1.8, 54.0), Vector3(104.0, 4.0, 54.0), 66.0], # Looking OUT from inside the map, over the boundary, which is the only # angle that tells you whether the world continues past the wall. ["beyond_west", Vector3(-104.0, 3.0, 20.0), Vector3(-200.0, 10.0, 20.0), 70.0], ["beyond_south", Vector3(0.0, 3.0, 74.0), Vector3(0.0, 12.0, 200.0), 70.0], ["catenary", Vector3(20.0, 3.0, 12.0), Vector3(-30.0, 6.5, 0.0), 60.0], ["vehicles", Vector3(-30.0, 2.2, 27.0), Vector3(-8.0, 1.4, 22.0), 55.0], ["rail_east_wall", Vector3(96.0, 9.0, -6.0), Vector3(126.0, 2.0, -38.0), 66.0], ["north_park", Vector3(-30.0, 3.0, -78.0), Vector3(30.0, 4.0, -60.0), 70.0], ["north_park_overview", Vector3(-34.0, 32.0, -45.0), Vector3(-20.0, 0.0, -70.0), 68.0], ["pond_bridge", Vector3(-58.0, 2.5, -64.0), Vector3(-34.0, 1.0, -73.0), 66.0], ["park_road", Vector3(60.0, 6.0, -22.0), Vector3(100.0, 1.0, -60.0), 68.0], ["shrine_precinct", Vector3(-22.0, 2.0, 58.0), Vector3(-22.0, 4.0, 84.0), 70.0], ["shrine_lawn", Vector3(-70.0, 8.0, 42.0), Vector3(-25.0, 2.0, 53.0), 68.0], ["playground", Vector3(-72.0, 2.0, 36.0), Vector3(-72.0, 1.4, 52.0), 70.0], ["playground_reverse", Vector3(-92.0, 5.0, 63.0), Vector3(-72.0, 1.5, 51.0), 68.0], ["shrine_intersection", Vector3(-2.0, 2.0, 54.0), Vector3(20.0, 1.0, 54.0), 66.0], ["sidewalk_corner", Vector3(13.0, 10.0, 7.0), Vector3(5.9, 0.2, 14.1), 52.0], ["street_sign", Vector3(3.5, 1.8, -18.0), Vector3(8.15, 2.0, -21.85), 46.0], ["bikes", Vector3(20.0, 2.0, 8.0), Vector3(32.0, 1.2, 13.0), 55.0], # Grazing-angle regression views for the fullscreen depth-ink pass. A flat # ground plane must not turn into a dark wedge as the camera approaches the # horizon; these three pitches keep that failure visible and reproducible. ["ground_grazing", Vector3(0.0, 1.7, 62.0), Vector3(0.0, 1.7, -70.0), 70.0], ["ground_shallow", Vector3(0.0, 1.7, 62.0), Vector3(0.0, -5.0, -70.0), 70.0], ["ground_normal", Vector3(0.0, 1.7, 62.0), Vector3(0.0, -28.0, -70.0), 70.0], ["ground_zoomed", Vector3(0.0, 1.7, 62.0), Vector3(0.0, 1.7, -70.0), 35.0], ["ground_wide", Vector3(0.0, 1.7, 62.0), Vector3(0.0, 1.7, -70.0), 95.0], ["shopping_band", Vector3(-4.0, 1.7, -30.0), Vector3(80.0, 1.7, -30.0), 70.0], ["shopping_band_zoomed", Vector3(-4.0, 1.7, -30.0), Vector3(80.0, 1.7, -30.0), 35.0], ["shopping_band_wide", Vector3(-4.0, 1.7, -30.0), Vector3(80.0, 1.7, -30.0), 95.0], ["park_ground_grazing", Vector3(34.0, 1.7, -65.0), Vector3(90.0, 1.7, -65.0), 70.0], ] var _out_dir := "." func _initialize() -> void: var args := OS.get_cmdline_user_args() if args.size() > 0: _out_dir = args[0] if not _out_dir.is_absolute_path(): _out_dir = ProjectSettings.globalize_path(_out_dir) DirAccess.make_dir_recursive_absolute(_out_dir) _run() func _run() -> void: await process_frame var packed: PackedScene = load(SCENE) var level: Node = packed.instantiate() root.add_child(level) for _i in SETTLE_FRAMES: await process_frame var cam := Camera3D.new() cam.far = 1200.0 level.add_child(cam) cam.current = true for v in VIEWS: cam.fov = float(v[3]) cam.global_position = v[1] cam.look_at(v[2], Vector3.UP) # Three frames: one for the transform, one for the frame drawn with it, # and one because the ink pass reads a screen copy of the frame before. for _i in 3: await process_frame var img := root.get_texture().get_image() var path := "%s/%s.png" % [_out_dir, v[0]] img.save_png(path) print("sakura_detail: saved ", path) level.queue_free() for _i in 6: await process_frame quit(0)