Load models as-is; yaw 0 follows glTF +Z front, spec-correct test bodies
@@ -23,7 +23,7 @@ De eerste projectweergave toont de bodies. **Kies man / Kies vrouw** selecteert
23
23
24
24
- Sleep om te orbiten. **Vast renderkader tonen** toont het gele orthografische exportkader; stel per man/vrouw **Vaste renderhoogte**, **Centrum Y** (beeldcentrum) en **Pivot Y** (orbitpunt) in en sla op. Zonder handmatige pivot gebruikt de editor de rustpose-nekhoogte (of een fallback met diagnose); **Auto nek** wist een handmatige override. **Omhullende animaties** berekent eenmalig een renderhoogte en Centrum Y waarbinnen alle clips, alle frames (op project-fps) en alle 60 hoeken vallen, met 5% marge aan elke kant; de pivot blijft staan. Daarna is het kader weer vast: er is geen automatische zoom per frame, clip of laag. Equipment dat verder uitsteekt dan het lichaam vraagt handmatig extra hoogte. Body en equipment delen exact dezelfde camera. Uitvinken geeft vrije perspectief-preview met scrollzoom; die zoom verandert de export niet. Een echte 24-bits depthbuffer houdt voorste oppervlakken vooraan.
25
25
- Kies een animatieclip en gebruik **Pauze / Speel**.
26
- **Yaw − / Yaw +** volgen twaalf hoeken van 30°; **pitch -60 / -30 / 0 / 30 / 60** kiezen de hoogte. Yaw 0 kijkt naar de voorkant van de testlichamen (−Z). Vaste oriëntatie (+Y omhoog, het lichaam kijkt naar −Z, zijn rechterzijde is +X): yaw 0 = voorkant (zijn rechterhand links in beeld), 90 = linkerzijde, 180 = achterkant, 270 = rechterzijde; positieve pitch kijkt van boven. Een test met gelabelde markers bewaakt deze afspraak.
26
- **Yaw − / Yaw +** volgen twaalf hoeken van 30°; **pitch -60 / -30 / 0 / 30 / 60** kiezen de hoogte. Yaw 0 kijkt naar de voorkant van elk model. Vaste oriëntatie volgens de glTF-standaard (+Y omhoog, de voorkant kijkt naar +Z, de linkerzijde is +X); modellen en animaties worden as-is geladen, zonder automatische correctie: yaw 0 = voorkant (de rechterhand links in beeld), 90 = linkerzijde, 180 = achterkant, 270 = rechterzijde; positieve pitch kijkt van boven. Een test met gelabelde markers bewaakt deze afspraak.
27
27
- **Render alle hoeken** rendert alle animaties × alle frames op project-fps × 60 hoeken (5 pitches × 12 yaws). Na de losse maps schrijft hij per maptype een atlas plus een `.ppda`-bestand (zie *Atlassen en .ppda*). De preview wordt direct vervangen door iedere voltooide pass: highres → detail → target/diffuse → depth → normal → specular. Alle passes behouden hun aspect met gecentreerde letterboxing en nearest-neighbor weergave. Voortgang telt echte passes; **Annuleer render** behoudt geldige gedeeltelijke uitvoer. **Live 3D** keert terug naar het model; een volgende voltooide renderpass kan de preview weer vervangen.
28
28
- Stel breedte, hoogte en fps in de Bodies-weergave in. Nieuwe projecten beginnen op 4 fps; een bestaand `.ppd` houdt zijn opgeslagen fps.
29
29
- **Zoek onderbroken runs** (ook in de equipment-editor) toont geannuleerde, mislukte of afgebroken runs van dezelfde body/equipmentset met het aantal vastgelegde PNG's. **Hervat** gaat alleen verder als bronbestanden en instellingen exact gelijk zijn aan die run; anders staat erbij wat er verschilt. Na annuleren verschijnt de run direct in deze lijst. Zie *Hervatten* hieronder.
@@ -23,7 +23,7 @@ De eerste projectweergave toont de bodies. **Kies man / Kies vrouw** selecteert23
23
24
- Sleep om te orbiten. **Vast renderkader tonen** toont het gele orthografische exportkader; stel per man/vrouw **Vaste renderhoogte**, **Centrum Y** (beeldcentrum) en **Pivot Y** (orbitpunt) in en sla op. Zonder handmatige pivot gebruikt de editor de rustpose-nekhoogte (of een fallback met diagnose); **Auto nek** wist een handmatige override. **Omhullende animaties** berekent eenmalig een renderhoogte en Centrum Y waarbinnen alle clips, alle frames (op project-fps) en alle 60 hoeken vallen, met 5% marge aan elke kant; de pivot blijft staan. Daarna is het kader weer vast: er is geen automatische zoom per frame, clip of laag. Equipment dat verder uitsteekt dan het lichaam vraagt handmatig extra hoogte. Body en equipment delen exact dezelfde camera. Uitvinken geeft vrije perspectief-preview met scrollzoom; die zoom verandert de export niet. Een echte 24-bits depthbuffer houdt voorste oppervlakken vooraan.24
- Sleep om te orbiten. **Vast renderkader tonen** toont het gele orthografische exportkader; stel per man/vrouw **Vaste renderhoogte**, **Centrum Y** (beeldcentrum) en **Pivot Y** (orbitpunt) in en sla op. Zonder handmatige pivot gebruikt de editor de rustpose-nekhoogte (of een fallback met diagnose); **Auto nek** wist een handmatige override. **Omhullende animaties** berekent eenmalig een renderhoogte en Centrum Y waarbinnen alle clips, alle frames (op project-fps) en alle 60 hoeken vallen, met 5% marge aan elke kant; de pivot blijft staan. Daarna is het kader weer vast: er is geen automatische zoom per frame, clip of laag. Equipment dat verder uitsteekt dan het lichaam vraagt handmatig extra hoogte. Body en equipment delen exact dezelfde camera. Uitvinken geeft vrije perspectief-preview met scrollzoom; die zoom verandert de export niet. Een echte 24-bits depthbuffer houdt voorste oppervlakken vooraan.25
- Kies een animatieclip en gebruik **Pauze / Speel**.25
- Kies een animatieclip en gebruik **Pauze / Speel**.26
- **Yaw − / Yaw +** volgen twaalf hoeken van 30°; **pitch -60 / -30 / 0 / 30 / 60** kiezen de hoogte. Yaw 0 kijkt naar de voorkant van de testlichamen (−Z). Vaste oriëntatie (+Y omhoog, het lichaam kijkt naar −Z, zijn rechterzijde is +X): yaw 0 = voorkant (zijn rechterhand links in beeld), 90 = linkerzijde, 180 = achterkant, 270 = rechterzijde; positieve pitch kijkt van boven. Een test met gelabelde markers bewaakt deze afspraak.26
- **Yaw − / Yaw +** volgen twaalf hoeken van 30°; **pitch -60 / -30 / 0 / 30 / 60** kiezen de hoogte. Yaw 0 kijkt naar de voorkant van elk model. Vaste oriëntatie volgens de glTF-standaard (+Y omhoog, de voorkant kijkt naar +Z, de linkerzijde is +X); modellen en animaties worden as-is geladen, zonder automatische correctie: yaw 0 = voorkant (de rechterhand links in beeld), 90 = linkerzijde, 180 = achterkant, 270 = rechterzijde; positieve pitch kijkt van boven. Een test met gelabelde markers bewaakt deze afspraak.27
- **Render alle hoeken** rendert alle animaties × alle frames op project-fps × 60 hoeken (5 pitches × 12 yaws). Na de losse maps schrijft hij per maptype een atlas plus een `.ppda`-bestand (zie *Atlassen en .ppda*). De preview wordt direct vervangen door iedere voltooide pass: highres → detail → target/diffuse → depth → normal → specular. Alle passes behouden hun aspect met gecentreerde letterboxing en nearest-neighbor weergave. Voortgang telt echte passes; **Annuleer render** behoudt geldige gedeeltelijke uitvoer. **Live 3D** keert terug naar het model; een volgende voltooide renderpass kan de preview weer vervangen.27
- **Render alle hoeken** rendert alle animaties × alle frames op project-fps × 60 hoeken (5 pitches × 12 yaws). Na de losse maps schrijft hij per maptype een atlas plus een `.ppda`-bestand (zie *Atlassen en .ppda*). De preview wordt direct vervangen door iedere voltooide pass: highres → detail → target/diffuse → depth → normal → specular. Alle passes behouden hun aspect met gecentreerde letterboxing en nearest-neighbor weergave. Voortgang telt echte passes; **Annuleer render** behoudt geldige gedeeltelijke uitvoer. **Live 3D** keert terug naar het model; een volgende voltooide renderpass kan de preview weer vervangen.28
- Stel breedte, hoogte en fps in de Bodies-weergave in. Nieuwe projecten beginnen op 4 fps; een bestaand `.ppd` houdt zijn opgeslagen fps.28
- Stel breedte, hoogte en fps in de Bodies-weergave in. Nieuwe projecten beginnen op 4 fps; een bestaand `.ppd` houdt zijn opgeslagen fps.29
- **Zoek onderbroken runs** (ook in de equipment-editor) toont geannuleerde, mislukte of afgebroken runs van dezelfde body/equipmentset met het aantal vastgelegde PNG's. **Hervat** gaat alleen verder als bronbestanden en instellingen exact gelijk zijn aan die run; anders staat erbij wat er verschilt. Na annuleren verschijnt de run direct in deze lijst. Zie *Hervatten* hieronder.29
- **Zoek onderbroken runs** (ook in de equipment-editor) toont geannuleerde, mislukte of afgebroken runs van dezelfde body/equipmentset met het aantal vastgelegde PNG's. **Hervat** gaat alleen verder als bronbestanden en instellingen exact gelijk zijn aan die run; anders staat erbij wat er verschilt. Na annuleren verschijnt de run direct in deze lijst. Zie *Hervatten* hieronder.@@ -3,7 +3,8 @@
3
3
4
4
The meshes, skeleton and clips are procedural. Nothing is downloaded.
5
5
The figures are labelled test assets, not finished characters. glTF axes:
6
Y is up, the character faces -Z, bind rotations are identity.
6
Y is up, the character faces +Z (the glTF front), its left side is +X,
7
bind rotations are identity.
7
8
8
9
Run from the repository root:
9
10
@@ -82,20 +83,20 @@ def skeleton(sex: str) -> list[tuple[str, str | None, tuple[float, float, float]
82
83
("Chest", "Spine", (0.0, 0.20, 0.0), (p["chest_w"], 0.22, 0.18)),
83
84
("Neck", "Chest", (0.0, 0.16, 0.0), (0.10, 0.08, 0.10)),
84
85
("Head", "Neck", (0.0, 0.14, 0.0), (0.18, 0.22, 0.20)),
85
("LeftShoulder", "Chest", (-shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),
86
("LeftUpperArm", "LeftShoulder", (-0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),
86
("LeftShoulder", "Chest", (shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),
87
("LeftUpperArm", "LeftShoulder", (0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),
87
88
("LeftLowerArm", "LeftUpperArm", (0.0, -p["upper_arm"], 0.0), (0.07, p["lower_arm"], 0.07)),
88
89
("LeftHand", "LeftLowerArm", (0.0, -p["lower_arm"], 0.0), (0.08, 0.10, 0.04)),
89
("RightShoulder", "Chest", (shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),
90
("RightUpperArm", "RightShoulder", (0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),
90
("RightShoulder", "Chest", (-shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),
91
("RightUpperArm", "RightShoulder", (-0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),
91
92
("RightLowerArm", "RightUpperArm", (0.0, -p["upper_arm"], 0.0), (0.07, p["lower_arm"], 0.07)),
92
93
("RightHand", "RightLowerArm", (0.0, -p["lower_arm"], 0.0), (0.08, 0.10, 0.04)),
93
("LeftUpperLeg", "Hips", (-hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),
94
("LeftUpperLeg", "Hips", (hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),
94
95
("LeftLowerLeg", "LeftUpperLeg", (0.0, -p["upper_leg"], 0.0), (0.09, p["lower_leg"], 0.09)),
95
("LeftFoot", "LeftLowerLeg", (0.0, -p["lower_leg"], -0.06), (0.10, 0.06, 0.22)),
96
("RightUpperLeg", "Hips", (hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),
96
("LeftFoot", "LeftLowerLeg", (0.0, -p["lower_leg"], 0.06), (0.10, 0.06, 0.22)),
97
("RightUpperLeg", "Hips", (-hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),
97
98
("RightLowerLeg", "RightUpperLeg", (0.0, -p["upper_leg"], 0.0), (0.09, p["lower_leg"], 0.09)),
98
("RightFoot", "RightLowerLeg", (0.0, -p["lower_leg"], -0.06), (0.10, 0.06, 0.22)),
99
("RightFoot", "RightLowerLeg", (0.0, -p["lower_leg"], 0.06), (0.10, 0.06, 0.22)),
99
100
]
100
101
names = [item[0] for item in spec]
101
102
if names != JOINT_ORDER:
@@ -124,17 +125,17 @@ def walk_clips() -> dict[str, list[tuple[float, float, float, float]]]:
124
125
"RightUpperArm": [-22.0, 0.0, 22.0, 0.0, -22.0],
125
126
"Chest": [4.0, 0.0, -4.0, 0.0, 4.0],
126
127
}
127
return {name: [quat_x(angle) for angle in angles] for name, angles in curves.items()} | {
128
return {name: [quat_x(-angle) for angle in angles] for name, angles in curves.items()} | {
128
129
"_times": [(t, 0.0, 0.0, 0.0) for t in times]
129
130
}
130
131
131
132
132
133
def attack_clips() -> dict[str, list[tuple[float, float, float, float]]]:
133
# Right arm swings toward -Z (negative X rotation). Chest twists about Y.
134
arm = [quat_x(a) for a in (0.0, -20.0, -100.0, -40.0, 0.0)]
135
forearm = [quat_x(a) for a in (0.0, -10.0, -35.0, -15.0, 0.0)]
134
# Right arm swings forward toward +Z (positive X rotation). Chest twists about Y.
135
arm = [quat_x(-a) for a in (0.0, -20.0, -100.0, -40.0, 0.0)]
136
forearm = [quat_x(-a) for a in (0.0, -10.0, -35.0, -15.0, 0.0)]
136
137
chest = [quat_y(a) for a in (0.0, 6.0, 18.0, 8.0, 0.0)]
137
spine = [quat_x(a) for a in (0.0, 4.0, 12.0, 4.0, 0.0)]
138
spine = [quat_x(-a) for a in (0.0, 4.0, 12.0, 4.0, 0.0)]
138
139
return {
139
140
"RightUpperArm": arm,
140
141
"RightLowerArm": forearm,
@@ -376,7 +377,7 @@ def build_glb(sex: str) -> bytes:
376
377
"license": "CC0-1.0",
377
378
"generator": "scripts/generate_test_bodies.py",
378
379
"up": "+Y",
379
"forward": "-Z",
380
"forward": "+Z",
380
381
"note": "Procedureel testlichaam. Geen motion capture en geen definitief karakter.",
381
382
},
382
383
},
@@ -3,7 +3,8 @@3
3
4
The meshes, skeleton and clips are procedural. Nothing is downloaded.4
The meshes, skeleton and clips are procedural. Nothing is downloaded.5
The figures are labelled test assets, not finished characters. glTF axes:5
The figures are labelled test assets, not finished characters. glTF axes:6
Y is up, the character faces -Z, bind rotations are identity.6
Y is up, the character faces +Z (the glTF front), its left side is +X,7
bind rotations are identity.7
8
8
Run from the repository root:9
Run from the repository root:9
10
@@ -82,20 +83,20 @@ def skeleton(sex: str) -> list[tuple[str, str | None, tuple[float, float, float]82
("Chest", "Spine", (0.0, 0.20, 0.0), (p["chest_w"], 0.22, 0.18)),83
("Chest", "Spine", (0.0, 0.20, 0.0), (p["chest_w"], 0.22, 0.18)),83
("Neck", "Chest", (0.0, 0.16, 0.0), (0.10, 0.08, 0.10)),84
("Neck", "Chest", (0.0, 0.16, 0.0), (0.10, 0.08, 0.10)),84
("Head", "Neck", (0.0, 0.14, 0.0), (0.18, 0.22, 0.20)),85
("Head", "Neck", (0.0, 0.14, 0.0), (0.18, 0.22, 0.20)),85
("LeftShoulder", "Chest", (-shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),86
("LeftShoulder", "Chest", (shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),86
("LeftUpperArm", "LeftShoulder", (-0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),87
("LeftUpperArm", "LeftShoulder", (0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),87
("LeftLowerArm", "LeftUpperArm", (0.0, -p["upper_arm"], 0.0), (0.07, p["lower_arm"], 0.07)),88
("LeftLowerArm", "LeftUpperArm", (0.0, -p["upper_arm"], 0.0), (0.07, p["lower_arm"], 0.07)),88
("LeftHand", "LeftLowerArm", (0.0, -p["lower_arm"], 0.0), (0.08, 0.10, 0.04)),89
("LeftHand", "LeftLowerArm", (0.0, -p["lower_arm"], 0.0), (0.08, 0.10, 0.04)),89
("RightShoulder", "Chest", (shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),90
("RightShoulder", "Chest", (-shoulder, 0.08, 0.0), (0.10, 0.08, 0.08)),90
("RightUpperArm", "RightShoulder", (0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),91
("RightUpperArm", "RightShoulder", (-0.08, 0.0, 0.0), (0.08, p["upper_arm"], 0.08)),91
("RightLowerArm", "RightUpperArm", (0.0, -p["upper_arm"], 0.0), (0.07, p["lower_arm"], 0.07)),92
("RightLowerArm", "RightUpperArm", (0.0, -p["upper_arm"], 0.0), (0.07, p["lower_arm"], 0.07)),92
("RightHand", "RightLowerArm", (0.0, -p["lower_arm"], 0.0), (0.08, 0.10, 0.04)),93
("RightHand", "RightLowerArm", (0.0, -p["lower_arm"], 0.0), (0.08, 0.10, 0.04)),93
("LeftUpperLeg", "Hips", (-hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),94
("LeftUpperLeg", "Hips", (hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),94
("LeftLowerLeg", "LeftUpperLeg", (0.0, -p["upper_leg"], 0.0), (0.09, p["lower_leg"], 0.09)),95
("LeftLowerLeg", "LeftUpperLeg", (0.0, -p["upper_leg"], 0.0), (0.09, p["lower_leg"], 0.09)),95
("LeftFoot", "LeftLowerLeg", (0.0, -p["lower_leg"], -0.06), (0.10, 0.06, 0.22)),96
("LeftFoot", "LeftLowerLeg", (0.0, -p["lower_leg"], 0.06), (0.10, 0.06, 0.22)),96
("RightUpperLeg", "Hips", (hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),97
("RightUpperLeg", "Hips", (-hip, -0.06, 0.0), (0.12, p["upper_leg"], 0.12)),97
("RightLowerLeg", "RightUpperLeg", (0.0, -p["upper_leg"], 0.0), (0.09, p["lower_leg"], 0.09)),98
("RightLowerLeg", "RightUpperLeg", (0.0, -p["upper_leg"], 0.0), (0.09, p["lower_leg"], 0.09)),98
("RightFoot", "RightLowerLeg", (0.0, -p["lower_leg"], -0.06), (0.10, 0.06, 0.22)),99
("RightFoot", "RightLowerLeg", (0.0, -p["lower_leg"], 0.06), (0.10, 0.06, 0.22)),99
]100
]100
names = [item[0] for item in spec]101
names = [item[0] for item in spec]101
if names != JOINT_ORDER:102
if names != JOINT_ORDER:@@ -124,17 +125,17 @@ def walk_clips() -> dict[str, list[tuple[float, float, float, float]]]:124
"RightUpperArm": [-22.0, 0.0, 22.0, 0.0, -22.0],125
"RightUpperArm": [-22.0, 0.0, 22.0, 0.0, -22.0],125
"Chest": [4.0, 0.0, -4.0, 0.0, 4.0],126
"Chest": [4.0, 0.0, -4.0, 0.0, 4.0],126
}127
}127
return {name: [quat_x(angle) for angle in angles] for name, angles in curves.items()} | {128
return {name: [quat_x(-angle) for angle in angles] for name, angles in curves.items()} | {128
"_times": [(t, 0.0, 0.0, 0.0) for t in times]129
"_times": [(t, 0.0, 0.0, 0.0) for t in times]129
}130
}130
131
131
132
132
def attack_clips() -> dict[str, list[tuple[float, float, float, float]]]:133
def attack_clips() -> dict[str, list[tuple[float, float, float, float]]]:133
# Right arm swings toward -Z (negative X rotation). Chest twists about Y.134
# Right arm swings forward toward +Z (positive X rotation). Chest twists about Y.134
arm = [quat_x(a) for a in (0.0, -20.0, -100.0, -40.0, 0.0)]135
arm = [quat_x(-a) for a in (0.0, -20.0, -100.0, -40.0, 0.0)]135
forearm = [quat_x(a) for a in (0.0, -10.0, -35.0, -15.0, 0.0)]136
forearm = [quat_x(-a) for a in (0.0, -10.0, -35.0, -15.0, 0.0)]136
chest = [quat_y(a) for a in (0.0, 6.0, 18.0, 8.0, 0.0)]137
chest = [quat_y(a) for a in (0.0, 6.0, 18.0, 8.0, 0.0)]137
spine = [quat_x(a) for a in (0.0, 4.0, 12.0, 4.0, 0.0)]138
spine = [quat_x(-a) for a in (0.0, 4.0, 12.0, 4.0, 0.0)]138
return {139
return {139
"RightUpperArm": arm,140
"RightUpperArm": arm,140
"RightLowerArm": forearm,141
"RightLowerArm": forearm,@@ -376,7 +377,7 @@ def build_glb(sex: str) -> bytes:376
"license": "CC0-1.0",377
"license": "CC0-1.0",377
"generator": "scripts/generate_test_bodies.py",378
"generator": "scripts/generate_test_bodies.py",378
"up": "+Y",379
"up": "+Y",379
"forward": "-Z",380
"forward": "+Z",380
"note": "Procedureel testlichaam. Geen motion capture en geen definitief karakter.",381
"note": "Procedureel testlichaam. Geen motion capture en geen definitief karakter.",381
},382
},382
},383
},@@ -171,8 +171,8 @@ pub fn matrices(framing: CameraFraming, yaw: f32, pitch: f32, aspect: f32) -> (M
171
171
}
172
172
173
173
/// Labelled orientation convention (§6/§13), verified by
174
/// `orientation_convention_is_labelled`: the character faces −Z, +Y is up,
175
/// its right hand side is +X. Camera eye = `eye_offset(yaw, pitch)`.
174
/// `orientation_convention_is_labelled`: the glTF convention — the character
175
/// faces +Z, +Y is up, its left hand side is +X (−X is right). Camera eye = `eye_offset(yaw, pitch)`.
176
176
pub const ORIENTATION_VIEWS: [(f32, &str); 4] = [
177
177
(0., "voorkant"),
178
178
(90., "linkerzijde"),
@@ -564,12 +564,12 @@ pub fn arm_measure(body: &PreviewCharacter) -> Option<(f32, f32)> {
564
564
mod tests {
565
565
#[test]
566
566
fn orientation_convention_is_labelled() {
567
// Labelled markers on a body facing −Z with its right side on +X.
567
// Labelled markers on a body facing +Z (glTF front), its left side on +X.
568
568
let markers = [
569
("voorkant", [0., 1., -0.3]),
570
("achterkant", [0., 1., 0.3]),
571
("linkerzijde", [-0.3, 1., 0.]),
572
("rechterzijde", [0.3, 1., 0.]),
569
("voorkant", [0., 1., 0.3]),
570
("achterkant", [0., 1., -0.3]),
571
("linkerzijde", [0.3, 1., 0.]),
572
("rechterzijde", [-0.3, 1., 0.]),
573
573
];
574
574
let framing = crate::project::CameraFraming::default();
575
575
for (yaw, label) in ORIENTATION_VIEWS {
@@ -583,14 +583,14 @@ mod tests {
583
583
.0;
584
584
assert_eq!(nearest, label, "yaw {yaw}");
585
585
}
586
// Yaw 0 (front): the character's right (+X) is on the image's left.
586
// Yaw 0 (front): the character's right (−X) is on the image's left.
587
587
let (view, _) = matrices(framing, 0., 0., 1.);
588
588
let x = |p: [f32; 3]| view[0] * p[0] + view[4] * p[1] + view[8] * p[2] + view[12];
589
assert!(x([0.3, 1., 0.]) < 0. && x([-0.3, 1., 0.]) > 0.);
589
assert!(x([-0.3, 1., 0.]) < 0. && x([0.3, 1., 0.]) > 0.);
590
590
// Positive pitch looks down from above: the front marker sits lower.
591
591
let (view, _) = matrices(framing, 0., 60., 1.);
592
592
let y = |p: [f32; 3]| view[1] * p[0] + view[5] * p[1] + view[9] * p[2] + view[13];
593
assert!(y([0., 1., -0.3]) < y([0., 1., 0.3]));
593
assert!(y([0., 1., 0.3]) < y([0., 1., -0.3]));
594
594
}
595
595
596
596
#[test]
@@ -171,8 +171,8 @@ pub fn matrices(framing: CameraFraming, yaw: f32, pitch: f32, aspect: f32) -> (M171
}171
}172
172
173
/// Labelled orientation convention (§6/§13), verified by173
/// Labelled orientation convention (§6/§13), verified by174
/// `orientation_convention_is_labelled`: the character faces −Z, +Y is up,174
/// `orientation_convention_is_labelled`: the glTF convention — the character175
/// its right hand side is +X. Camera eye = `eye_offset(yaw, pitch)`.175
/// faces +Z, +Y is up, its left hand side is +X (−X is right). Camera eye = `eye_offset(yaw, pitch)`.176
pub const ORIENTATION_VIEWS: [(f32, &str); 4] = [176
pub const ORIENTATION_VIEWS: [(f32, &str); 4] = [177
(0., "voorkant"),177
(0., "voorkant"),178
(90., "linkerzijde"),178
(90., "linkerzijde"),@@ -564,12 +564,12 @@ pub fn arm_measure(body: &PreviewCharacter) -> Option<(f32, f32)> {564
mod tests {564
mod tests {565
#[test]565
#[test]566
fn orientation_convention_is_labelled() {566
fn orientation_convention_is_labelled() {567
// Labelled markers on a body facing −Z with its right side on +X.567
// Labelled markers on a body facing +Z (glTF front), its left side on +X.568
let markers = [568
let markers = [569
("voorkant", [0., 1., -0.3]),569
("voorkant", [0., 1., 0.3]),570
("achterkant", [0., 1., 0.3]),570
("achterkant", [0., 1., -0.3]),571
("linkerzijde", [-0.3, 1., 0.]),571
("linkerzijde", [0.3, 1., 0.]),572
("rechterzijde", [0.3, 1., 0.]),572
("rechterzijde", [-0.3, 1., 0.]),573
];573
];574
let framing = crate::project::CameraFraming::default();574
let framing = crate::project::CameraFraming::default();575
for (yaw, label) in ORIENTATION_VIEWS {575
for (yaw, label) in ORIENTATION_VIEWS {@@ -583,14 +583,14 @@ mod tests {583
.0;583
.0;584
assert_eq!(nearest, label, "yaw {yaw}");584
assert_eq!(nearest, label, "yaw {yaw}");585
}585
}586
// Yaw 0 (front): the character's right (+X) is on the image's left.586
// Yaw 0 (front): the character's right (−X) is on the image's left.587
let (view, _) = matrices(framing, 0., 0., 1.);587
let (view, _) = matrices(framing, 0., 0., 1.);588
let x = |p: [f32; 3]| view[0] * p[0] + view[4] * p[1] + view[8] * p[2] + view[12];588
let x = |p: [f32; 3]| view[0] * p[0] + view[4] * p[1] + view[8] * p[2] + view[12];589
assert!(x([0.3, 1., 0.]) < 0. && x([-0.3, 1., 0.]) > 0.);589
assert!(x([-0.3, 1., 0.]) < 0. && x([0.3, 1., 0.]) > 0.);590
// Positive pitch looks down from above: the front marker sits lower.590
// Positive pitch looks down from above: the front marker sits lower.591
let (view, _) = matrices(framing, 0., 60., 1.);591
let (view, _) = matrices(framing, 0., 60., 1.);592
let y = |p: [f32; 3]| view[1] * p[0] + view[5] * p[1] + view[9] * p[2] + view[13];592
let y = |p: [f32; 3]| view[1] * p[0] + view[5] * p[1] + view[9] * p[2] + view[13];593
assert!(y([0., 1., -0.3]) < y([0., 1., 0.3]));593
assert!(y([0., 1., 0.3]) < y([0., 1., -0.3]));594
}594
}595
595
596
#[test]596
#[test]@@ -122,7 +122,7 @@ impl SyntheticRun {
122
122
"depth_bits": self.depth_format.bits,
123
123
"normal_space": "view (+Y up), PNG rows top-down",
124
124
"camera_distance": 10,
125
"yaw_zero": "camera on -Z",
125
"yaw_zero": "camera on +Z",
126
126
"pitches": PRODUCTION_PITCHES,
127
127
"yaws": production::production_yaws(),
128
128
"yaw_step": 30,
@@ -122,7 +122,7 @@ impl SyntheticRun {122
"depth_bits": self.depth_format.bits,122
"depth_bits": self.depth_format.bits,123
"normal_space": "view (+Y up), PNG rows top-down",123
"normal_space": "view (+Y up), PNG rows top-down",124
"camera_distance": 10,124
"camera_distance": 10,125
"yaw_zero": "camera on -Z",125
"yaw_zero": "camera on +Z",126
"pitches": PRODUCTION_PITCHES,126
"pitches": PRODUCTION_PITCHES,127
"yaws": production::production_yaws(),127
"yaws": production::production_yaws(),128
"yaw_step": 30,128
"yaw_step": 30,@@ -1033,7 +1033,7 @@ mod tests {
1033
1033
"depth_encoding": "gray",
1034
1034
"depth_bits": 16,
1035
1035
"camera_distance": 10.0,
1036
"yaw_zero": "camera on -Z",
1036
"yaw_zero": "camera on +Z",
1037
1037
"normal_space": "view (+Y up), PNG rows top-down",
1038
1038
"pitches": crate::preview::PRODUCTION_PITCHES,
1039
1039
"yaws": crate::production::production_yaws(),
@@ -1033,7 +1033,7 @@ mod tests {1033
"depth_encoding": "gray",1033
"depth_encoding": "gray",1034
"depth_bits": 16,1034
"depth_bits": 16,1035
"camera_distance": 10.0,1035
"camera_distance": 10.0,1036
"yaw_zero": "camera on -Z",1036
"yaw_zero": "camera on +Z",1037
"normal_space": "view (+Y up), PNG rows top-down",1037
"normal_space": "view (+Y up), PNG rows top-down",1038
"pitches": crate::preview::PRODUCTION_PITCHES,1038
"pitches": crate::preview::PRODUCTION_PITCHES,1039
"yaws": crate::production::production_yaws(),1039
"yaws": crate::production::production_yaws(),@@ -3,7 +3,7 @@
3
3
//! This is not the paperdoll export. The export camera is orthographic and
4
4
//! still out of scope. The interactive camera can snap to the same five
5
5
//! pitches and twelve yaws. The character forward axis of the test bodies is -Z,
6
//! so yaw 0 places the camera on -Z, looking at the body.
6
//! so yaw 0 places the camera on +Z (the glTF front), looking at the body.
7
7
8
8
use std::path::Path;
9
9
@@ -1188,9 +1188,9 @@ pub fn eye_offset(yaw_deg: f32, pitch_deg: f32, distance: f32) -> [f32; 3] {
1188
1188
let yaw = yaw_deg.to_radians();
1189
1189
let pitch = pitch_deg.to_radians();
1190
1190
[
1191
-distance * pitch.cos() * yaw.sin(),
1191
distance * pitch.cos() * yaw.sin(),
1192
1192
distance * pitch.sin(),
1193
-distance * pitch.cos() * yaw.cos(),
1193
distance * pitch.cos() * yaw.cos(),
1194
1194
]
1195
1195
}
1196
1196
@@ -1927,7 +1927,10 @@ mod tests {
1927
1927
#[test]
1928
1928
fn yaw_zero_is_in_front_and_the_twelve_yaws_differ() {
1929
1929
let front = eye_offset(0.0, 0.0, 4.0);
1930
assert!(front[2] < -3.5, "yaw 0 camera belongs on -Z, got {front:?}");
1930
assert!(
1931
front[2] > 3.5,
1932
"yaw 0 camera belongs on +Z (glTF front), got {front:?}"
1933
);
1931
1934
assert!(front[0].abs() < 0.05);
1932
1935
let mut seen = Vec::new();
1933
1936
for yaw in paperdoll_yaws_deg() {
@@ -3,7 +3,7 @@3
//! This is not the paperdoll export. The export camera is orthographic and3
//! This is not the paperdoll export. The export camera is orthographic and4
//! still out of scope. The interactive camera can snap to the same five4
//! still out of scope. The interactive camera can snap to the same five5
//! pitches and twelve yaws. The character forward axis of the test bodies is -Z,5
//! pitches and twelve yaws. The character forward axis of the test bodies is -Z,6
//! so yaw 0 places the camera on -Z, looking at the body.6
//! so yaw 0 places the camera on +Z (the glTF front), looking at the body.7
7
8
use std::path::Path;8
use std::path::Path;9
9
@@ -1188,9 +1188,9 @@ pub fn eye_offset(yaw_deg: f32, pitch_deg: f32, distance: f32) -> [f32; 3] {1188
let yaw = yaw_deg.to_radians();1188
let yaw = yaw_deg.to_radians();1189
let pitch = pitch_deg.to_radians();1189
let pitch = pitch_deg.to_radians();1190
[1190
[1191
-distance * pitch.cos() * yaw.sin(),1191
distance * pitch.cos() * yaw.sin(),1192
distance * pitch.sin(),1192
distance * pitch.sin(),1193
-distance * pitch.cos() * yaw.cos(),1193
distance * pitch.cos() * yaw.cos(),1194
]1194
]1195
}1195
}1196
1196
@@ -1927,7 +1927,10 @@ mod tests {1927
#[test]1927
#[test]1928
fn yaw_zero_is_in_front_and_the_twelve_yaws_differ() {1928
fn yaw_zero_is_in_front_and_the_twelve_yaws_differ() {1929
let front = eye_offset(0.0, 0.0, 4.0);1929
let front = eye_offset(0.0, 0.0, 4.0);1930
assert!(front[2] < -3.5, "yaw 0 camera belongs on -Z, got {front:?}");1930
assert!(1931
front[2] > 3.5,1932
"yaw 0 camera belongs on +Z (glTF front), got {front:?}"1933
);1931
assert!(front[0].abs() < 0.05);1934
assert!(front[0].abs() < 0.05);1932
let mut seen = Vec::new();1935
let mut seen = Vec::new();1933
for yaw in paperdoll_yaws_deg() {1936
for yaw in paperdoll_yaws_deg() {@@ -137,7 +137,7 @@ impl Viewport {
137
137
));
138
138
});
139
139
ui.label(
140
"Sleep om te draaien, scroll om te zoomen. Yaw 0 kijkt op de voorkant (−Z). De knoppen zetten de vijf pitches en de twaalf yaws.",
140
"Sleep om te draaien, scroll om te zoomen. Yaw 0 kijkt op de voorkant (+Z, glTF-standaard). De knoppen zetten de vijf pitches en de twaalf yaws.",
141
141
);
142
142
let available = ui.available_rect_before_wrap();
143
143
let rect = egui::Rect::from_min_size(
@@ -137,7 +137,7 @@ impl Viewport {137
));137
));138
});138
});139
ui.label(139
ui.label(140
"Sleep om te draaien, scroll om te zoomen. Yaw 0 kijkt op de voorkant (−Z). De knoppen zetten de vijf pitches en de twaalf yaws.",140
"Sleep om te draaien, scroll om te zoomen. Yaw 0 kijkt op de voorkant (+Z, glTF-standaard). De knoppen zetten de vijf pitches en de twaalf yaws.",141
);141
);142
let available = ui.available_rect_before_wrap();142
let available = ui.available_rect_before_wrap();143
let rect = egui::Rect::from_min_size(143
let rect = egui::Rect::from_min_size(@@ -1474,7 +1474,7 @@ pub fn contract(mut job: RenderJob) -> Result<Contract, String> {
1474
1474
"depth_bits": job.depth_format.bits,
1475
1475
"normal_space": "view (+Y up), PNG rows top-down",
1476
1476
"camera_distance": crate::camera::CAMERA_DISTANCE,
1477
"yaw_zero": "camera on -Z",
1477
"yaw_zero": "camera on +Z",
1478
1478
"pitches": preview::PRODUCTION_PITCHES,
1479
1479
"yaws": production_yaws(),
1480
1480
"yaw_step": 30,
@@ -1474,7 +1474,7 @@ pub fn contract(mut job: RenderJob) -> Result<Contract, String> {1474
"depth_bits": job.depth_format.bits,1474
"depth_bits": job.depth_format.bits,1475
"normal_space": "view (+Y up), PNG rows top-down",1475
"normal_space": "view (+Y up), PNG rows top-down",1476
"camera_distance": crate::camera::CAMERA_DISTANCE,1476
"camera_distance": crate::camera::CAMERA_DISTANCE,1477
"yaw_zero": "camera on -Z",1477
"yaw_zero": "camera on +Z",1478
"pitches": preview::PRODUCTION_PITCHES,1478
"pitches": preview::PRODUCTION_PITCHES,1479
"yaws": production_yaws(),1479
"yaws": production_yaws(),1480
"yaw_step": 30,1480
"yaw_step": 30,@@ -185,12 +185,12 @@ mod tests {
185
185
.join("tests/fixtures/bodies/test-body-male.glb");
186
186
let mut character = load_gltf_file(&path).unwrap();
187
187
character.positions = vec![
188
[-0.5, 0.4, -0.25],
189
[0.5, 0.4, -0.25],
190
[0., 1.5, -0.25],
191
188
[-0.5, 0.4, 0.25],
192
189
[0.5, 0.4, 0.25],
193
[0., 1.5, 0.95],
190
[0., 1.5, 0.25],
191
[-0.5, 0.4, -0.25],
192
[0.5, 0.4, -0.25],
193
[0., 1.5, -0.95],
194
194
];
195
195
character.joint_nodes.clear();
196
196
character.inverse_binds.clear();
@@ -185,12 +185,12 @@ mod tests {185
.join("tests/fixtures/bodies/test-body-male.glb");185
.join("tests/fixtures/bodies/test-body-male.glb");186
let mut character = load_gltf_file(&path).unwrap();186
let mut character = load_gltf_file(&path).unwrap();187
character.positions = vec![187
character.positions = vec![188
[-0.5, 0.4, -0.25],189
[0.5, 0.4, -0.25],190
[0., 1.5, -0.25],191
[-0.5, 0.4, 0.25],188
[-0.5, 0.4, 0.25],192
[0.5, 0.4, 0.25],189
[0.5, 0.4, 0.25],193
[0., 1.5, 0.95],190
[0., 1.5, 0.25],191
[-0.5, 0.4, -0.25],192
[0.5, 0.4, -0.25],193
[0., 1.5, -0.95],194
];194
];195
character.joint_nodes.clear();195
character.joint_nodes.clear();196
character.inverse_binds.clear();196
character.inverse_binds.clear();@@ -12,7 +12,7 @@ Beide hebben een skin met 19 joints en twee clips:
12
12
- `walk` — loopcyclus van 1 seconde, armen tegengesteld aan de benen, eerste en laatste sample gelijk
13
13
- `attack` — zwaai van de rechterarm naar voren, 0,8 seconde, eindigt weer in de bindpose
14
14
15
De bindpose heeft identiteitsrotaties. glTF-assen: +Y is omhoog, het gezicht wijst naar -Z. Elke vertex hoort met gewicht 1 bij één joint. De inverse-bindmatrix is de inverse translatie van de wereldpositie in die bindpose.
15
De bindpose heeft identiteitsrotaties. glTF-assen: +Y is omhoog, het gezicht wijst naar +Z (glTF-standaard), de linkerzijde ligt op +X. Elke vertex hoort met gewicht 1 bij één joint. De inverse-bindmatrix is de inverse translatie van de wereldpositie in die bindpose.
16
16
17
17
Opnieuw genereren, vanaf de repositoryroot:
18
18
@@ -12,7 +12,7 @@ Beide hebben een skin met 19 joints en twee clips:12
- `walk` — loopcyclus van 1 seconde, armen tegengesteld aan de benen, eerste en laatste sample gelijk12
- `walk` — loopcyclus van 1 seconde, armen tegengesteld aan de benen, eerste en laatste sample gelijk13
- `attack` — zwaai van de rechterarm naar voren, 0,8 seconde, eindigt weer in de bindpose13
- `attack` — zwaai van de rechterarm naar voren, 0,8 seconde, eindigt weer in de bindpose14
14
15
De bindpose heeft identiteitsrotaties. glTF-assen: +Y is omhoog, het gezicht wijst naar -Z. Elke vertex hoort met gewicht 1 bij één joint. De inverse-bindmatrix is de inverse translatie van de wereldpositie in die bindpose.15
De bindpose heeft identiteitsrotaties. glTF-assen: +Y is omhoog, het gezicht wijst naar +Z (glTF-standaard), de linkerzijde ligt op +X. Elke vertex hoort met gewicht 1 bij één joint. De inverse-bindmatrix is de inverse translatie van de wereldpositie in die bindpose.16
16
17
Opnieuw genereren, vanaf de repositoryroot:17
Opnieuw genereren, vanaf de repositoryroot:18
18
The contents of this binary file are not shown.
@@ -103,86 +103,6 @@ vn 0.000000 1.000000 0.000000
103
103
vn 0.000000 1.000000 0.000000
104
104
vn 0.000000 -1.000000 0.000000
105
105
vn 0.000000 -1.000000 0.000000
106
v -0.250000 1.340000 -0.040000
107
v -0.150000 1.340000 -0.040000
108
v -0.150000 1.420000 -0.040000
109
v -0.250000 1.420000 -0.040000
110
v -0.250000 1.340000 0.040000
111
v -0.150000 1.340000 0.040000
112
v -0.150000 1.420000 0.040000
113
v -0.250000 1.420000 0.040000
114
vn 0.000000 0.000000 -1.000000
115
vn 0.000000 0.000000 -1.000000
116
vn 0.000000 0.000000 1.000000
117
vn 0.000000 -0.000000 1.000000
118
vn -1.000000 0.000000 0.000000
119
vn -1.000000 0.000000 0.000000
120
vn 1.000000 0.000000 0.000000
121
vn 1.000000 0.000000 0.000000
122
vn 0.000000 1.000000 0.000000
123
vn 0.000000 1.000000 0.000000
124
vn 0.000000 -1.000000 0.000000
125
vn 0.000000 -1.000000 0.000000
126
v -0.320000 1.240000 -0.040000
127
v -0.240000 1.240000 -0.040000
128
v -0.240000 1.520000 -0.040000
129
v -0.320000 1.520000 -0.040000
130
v -0.320000 1.240000 0.040000
131
v -0.240000 1.240000 0.040000
132
v -0.240000 1.520000 0.040000
133
v -0.320000 1.520000 0.040000
134
vn 0.000000 0.000000 -1.000000
135
vn 0.000000 0.000000 -1.000000
136
vn 0.000000 0.000000 1.000000
137
vn 0.000000 -0.000000 1.000000
138
vn -1.000000 0.000000 0.000000
139
vn -1.000000 0.000000 0.000000
140
vn 1.000000 0.000000 0.000000
141
vn 1.000000 0.000000 0.000000
142
vn 0.000000 1.000000 0.000000
143
vn 0.000000 1.000000 0.000000
144
vn 0.000000 -1.000000 0.000000
145
vn 0.000000 -1.000000 0.000000
146
v -0.315000 0.970000 -0.035000
147
v -0.245000 0.970000 -0.035000
148
v -0.245000 1.230000 -0.035000
149
v -0.315000 1.230000 -0.035000
150
v -0.315000 0.970000 0.035000
151
v -0.245000 0.970000 0.035000
152
v -0.245000 1.230000 0.035000
153
v -0.315000 1.230000 0.035000
154
vn 0.000000 0.000000 -1.000000
155
vn 0.000000 0.000000 -1.000000
156
vn 0.000000 0.000000 1.000000
157
vn 0.000000 -0.000000 1.000000
158
vn -1.000000 0.000000 0.000000
159
vn -1.000000 0.000000 0.000000
160
vn 1.000000 0.000000 0.000000
161
vn 1.000000 0.000000 0.000000
162
vn 0.000000 1.000000 0.000000
163
vn 0.000000 1.000000 0.000000
164
vn 0.000000 -1.000000 0.000000
165
vn 0.000000 -1.000000 0.000000
166
v -0.320000 0.790000 -0.020000
167
v -0.240000 0.790000 -0.020000
168
v -0.240000 0.890000 -0.020000
169
v -0.320000 0.890000 -0.020000
170
v -0.320000 0.790000 0.020000
171
v -0.240000 0.790000 0.020000
172
v -0.240000 0.890000 0.020000
173
v -0.320000 0.890000 0.020000
174
vn 0.000000 0.000000 -1.000000
175
vn 0.000000 0.000000 -1.000000
176
vn 0.000000 0.000000 1.000000
177
vn 0.000000 -0.000000 1.000000
178
vn -1.000000 0.000000 0.000000
179
vn -1.000000 0.000000 0.000000
180
vn 1.000000 0.000000 0.000000
181
vn 1.000000 0.000000 0.000000
182
vn 0.000000 1.000000 0.000000
183
vn 0.000000 1.000000 0.000000
184
vn 0.000000 -1.000000 0.000000
185
vn 0.000000 -1.000000 0.000000
186
106
v 0.150000 1.340000 -0.040000
187
107
v 0.250000 1.340000 -0.040000
188
108
v 0.250000 1.420000 -0.040000
@@ -263,14 +183,14 @@ vn 0.000000 1.000000 0.000000
263
183
vn 0.000000 1.000000 0.000000
264
184
vn 0.000000 -1.000000 0.000000
265
185
vn 0.000000 -1.000000 0.000000
266
v -0.160000 0.690000 -0.060000
267
v -0.040000 0.690000 -0.060000
268
v -0.040000 1.110000 -0.060000
269
v -0.160000 1.110000 -0.060000
270
v -0.160000 0.690000 0.060000
271
v -0.040000 0.690000 0.060000
272
v -0.040000 1.110000 0.060000
273
v -0.160000 1.110000 0.060000
186
v -0.250000 1.340000 -0.040000
187
v -0.150000 1.340000 -0.040000
188
v -0.150000 1.420000 -0.040000
189
v -0.250000 1.420000 -0.040000
190
v -0.250000 1.340000 0.040000
191
v -0.150000 1.340000 0.040000
192
v -0.150000 1.420000 0.040000
193
v -0.250000 1.420000 0.040000
274
194
vn 0.000000 0.000000 -1.000000
275
195
vn 0.000000 0.000000 -1.000000
276
196
vn 0.000000 0.000000 1.000000
@@ -283,14 +203,34 @@ vn 0.000000 1.000000 0.000000
283
203
vn 0.000000 1.000000 0.000000
284
204
vn 0.000000 -1.000000 0.000000
285
205
vn 0.000000 -1.000000 0.000000
286
v -0.145000 0.280000 -0.045000
287
v -0.055000 0.280000 -0.045000
288
v -0.055000 0.680000 -0.045000
289
v -0.145000 0.680000 -0.045000
290
v -0.145000 0.280000 0.045000
291
v -0.055000 0.280000 0.045000
292
v -0.055000 0.680000 0.045000
293
v -0.145000 0.680000 0.045000
206
v -0.320000 1.240000 -0.040000
207
v -0.240000 1.240000 -0.040000
208
v -0.240000 1.520000 -0.040000
209
v -0.320000 1.520000 -0.040000
210
v -0.320000 1.240000 0.040000
211
v -0.240000 1.240000 0.040000
212
v -0.240000 1.520000 0.040000
213
v -0.320000 1.520000 0.040000
214
vn 0.000000 0.000000 -1.000000
215
vn 0.000000 0.000000 -1.000000
216
vn 0.000000 0.000000 1.000000
217
vn 0.000000 -0.000000 1.000000
218
vn -1.000000 0.000000 0.000000
219
vn -1.000000 0.000000 0.000000
220
vn 1.000000 0.000000 0.000000
221
vn 1.000000 0.000000 0.000000
222
vn 0.000000 1.000000 0.000000
223
vn 0.000000 1.000000 0.000000
224
vn 0.000000 -1.000000 0.000000
225
vn 0.000000 -1.000000 0.000000
226
v -0.315000 0.970000 -0.035000
227
v -0.245000 0.970000 -0.035000
228
v -0.245000 1.230000 -0.035000
229
v -0.315000 1.230000 -0.035000
230
v -0.315000 0.970000 0.035000
231
v -0.245000 0.970000 0.035000
232
v -0.245000 1.230000 0.035000
233
v -0.315000 1.230000 0.035000
294
234
vn 0.000000 0.000000 -1.000000
295
235
vn 0.000000 0.000000 -1.000000
296
236
vn 0.000000 0.000000 1.000000
@@ -303,14 +243,14 @@ vn 0.000000 1.000000 0.000000
303
243
vn 0.000000 1.000000 0.000000
304
244
vn 0.000000 -1.000000 0.000000
305
245
vn 0.000000 -1.000000 0.000000
306
v -0.150000 0.050000 -0.170000
307
v -0.050000 0.050000 -0.170000
308
v -0.050000 0.110000 -0.170000
309
v -0.150000 0.110000 -0.170000
310
v -0.150000 0.050000 0.050000
311
v -0.050000 0.050000 0.050000
312
v -0.050000 0.110000 0.050000
313
v -0.150000 0.110000 0.050000
246
v -0.320000 0.790000 -0.020000
247
v -0.240000 0.790000 -0.020000
248
v -0.240000 0.890000 -0.020000
249
v -0.320000 0.890000 -0.020000
250
v -0.320000 0.790000 0.020000
251
v -0.240000 0.790000 0.020000
252
v -0.240000 0.890000 0.020000
253
v -0.320000 0.890000 0.020000
314
254
vn 0.000000 0.000000 -1.000000
315
255
vn 0.000000 0.000000 -1.000000
316
256
vn 0.000000 0.000000 1.000000
@@ -363,14 +303,74 @@ vn 0.000000 1.000000 0.000000
363
303
vn 0.000000 1.000000 0.000000
364
304
vn 0.000000 -1.000000 0.000000
365
305
vn 0.000000 -1.000000 0.000000
366
v 0.050000 0.050000 -0.170000
367
v 0.150000 0.050000 -0.170000
368
v 0.150000 0.110000 -0.170000
369
v 0.050000 0.110000 -0.170000
370
v 0.050000 0.050000 0.050000
371
v 0.150000 0.050000 0.050000
372
v 0.150000 0.110000 0.050000
373
v 0.050000 0.110000 0.050000
306
v 0.050000 0.050000 -0.050000
307
v 0.150000 0.050000 -0.050000
308
v 0.150000 0.110000 -0.050000
309
v 0.050000 0.110000 -0.050000
310
v 0.050000 0.050000 0.170000
311
v 0.150000 0.050000 0.170000
312
v 0.150000 0.110000 0.170000
313
v 0.050000 0.110000 0.170000
314
vn 0.000000 0.000000 -1.000000
315
vn 0.000000 0.000000 -1.000000
316
vn 0.000000 0.000000 1.000000
317
vn 0.000000 -0.000000 1.000000
318
vn -1.000000 0.000000 0.000000
319
vn -1.000000 0.000000 0.000000
320
vn 1.000000 0.000000 0.000000
321
vn 1.000000 0.000000 0.000000
322
vn 0.000000 1.000000 0.000000
323
vn 0.000000 1.000000 0.000000
324
vn 0.000000 -1.000000 0.000000
325
vn 0.000000 -1.000000 0.000000
326
v -0.160000 0.690000 -0.060000
327
v -0.040000 0.690000 -0.060000
328
v -0.040000 1.110000 -0.060000
329
v -0.160000 1.110000 -0.060000
330
v -0.160000 0.690000 0.060000
331
v -0.040000 0.690000 0.060000
332
v -0.040000 1.110000 0.060000
333
v -0.160000 1.110000 0.060000
334
vn 0.000000 0.000000 -1.000000
335
vn 0.000000 0.000000 -1.000000
336
vn 0.000000 0.000000 1.000000
337
vn 0.000000 -0.000000 1.000000
338
vn -1.000000 0.000000 0.000000
339
vn -1.000000 0.000000 0.000000
340
vn 1.000000 0.000000 0.000000
341
vn 1.000000 0.000000 0.000000
342
vn 0.000000 1.000000 0.000000
343
vn 0.000000 1.000000 0.000000
344
vn 0.000000 -1.000000 0.000000
345
vn 0.000000 -1.000000 0.000000
346
v -0.145000 0.280000 -0.045000
347
v -0.055000 0.280000 -0.045000
348
v -0.055000 0.680000 -0.045000
349
v -0.145000 0.680000 -0.045000
350
v -0.145000 0.280000 0.045000
351
v -0.055000 0.280000 0.045000
352
v -0.055000 0.680000 0.045000
353
v -0.145000 0.680000 0.045000
354
vn 0.000000 0.000000 -1.000000
355
vn 0.000000 0.000000 -1.000000
356
vn 0.000000 0.000000 1.000000
357
vn 0.000000 -0.000000 1.000000
358
vn -1.000000 0.000000 0.000000
359
vn -1.000000 0.000000 0.000000
360
vn 1.000000 0.000000 0.000000
361
vn 1.000000 0.000000 0.000000
362
vn 0.000000 1.000000 0.000000
363
vn 0.000000 1.000000 0.000000
364
vn 0.000000 -1.000000 0.000000
365
vn 0.000000 -1.000000 0.000000
366
v -0.150000 0.050000 -0.050000
367
v -0.050000 0.050000 -0.050000
368
v -0.050000 0.110000 -0.050000
369
v -0.150000 0.110000 -0.050000
370
v -0.150000 0.050000 0.170000
371
v -0.050000 0.050000 0.170000
372
v -0.050000 0.110000 0.170000
373
v -0.150000 0.110000 0.170000
374
374
vn 0.000000 0.000000 -1.000000
375
375
vn 0.000000 0.000000 -1.000000
376
376
vn 0.000000 0.000000 1.000000
@@ -103,86 +103,6 @@ vn 0.000000 1.000000 0.000000103
vn 0.000000 1.000000 0.000000103
vn 0.000000 1.000000 0.000000104
vn 0.000000 -1.000000 0.000000104
vn 0.000000 -1.000000 0.000000105
vn 0.000000 -1.000000 0.000000105
vn 0.000000 -1.000000 0.000000106
v -0.250000 1.340000 -0.040000107
v -0.150000 1.340000 -0.040000108
v -0.150000 1.420000 -0.040000109
v -0.250000 1.420000 -0.040000110
v -0.250000 1.340000 0.040000111
v -0.150000 1.340000 0.040000112
v -0.150000 1.420000 0.040000113
v -0.250000 1.420000 0.040000114
vn 0.000000 0.000000 -1.000000115
vn 0.000000 0.000000 -1.000000116
vn 0.000000 0.000000 1.000000117
vn 0.000000 -0.000000 1.000000118
vn -1.000000 0.000000 0.000000119
vn -1.000000 0.000000 0.000000120
vn 1.000000 0.000000 0.000000121
vn 1.000000 0.000000 0.000000122
vn 0.000000 1.000000 0.000000123
vn 0.000000 1.000000 0.000000124
vn 0.000000 -1.000000 0.000000125
vn 0.000000 -1.000000 0.000000126
v -0.320000 1.240000 -0.040000127
v -0.240000 1.240000 -0.040000128
v -0.240000 1.520000 -0.040000129
v -0.320000 1.520000 -0.040000130
v -0.320000 1.240000 0.040000131
v -0.240000 1.240000 0.040000132
v -0.240000 1.520000 0.040000133
v -0.320000 1.520000 0.040000134
vn 0.000000 0.000000 -1.000000135
vn 0.000000 0.000000 -1.000000136
vn 0.000000 0.000000 1.000000137
vn 0.000000 -0.000000 1.000000138
vn -1.000000 0.000000 0.000000139
vn -1.000000 0.000000 0.000000140
vn 1.000000 0.000000 0.000000141
vn 1.000000 0.000000 0.000000142
vn 0.000000 1.000000 0.000000143
vn 0.000000 1.000000 0.000000144
vn 0.000000 -1.000000 0.000000145
vn 0.000000 -1.000000 0.000000146
v -0.315000 0.970000 -0.035000147
v -0.245000 0.970000 -0.035000148
v -0.245000 1.230000 -0.035000149
v -0.315000 1.230000 -0.035000150
v -0.315000 0.970000 0.035000151
v -0.245000 0.970000 0.035000152
v -0.245000 1.230000 0.035000153
v -0.315000 1.230000 0.035000154
vn 0.000000 0.000000 -1.000000155
vn 0.000000 0.000000 -1.000000156
vn 0.000000 0.000000 1.000000157
vn 0.000000 -0.000000 1.000000158
vn -1.000000 0.000000 0.000000159
vn -1.000000 0.000000 0.000000160
vn 1.000000 0.000000 0.000000161
vn 1.000000 0.000000 0.000000162
vn 0.000000 1.000000 0.000000163
vn 0.000000 1.000000 0.000000164
vn 0.000000 -1.000000 0.000000165
vn 0.000000 -1.000000 0.000000166
v -0.320000 0.790000 -0.020000167
v -0.240000 0.790000 -0.020000168
v -0.240000 0.890000 -0.020000169
v -0.320000 0.890000 -0.020000170
v -0.320000 0.790000 0.020000171
v -0.240000 0.790000 0.020000172
v -0.240000 0.890000 0.020000173
v -0.320000 0.890000 0.020000174
vn 0.000000 0.000000 -1.000000175
vn 0.000000 0.000000 -1.000000176
vn 0.000000 0.000000 1.000000177
vn 0.000000 -0.000000 1.000000178
vn -1.000000 0.000000 0.000000179
vn -1.000000 0.000000 0.000000180
vn 1.000000 0.000000 0.000000181
vn 1.000000 0.000000 0.000000182
vn 0.000000 1.000000 0.000000183
vn 0.000000 1.000000 0.000000184
vn 0.000000 -1.000000 0.000000185
vn 0.000000 -1.000000 0.000000186
v 0.150000 1.340000 -0.040000106
v 0.150000 1.340000 -0.040000187
v 0.250000 1.340000 -0.040000107
v 0.250000 1.340000 -0.040000188
v 0.250000 1.420000 -0.040000108
v 0.250000 1.420000 -0.040000@@ -263,14 +183,14 @@ vn 0.000000 1.000000 0.000000263
vn 0.000000 1.000000 0.000000183
vn 0.000000 1.000000 0.000000264
vn 0.000000 -1.000000 0.000000184
vn 0.000000 -1.000000 0.000000265
vn 0.000000 -1.000000 0.000000185
vn 0.000000 -1.000000 0.000000266
v -0.160000 0.690000 -0.060000186
v -0.250000 1.340000 -0.040000267
v -0.040000 0.690000 -0.060000187
v -0.150000 1.340000 -0.040000268
v -0.040000 1.110000 -0.060000188
v -0.150000 1.420000 -0.040000269
v -0.160000 1.110000 -0.060000189
v -0.250000 1.420000 -0.040000270
v -0.160000 0.690000 0.060000190
v -0.250000 1.340000 0.040000271
v -0.040000 0.690000 0.060000191
v -0.150000 1.340000 0.040000272
v -0.040000 1.110000 0.060000192
v -0.150000 1.420000 0.040000273
v -0.160000 1.110000 0.060000193
v -0.250000 1.420000 0.040000274
vn 0.000000 0.000000 -1.000000194
vn 0.000000 0.000000 -1.000000275
vn 0.000000 0.000000 -1.000000195
vn 0.000000 0.000000 -1.000000276
vn 0.000000 0.000000 1.000000196
vn 0.000000 0.000000 1.000000@@ -283,14 +203,34 @@ vn 0.000000 1.000000 0.000000283
vn 0.000000 1.000000 0.000000203
vn 0.000000 1.000000 0.000000284
vn 0.000000 -1.000000 0.000000204
vn 0.000000 -1.000000 0.000000285
vn 0.000000 -1.000000 0.000000205
vn 0.000000 -1.000000 0.000000286
v -0.145000 0.280000 -0.045000206
v -0.320000 1.240000 -0.040000287
v -0.055000 0.280000 -0.045000207
v -0.240000 1.240000 -0.040000288
v -0.055000 0.680000 -0.045000208
v -0.240000 1.520000 -0.040000289
v -0.145000 0.680000 -0.045000209
v -0.320000 1.520000 -0.040000290
v -0.145000 0.280000 0.045000210
v -0.320000 1.240000 0.040000291
v -0.055000 0.280000 0.045000211
v -0.240000 1.240000 0.040000292
v -0.055000 0.680000 0.045000212
v -0.240000 1.520000 0.040000293
v -0.145000 0.680000 0.045000213
v -0.320000 1.520000 0.040000214
vn 0.000000 0.000000 -1.000000215
vn 0.000000 0.000000 -1.000000216
vn 0.000000 0.000000 1.000000217
vn 0.000000 -0.000000 1.000000218
vn -1.000000 0.000000 0.000000219
vn -1.000000 0.000000 0.000000220
vn 1.000000 0.000000 0.000000221
vn 1.000000 0.000000 0.000000222
vn 0.000000 1.000000 0.000000223
vn 0.000000 1.000000 0.000000224
vn 0.000000 -1.000000 0.000000225
vn 0.000000 -1.000000 0.000000226
v -0.315000 0.970000 -0.035000227
v -0.245000 0.970000 -0.035000228
v -0.245000 1.230000 -0.035000229
v -0.315000 1.230000 -0.035000230
v -0.315000 0.970000 0.035000231
v -0.245000 0.970000 0.035000232
v -0.245000 1.230000 0.035000233
v -0.315000 1.230000 0.035000294
vn 0.000000 0.000000 -1.000000234
vn 0.000000 0.000000 -1.000000295
vn 0.000000 0.000000 -1.000000235
vn 0.000000 0.000000 -1.000000296
vn 0.000000 0.000000 1.000000236
vn 0.000000 0.000000 1.000000@@ -303,14 +243,14 @@ vn 0.000000 1.000000 0.000000303
vn 0.000000 1.000000 0.000000243
vn 0.000000 1.000000 0.000000304
vn 0.000000 -1.000000 0.000000244
vn 0.000000 -1.000000 0.000000305
vn 0.000000 -1.000000 0.000000245
vn 0.000000 -1.000000 0.000000306
v -0.150000 0.050000 -0.170000246
v -0.320000 0.790000 -0.020000307
v -0.050000 0.050000 -0.170000247
v -0.240000 0.790000 -0.020000308
v -0.050000 0.110000 -0.170000248
v -0.240000 0.890000 -0.020000309
v -0.150000 0.110000 -0.170000249
v -0.320000 0.890000 -0.020000310
v -0.150000 0.050000 0.050000250
v -0.320000 0.790000 0.020000311
v -0.050000 0.050000 0.050000251
v -0.240000 0.790000 0.020000312
v -0.050000 0.110000 0.050000252
v -0.240000 0.890000 0.020000313
v -0.150000 0.110000 0.050000253
v -0.320000 0.890000 0.020000314
vn 0.000000 0.000000 -1.000000254
vn 0.000000 0.000000 -1.000000315
vn 0.000000 0.000000 -1.000000255
vn 0.000000 0.000000 -1.000000316
vn 0.000000 0.000000 1.000000256
vn 0.000000 0.000000 1.000000@@ -363,14 +303,74 @@ vn 0.000000 1.000000 0.000000363
vn 0.000000 1.000000 0.000000303
vn 0.000000 1.000000 0.000000364
vn 0.000000 -1.000000 0.000000304
vn 0.000000 -1.000000 0.000000365
vn 0.000000 -1.000000 0.000000305
vn 0.000000 -1.000000 0.000000366
v 0.050000 0.050000 -0.170000306
v 0.050000 0.050000 -0.050000367
v 0.150000 0.050000 -0.170000307
v 0.150000 0.050000 -0.050000368
v 0.150000 0.110000 -0.170000308
v 0.150000 0.110000 -0.050000369
v 0.050000 0.110000 -0.170000309
v 0.050000 0.110000 -0.050000370
v 0.050000 0.050000 0.050000310
v 0.050000 0.050000 0.170000371
v 0.150000 0.050000 0.050000311
v 0.150000 0.050000 0.170000372
v 0.150000 0.110000 0.050000312
v 0.150000 0.110000 0.170000373
v 0.050000 0.110000 0.050000313
v 0.050000 0.110000 0.170000314
vn 0.000000 0.000000 -1.000000315
vn 0.000000 0.000000 -1.000000316
vn 0.000000 0.000000 1.000000317
vn 0.000000 -0.000000 1.000000318
vn -1.000000 0.000000 0.000000319
vn -1.000000 0.000000 0.000000320
vn 1.000000 0.000000 0.000000321
vn 1.000000 0.000000 0.000000322
vn 0.000000 1.000000 0.000000323
vn 0.000000 1.000000 0.000000324
vn 0.000000 -1.000000 0.000000325
vn 0.000000 -1.000000 0.000000326
v -0.160000 0.690000 -0.060000327
v -0.040000 0.690000 -0.060000328
v -0.040000 1.110000 -0.060000329
v -0.160000 1.110000 -0.060000330
v -0.160000 0.690000 0.060000331
v -0.040000 0.690000 0.060000332
v -0.040000 1.110000 0.060000333
v -0.160000 1.110000 0.060000334
vn 0.000000 0.000000 -1.000000335
vn 0.000000 0.000000 -1.000000336
vn 0.000000 0.000000 1.000000337
vn 0.000000 -0.000000 1.000000338
vn -1.000000 0.000000 0.000000339
vn -1.000000 0.000000 0.000000340
vn 1.000000 0.000000 0.000000341
vn 1.000000 0.000000 0.000000342
vn 0.000000 1.000000 0.000000343
vn 0.000000 1.000000 0.000000344
vn 0.000000 -1.000000 0.000000345
vn 0.000000 -1.000000 0.000000346
v -0.145000 0.280000 -0.045000347
v -0.055000 0.280000 -0.045000348
v -0.055000 0.680000 -0.045000349
v -0.145000 0.680000 -0.045000350
v -0.145000 0.280000 0.045000351
v -0.055000 0.280000 0.045000352
v -0.055000 0.680000 0.045000353
v -0.145000 0.680000 0.045000354
vn 0.000000 0.000000 -1.000000355
vn 0.000000 0.000000 -1.000000356
vn 0.000000 0.000000 1.000000357
vn 0.000000 -0.000000 1.000000358
vn -1.000000 0.000000 0.000000359
vn -1.000000 0.000000 0.000000360
vn 1.000000 0.000000 0.000000361
vn 1.000000 0.000000 0.000000362
vn 0.000000 1.000000 0.000000363
vn 0.000000 1.000000 0.000000364
vn 0.000000 -1.000000 0.000000365
vn 0.000000 -1.000000 0.000000366
v -0.150000 0.050000 -0.050000367
v -0.050000 0.050000 -0.050000368
v -0.050000 0.110000 -0.050000369
v -0.150000 0.110000 -0.050000370
v -0.150000 0.050000 0.170000371
v -0.050000 0.050000 0.170000372
v -0.050000 0.110000 0.170000373
v -0.150000 0.110000 0.170000374
vn 0.000000 0.000000 -1.000000374
vn 0.000000 0.000000 -1.000000375
vn 0.000000 0.000000 -1.000000375
vn 0.000000 0.000000 -1.000000376
vn 0.000000 0.000000 1.000000376
vn 0.000000 0.000000 1.000000The contents of this binary file are not shown.
The contents of this binary file are not shown.
The contents of this binary file are not shown.
The contents of this binary file are not shown.
@@ -203,7 +203,29 @@ fn assert_body(json: &Value, bin: &[u8], sex: &str) {
203
203
assert_eq!(extras["sex"], sex);
204
204
assert_eq!(extras["license"], "CC0-1.0");
205
205
assert_eq!(extras["up"], "+Y");
206
assert_eq!(extras["forward"], "-Z");
206
assert_eq!(extras["forward"], "+Z");
207
// glTF convention: front faces +Z, the character's left side is +X.
208
let node = |name: &str| {
209
json["nodes"]
210
.as_array()
211
.unwrap()
212
.iter()
213
.find(|n| n["name"] == name)
214
.unwrap_or_else(|| panic!("{name} missing"))
215
.clone()
216
};
217
assert!(
218
node("LeftFoot")["translation"][2].as_f64().unwrap() > 0.0,
219
"toes point to +Z"
220
);
221
assert!(
222
node("LeftUpperLeg")["translation"][0].as_f64().unwrap() > 0.0,
223
"left leg on +X"
224
);
225
assert!(
226
node("RightUpperLeg")["translation"][0].as_f64().unwrap() < 0.0,
227
"right leg on -X"
228
);
207
229
let label = extras["label"].as_str().unwrap();
208
230
assert!(
209
231
label.contains("geen definitief karakter"),
@@ -339,14 +361,16 @@ fn male_and_female_test_bodies_have_a_skeleton_and_both_clips() {
339
361
assert_body(&male, &male_bin, "male");
340
362
assert_body(&female, &female_bin, "female");
341
363
342
let male_shoulder = translation(&male, "LeftShoulder")[0];
343
let female_shoulder = translation(&female, "LeftShoulder")[0];
364
let male_shoulder = translation(&male, "LeftShoulder")[0].abs();
365
let female_shoulder = translation(&female, "LeftShoulder")[0].abs();
344
366
assert!(
345
male_shoulder < female_shoulder,
367
male_shoulder > female_shoulder,
346
368
"male shoulders must be wider ({male_shoulder} vs {female_shoulder})"
347
369
);
348
370
assert!(translation(&male, "Hips")[1] > translation(&female, "Hips")[1]);
349
assert!(translation(&female, "LeftUpperLeg")[0] < translation(&male, "LeftUpperLeg")[0]);
371
assert!(
372
translation(&female, "LeftUpperLeg")[0].abs() > translation(&male, "LeftUpperLeg")[0].abs()
373
);
350
374
351
375
let readme =
352
376
std::fs::read_to_string(repo_root().join("tests/fixtures/bodies/README.md")).unwrap();
@@ -203,7 +203,29 @@ fn assert_body(json: &Value, bin: &[u8], sex: &str) {203
assert_eq!(extras["sex"], sex);203
assert_eq!(extras["sex"], sex);204
assert_eq!(extras["license"], "CC0-1.0");204
assert_eq!(extras["license"], "CC0-1.0");205
assert_eq!(extras["up"], "+Y");205
assert_eq!(extras["up"], "+Y");206
assert_eq!(extras["forward"], "-Z");206
assert_eq!(extras["forward"], "+Z");207
// glTF convention: front faces +Z, the character's left side is +X.208
let node = |name: &str| {209
json["nodes"]210
.as_array()211
.unwrap()212
.iter()213
.find(|n| n["name"] == name)214
.unwrap_or_else(|| panic!("{name} missing"))215
.clone()216
};217
assert!(218
node("LeftFoot")["translation"][2].as_f64().unwrap() > 0.0,219
"toes point to +Z"220
);221
assert!(222
node("LeftUpperLeg")["translation"][0].as_f64().unwrap() > 0.0,223
"left leg on +X"224
);225
assert!(226
node("RightUpperLeg")["translation"][0].as_f64().unwrap() < 0.0,227
"right leg on -X"228
);207
let label = extras["label"].as_str().unwrap();229
let label = extras["label"].as_str().unwrap();208
assert!(230
assert!(209
label.contains("geen definitief karakter"),231
label.contains("geen definitief karakter"),@@ -339,14 +361,16 @@ fn male_and_female_test_bodies_have_a_skeleton_and_both_clips() {339
assert_body(&male, &male_bin, "male");361
assert_body(&male, &male_bin, "male");340
assert_body(&female, &female_bin, "female");362
assert_body(&female, &female_bin, "female");341
363
342
let male_shoulder = translation(&male, "LeftShoulder")[0];364
let male_shoulder = translation(&male, "LeftShoulder")[0].abs();343
let female_shoulder = translation(&female, "LeftShoulder")[0];365
let female_shoulder = translation(&female, "LeftShoulder")[0].abs();344
assert!(366
assert!(345
male_shoulder < female_shoulder,367
male_shoulder > female_shoulder,346
"male shoulders must be wider ({male_shoulder} vs {female_shoulder})"368
"male shoulders must be wider ({male_shoulder} vs {female_shoulder})"347
);369
);348
assert!(translation(&male, "Hips")[1] > translation(&female, "Hips")[1]);370
assert!(translation(&male, "Hips")[1] > translation(&female, "Hips")[1]);349
assert!(translation(&female, "LeftUpperLeg")[0] < translation(&male, "LeftUpperLeg")[0]);371
assert!(372
translation(&female, "LeftUpperLeg")[0].abs() > translation(&male, "LeftUpperLeg")[0].abs()373
);350
374
351
let readme =375
let readme =352
std::fs::read_to_string(repo_root().join("tests/fixtures/bodies/README.md")).unwrap();376
std::fs::read_to_string(repo_root().join("tests/fixtures/bodies/README.md")).unwrap();