extends Node3D var stage: Node3D var viewport: SubViewport var camera: Camera3D var figures: Array[Node3D] = [] var results: Array = [] func _ready() -> void: call_deferred("run") func run() -> void: Soundscape.enabled = false DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) get_window().size = Vector2i(960,540) viewport = SubViewport.new() viewport.own_world_3d = true viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS viewport.msaa_3d = Viewport.MSAA_4X add_child(viewport) stage = Node3D.new() viewport.add_child(stage) var display := TextureRect.new() display.texture = viewport.get_texture() display.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) display.expand_mode = TextureRect.EXPAND_IGNORE_SIZE add_child(display) var env := WorldEnvironment.new() env.environment=Environment.new() preload("res://scripts/presentation/lighting.gd").configure(env.environment,true) stage.add_child(env) var light := DirectionalLight3D.new() light.rotation_degrees=Vector3(-45,-30,0) light.light_energy=1.3 light.shadow_enabled=true stage.add_child(light) camera=Camera3D.new() camera.projection=Camera3D.PROJECTION_ORTHOGONAL stage.add_child(camera) for resolution: Vector2i in [Vector2i(1920,1080),Vector2i(2560,1440)]: viewport.size=resolution for count: int in [1,30,90]: for figure: Node3D in figures:figure.free() figures.clear() var columns: int = ceili(sqrt(count)) for i: int in range(count): var figure: Node3D = AssetLibrary.instantiate_fighter("w04") figure.position=Vector3((i%columns-columns*.5)*2.2,0,(i/columns-columns*.5)*2.2) stage.add_child(figure) figures.append(figure) camera.size=maxf(4,columns*2.5) camera.position=Vector3(8,18,23) camera.look_at(Vector3(0,.8,0)) var times: Array[float]=[] var started: int=Time.get_ticks_usec() var previous: int=started while Time.get_ticks_usec()-started < 8000000: var elapsed: float = (Time.get_ticks_usec()-started)/1000000.0 for i: int in range(figures.size()):figures[i].preview("walk",fmod(elapsed+i*.05,1.4)) await get_tree().process_frame var now: int=Time.get_ticks_usec() if elapsed>2:times.append((now-previous)/1000.0) previous=now var total: float=0 for t: float in times:total+=t times.sort() var record := {"resolution":str(resolution),"window_size":str(get_window().size),"render_size":str(viewport.get_texture().get_size()),"instances":count,"mean_frame_ms":total/times.size(),"p95_frame_ms":times[int(times.size()*.95)],"draw_calls":Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME),"video_memory_bytes":Performance.get_monitor(Performance.RENDER_VIDEO_MEM_USED),"fps":1000.0/(total/times.size())} results.append(record) print("RIG_BENCH: ",record) var f:=FileAccess.open("res://docs/phase11-benchmark.json",FileAccess.WRITE) f.store_string(JSON.stringify({"device":RenderingServer.get_video_adapter_name(),"renderer":RenderingServer.get_current_rendering_method(),"vsync":false,"msaa":"4x","render_target":"Fixed-size SubViewport independent of desktop DPI and window stretch","warmup_seconds":2,"sample_seconds":6,"scope":"Isolated animated characters; not a complete game benchmark; includes CPU and GPU frame pacing, not separately timed stages","results":results},"\t"));f.close() await Soundscape.quit_game()