File size: 2,612 Bytes
381de33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""Reimport the delivery GLB and verify skinning plus actual animated deformation."""

import argparse
import json
from pathlib import Path
import sys

import bpy
import numpy as np

p = argparse.ArgumentParser()
p.add_argument("--input", required=True)
p.add_argument("--output", required=True)
a = p.parse_args(sys.argv[sys.argv.index("--") + 1 :])
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
bpy.context.scene.render.fps = 30
bpy.ops.import_scene.gltf(filepath=str(Path(a.input).resolve()))
meshes = [
    obj
    for obj in bpy.context.scene.objects
    if obj.type == "MESH" and any(m.type == "ARMATURE" for m in obj.modifiers)
]
assert len(meshes) == 8, "Expected all eight skinned components"
rigs = [obj for obj in bpy.context.scene.objects if obj.type == "ARMATURE"]
assert len(rigs) == 1, "Expected one rig"
assert rigs[0].animation_data and rigs[0].animation_data.action, "Missing embedded animation"
assert len(rigs[0].data.bones) == 21
for obj in meshes:
    assert all(v.groups for v in obj.data.vertices), f"Unweighted vertices in {obj.name}"
    assert all(abs(sum(g.weight for g in v.groups) - 1) < 0.002 for v in obj.data.vertices)
    assert any(m.type == "ARMATURE" for m in obj.modifiers)
    assert obj.data.uv_layers, f"Missing UVs in {obj.name}"
    assert obj.data.materials, f"Missing materials in {obj.name}"
positions = []
frames = list(range(1, 181))
for frame in frames:
    bpy.context.scene.frame_set(frame)
    depsgraph = bpy.context.evaluated_depsgraph_get()
    coords = []
    for obj in meshes:
        evaluated = obj.evaluated_get(depsgraph)
        mesh = evaluated.to_mesh()
        coords.extend(tuple(evaluated.matrix_world @ v.co) for v in mesh.vertices)
        evaluated.to_mesh_clear()
    coords = np.array(coords)
    assert np.isfinite(coords).all()
    assert np.max(np.ptp(coords, axis=0)) < 1.6, "Implausible skin stretching"
    positions.append(coords)
movement = np.max(np.linalg.norm(np.stack(positions) - positions[0], axis=-1), axis=0)
assert movement.max() > 0.1, "The skin does not move with the animation"
report = {
    "verified": True,
    "frames_checked": frames,
    "mesh_objects": len(meshes),
    "bones": 21,
    "vertices": len(movement),
    "moving_vertices": int((movement > 0.005).sum()),
    "max_vertex_displacement": float(movement.max()),
    "weights_normalized": True,
    "uvs_and_materials_present": True,
    "finite_deformed_positions": True,
    "animation_name": rigs[0].animation_data.action.name,
}
Path(a.output).write_text(json.dumps(report, indent=2))
print(json.dumps(report))