squad-proto/tools/blender/inspect_source_model.py
z.kirill 8d35f4c2ec Конвейер ассетов: манифесты, риги, каталоги, инструменты
Всё, из чего собираются спрайты, и ничего собранного. Источник истины —
assets/manifests и assets/*/catalog.yaml; PNG, .sfa и contact sheet остаются
за бортом, потому что воспроизводятся командой (docs/12-assets.md).

  assets/manifests   что и как рендерить: окружение, твари, агенты, предметы
  assets/agents      паперdoll-риг восьми направлений, каталог снаряжения
  assets/monsters    пять морфологий, каждая своим ригом (docs/14-monsters.md)
  assets/sources     исходные развёртки и импорты
  assets/art_masters мастер-развёртки, по которым сверяется стиль
  tools/             сборка ассетов, покрытие, генераторы, blender-скрипты
  generated/         заголовки с константами SF_ASSET_*: без них игра не
                     соберётся, поэтому они в репозитории, хотя и производные

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 21:06:09 +03:00

47 lines
2.1 KiB
Python

"""Print a compact inventory of a Blender-compatible source model."""
import sys
from pathlib import Path
import bpy
from mathutils import Vector
def main() -> None:
marker = sys.argv.index("--")
source = Path(sys.argv[marker + 1]).resolve()
bpy.ops.wm.read_factory_settings(use_empty=True)
suffix = source.suffix.lower()
if suffix in {".glb", ".gltf"}:
bpy.ops.import_scene.gltf(filepath=str(source))
elif suffix == ".fbx":
bpy.ops.import_scene.fbx(filepath=str(source))
elif suffix == ".obj":
bpy.ops.wm.obj_import(filepath=str(source))
else:
raise SystemExit(f"unsupported source format: {suffix}")
for obj in sorted(bpy.context.scene.objects, key=lambda value: value.name):
if obj.type == "MESH":
corners = [obj.matrix_world @ Vector(corner) for corner in obj.bound_box]
lo = tuple(round(min(point[index] for point in corners), 4) for index in range(3))
hi = tuple(round(max(point[index] for point in corners), 4) for index in range(3))
parent = obj.parent.name if obj.parent else "-"
print(f"MESH {obj.name} verts={len(obj.data.vertices)} mats={len(obj.data.materials)} parent={parent} hide={obj.hide_render} bbox={lo}..{hi}")
elif obj.type == "ARMATURE":
bones = ",".join(bone.name for bone in obj.data.bones)
print(f"ARMATURE {obj.name} bones={len(obj.data.bones)} [{bones}]")
for bone in obj.data.bones:
if bone.name in {"root","DEF-hips","DEF-spine.002","DEF-spine.003","DEF-head",
"DEF-hand.L","DEF-hand.R","DEF-upper_arm.L","DEF-upper_arm.R"}:
head=tuple(round(value,4) for value in bone.head_local)
tail=tuple(round(value,4) for value in bone.tail_local)
print(f"BONE {bone.name} {head}->{tail}")
for action in sorted(bpy.data.actions, key=lambda value: value.name):
start, end = action.frame_range
print(f"ACTION {action.name} frames={start:.0f}..{end:.0f}")
if __name__ == "__main__":
main()