Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
57 lines
2.3 KiB
Python
57 lines
2.3 KiB
Python
"""Independently read and author the same rig state in desktop Blender."""
|
|
import json
|
|
import pathlib
|
|
import sys
|
|
import bpy
|
|
|
|
|
|
def vector(values):
|
|
return [round(float(value), 5) + 0.0 for value in values]
|
|
|
|
|
|
def summary():
|
|
bpy.context.view_layer.update()
|
|
owner = bpy.data.objects["PoseConstraintArmatureObject"]
|
|
return {
|
|
"bones": [{"name": b.name, "parent": b.parent.name if b.parent else None,
|
|
"head": vector(b.head_local), "tail": vector(b.tail_local),
|
|
"matrix": [vector(row) for row in b.matrix_local], "connected": b.use_connect}
|
|
for b in sorted(owner.data.bones, key=lambda b: b.name)],
|
|
"pose": [{"name": p.name, "location": vector(p.location), "rotation": vector(p.rotation_euler),
|
|
"scale": vector(p.scale), "matrix": [vector(row) for row in p.matrix_basis]}
|
|
for p in sorted(owner.pose.bones, key=lambda p: p.name)],
|
|
}
|
|
|
|
|
|
directory = pathlib.Path(sys.argv[sys.argv.index("--") + 1])
|
|
command = json.loads((directory / "command.json").read_text())
|
|
states = {}
|
|
for blend in sorted(directory.glob("*.blend")):
|
|
bpy.ops.wm.open_mainfile(filepath=str(blend))
|
|
states[blend.stem] = summary()
|
|
bpy.ops.wm.open_mainfile(filepath=str(directory / "before.blend"))
|
|
obj = bpy.data.objects["PoseConstraintArmatureObject"]
|
|
if command["type"] == "setArmatureBones":
|
|
bpy.context.view_layer.objects.active = obj
|
|
obj.select_set(True)
|
|
bpy.ops.object.mode_set(mode="EDIT")
|
|
for bone in list(obj.data.edit_bones):
|
|
obj.data.edit_bones.remove(bone)
|
|
for item in command["bones"]:
|
|
bone = obj.data.edit_bones.new(item["name"])
|
|
bone.head, bone.tail, bone.roll = item["head"], item["tail"], item["roll"]
|
|
for item in command["bones"]:
|
|
bone = obj.data.edit_bones[item["name"]]
|
|
if item["parentName"]:
|
|
bone.parent = obj.data.edit_bones[item["parentName"]]
|
|
bone.use_connect = item["connected"]
|
|
bpy.ops.object.mode_set(mode="OBJECT")
|
|
else:
|
|
bone = obj.pose.bones[command["boneName"]]
|
|
bone.rotation_mode = "XYZ"
|
|
bone.location = command["translation"]
|
|
bone.rotation_euler = command["rotationEuler"]
|
|
bone.scale = command["scale"]
|
|
states["expected"] = summary()
|
|
(directory / "native.json").write_text(json.dumps(states, sort_keys=True, indent=2) + "\n")
|