This commit is contained in:
Nicholas Butzke
2026-08-02 02:20:02 -04:00
parent 61669627db
commit 922983429e
226 changed files with 34032 additions and 18521 deletions
+66 -22
View File
@@ -2,30 +2,46 @@ extends SceneTree
## Dev tool: screenshot every animation state on the active GLB skin.
## Run:
## godot --path . --windowed --resolution 1280x720 -s res://debug/anim_capture.gd -- <out_dir> [skin_id]
## godot --path . --windowed --resolution 1280x720 -s res://debug/anim_capture.gd -- <out_dir> [skin_id] [unarmed] [tag,tag,...]
## Saves anim_<state>.png per state plus mid-action shots for reload/throw.
var _frames := 0
var _out_dir := "."
var _skin := "miku"
var _unarmed := false
var _player: Node = null
var _model: Node = null
var _cam: Camera3D = null
# [tag, state, speed, crouch, hold_frames]
# [tag, state, speed, crouch, hold_frames, strafe, forward, emote_index]
var _states := [
["idle", "idle", 0.0, false, 50],
["walk", "ground", 2.2, false, 50],
["run", "ground", 6.5, false, 50],
["sprint", "ground", 12.0, false, 50],
["crouch", "ground", 0.0, true, 50],
["crouchwalk", "ground", 2.0, true, 50],
["fall", "air", 4.0, false, 50],
["slide", "slide", 10.0, true, 50],
["dash", "dash", 14.0, false, 30],
["wallrun", "wall_run", 9.0, false, 50],
["grapple", "grapple", 10.0, false, 50],
["dance", "idle", 0.0, false, 60],
["idle", "idle", 0.0, false, 50, 0.0, 0.0, -1],
["walk", "ground", 0.975, false, 50, 0.0, 1.0, -1],
["run", "ground", 5.26148, false, 50, 0.0, 1.0, -1],
["sprint", "ground", 8.25, false, 50, 0.0, 1.0, -1],
["sprint_game_speed", "ground", 12.0, false, 50, 0.0, 1.0, -1],
["strafe_walk_back", "ground", 3.0, false, 50, 0.0, -1.0, -1],
["strafe_walk_left", "ground", 3.0, false, 50, -1.0, 0.0, -1],
["strafe_walk_right", "ground", 3.0, false, 50, 1.0, 0.0, -1],
["run_back", "ground", 8.25, false, 50, 0.0, -1.0, -1],
["run_left", "ground", 8.25, false, 50, -1.0, 0.0, -1],
["run_right", "ground", 8.25, false, 50, 1.0, 0.0, -1],
["run_left_game_speed", "ground", 11.0, false, 50, -1.0, 0.0, -1],
["run_right_game_speed", "ground", 11.0, false, 50, 1.0, 0.0, -1],
["crouch", "ground", 0.0, true, 50, 0.0, 0.0, -1],
["crouchwalk", "ground", 0.75, true, 50, 0.0, 1.0, -1],
["fall", "air", 4.0, false, 50, 0.0, 1.0, -1],
["slide", "slide", 10.0, true, 50, 0.0, 1.0, -1],
["dash", "dash", 14.0, false, 30, 0.0, 1.0, -1],
["wallrun", "wall_run", 13.0, false, 50, 0.0, 1.0, -1],
["wallcling", "wall_cling", 0.0, false, 50, 0.0, 0.0, -1],
["wallclimb", "wall_climb", 2.0, false, 50, 0.0, 1.0, -1],
["grapple", "grapple", 10.0, false, 50, 0.0, 1.0, -1],
["emote_dance", "idle", 0.0, false, 60, 0.0, 0.0, 0],
["emote_stretch", "idle", 0.0, false, 60, 0.0, 0.0, 1],
["emote_call", "idle", 0.0, false, 60, 0.0, 0.0, 2],
["emote_yes", "idle", 0.0, false, 60, 0.0, 0.0, 3],
["emote_no", "idle", 0.0, false, 60, 0.0, 0.0, 4],
]
var _phase := 0 # index into _states, then actions after
var _phase_frame := 0
@@ -40,6 +56,20 @@ func _initialize() -> void:
_out_dir = args[0]
if args.size() > 1:
_skin = args[1]
if args.size() > 2:
_unarmed = args[2].to_lower() == "unarmed"
if args.size() > 3 and args[3] != "":
var wanted := args[3].split(",", false)
_states = _states.filter(func(state: Array) -> bool:
return String(state[0]) in wanted)
if not _out_dir.is_absolute_path():
_out_dir = ProjectSettings.globalize_path(_out_dir)
var mkdir_error := DirAccess.make_dir_recursive_absolute(_out_dir)
if mkdir_error != OK:
printerr("anim_capture: could not create '%s' (error %d)" % [
_out_dir, mkdir_error])
quit(mkdir_error)
return
change_scene_to_file("res://ui/main_menu/main_menu.tscn")
@@ -75,9 +105,10 @@ func _process(_delta: float) -> bool:
_player.global_position = Vector3(0, 1.2, 14)
_player.rotation = Vector3.ZERO
_model.set_owner_visible(true)
# Give the model a weapon so armed poses read.
# Optional unarmed pass exposes the authored arm silhouettes used by
# idle/dance/emotes instead of covering them with weapon IK.
if _model.has_method("set_weapon"):
_model.set_weapon("res://weapons/ak47.gd")
_model.set_weapon("" if _unarmed else "res://weapons/ak47.gd")
# Camera: repositioned per shot (front + side). Model faces -Z.
_cam = Camera3D.new()
_cam.cull_mask &= ~(1 << 19) # don't render the FP viewmodel layer
@@ -91,8 +122,14 @@ func _process(_delta: float) -> bool:
# hop needs a real rendered frame in between).
if _mode == "states":
var s: Array = _states[_phase]
if s[0] == "dance" and _model.has_method("set_dancing"):
_model.set_dancing(true)
if _model.has_method("set_locomotion"):
_model.set_locomotion(float(s[5]), float(s[6]), 0.0)
if s[0] == "wallrun" and _model.has_method("set_wall_side"):
_model.set_wall_side(-1.0)
if _model.has_method("set_wall_run_motion"):
_model.set_wall_run_motion(Vector3(13.0, 0.0, 0.0))
if int(s[7]) >= 0 and _model.has_method("set_dancing"):
_model.set_dancing(true, int(s[7]))
_model.update_state(s[1], s[2], s[3])
_phase_frame += 1
var hold: int = int(s[4])
@@ -102,7 +139,7 @@ func _process(_delta: float) -> bool:
elif _phase_frame >= hold:
_snap("anim_" + String(s[0]) + "_s")
_cam_to(Vector3(0.4, 0.9, -2.4))
if s[0] == "dance" and _model.has_method("set_dancing"):
if int(s[7]) >= 0 and _model.has_method("set_dancing"):
_model.set_dancing(false)
if s[0] == "idle":
_debug_gun()
@@ -188,7 +225,10 @@ func _process(_delta: float) -> bool:
_model.update_state("grapple", 12.0, false)
if _model.has_method("set_grapple_target"):
# Anchor up and ahead of the player (player faces -Z world).
_model.set_grapple_target(_player.global_position + Vector3(1.5, 7.0, -7.0))
_model.set_grapple_target(
_player.global_position + Vector3(1.5, 7.0, -7.0),
Vector3(14.0, 2.0, -4.0),
)
_phase_frame += 1
if _phase_frame == 48:
_snap("anim_grapple_zip_f")
@@ -222,5 +262,9 @@ func _cam_to(offset: Vector3) -> void:
func _snap(tag: String) -> void:
var img := root.get_viewport().get_texture().get_image()
var path := _out_dir + "/" + tag + ".png"
img.save_png(path)
print("anim_capture: saved ", path)
var save_error := img.save_png(path)
if save_error == OK:
print("anim_capture: saved ", path)
else:
printerr("anim_capture: could not save '%s' (error %d)" % [
path, save_error])