@pmndrs/viverse 0.2.25 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation/bvh-bone-map.d.ts +11 -0
- package/dist/animation/bvh-bone-map.js +33 -0
- package/dist/animation/index.d.ts +1 -1
- package/dist/animation/index.js +2 -2
- package/dist/animation/mixamo-bone-map.d.ts +11 -0
- package/dist/animation/mixamo-bone-map.js +63 -0
- package/dist/physics/world.js +102 -33
- package/package.json +1 -1
- package/dist/animation/bvh-bone-map.json +0 -24
- package/dist/animation/mixamo-bone-map.json +0 -54
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { VRMHumanBoneName } from '@pixiv/three-vrm';
|
|
2
|
+
/**
|
|
3
|
+
* Maps standard BVH bone names to VRM humanoid bone names.
|
|
4
|
+
*
|
|
5
|
+
* Kept as a `.ts` module rather than a `.json` import on purpose: importing JSON requires
|
|
6
|
+
* import attributes (`with { type: 'json' }`), which survive into the published ESM build and
|
|
7
|
+
* break in-browser bundlers like the docs' Sandpack (Babel: "experimental syntax
|
|
8
|
+
* 'moduleAttributes' isn't currently enabled").
|
|
9
|
+
*/
|
|
10
|
+
declare const bvhBoneMap: Record<string, VRMHumanBoneName>;
|
|
11
|
+
export default bvhBoneMap;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps standard BVH bone names to VRM humanoid bone names.
|
|
3
|
+
*
|
|
4
|
+
* Kept as a `.ts` module rather than a `.json` import on purpose: importing JSON requires
|
|
5
|
+
* import attributes (`with { type: 'json' }`), which survive into the published ESM build and
|
|
6
|
+
* break in-browser bundlers like the docs' Sandpack (Babel: "experimental syntax
|
|
7
|
+
* 'moduleAttributes' isn't currently enabled").
|
|
8
|
+
*/
|
|
9
|
+
const bvhBoneMap = {
|
|
10
|
+
Hips: 'hips',
|
|
11
|
+
Spine: 'spine',
|
|
12
|
+
Spine1: 'chest',
|
|
13
|
+
Spine2: 'upperChest',
|
|
14
|
+
Neck: 'neck',
|
|
15
|
+
Head: 'head',
|
|
16
|
+
LeftShoulder: 'leftShoulder',
|
|
17
|
+
LeftArm: 'leftUpperArm',
|
|
18
|
+
LeftForeArm: 'leftLowerArm',
|
|
19
|
+
LeftHand: 'leftHand',
|
|
20
|
+
RightShoulder: 'rightShoulder',
|
|
21
|
+
RightArm: 'rightUpperArm',
|
|
22
|
+
RightForeArm: 'rightLowerArm',
|
|
23
|
+
RightHand: 'rightHand',
|
|
24
|
+
LeftUpLeg: 'leftUpperLeg',
|
|
25
|
+
LeftLeg: 'leftLowerLeg',
|
|
26
|
+
LeftFoot: 'leftFoot',
|
|
27
|
+
LeftToe: 'leftToes',
|
|
28
|
+
RightUpLeg: 'rightUpperLeg',
|
|
29
|
+
RightLeg: 'rightLowerLeg',
|
|
30
|
+
RightFoot: 'rightFoot',
|
|
31
|
+
RightToe: 'rightToes',
|
|
32
|
+
};
|
|
33
|
+
export default bvhBoneMap;
|
|
@@ -25,4 +25,4 @@ export declare function flattenCharacterAnimationOptions(options: Exclude<Charac
|
|
|
25
25
|
export declare function loadCharacterAnimation(model: CharacterModel, url: string | DefaultUrl, type?: CharacterAnimationOptions['type'], removeXZMovement?: boolean, trimStartTime?: number | undefined, trimEndTime?: number | undefined, boneMap?: Record<string, VRMHumanBoneName> | undefined, scaleTime?: number | undefined, mask?: CharacterAnimationMask): Promise<AnimationClip>;
|
|
26
26
|
export declare const mixamoBoneMap: Record<string, VRMHumanBoneName>;
|
|
27
27
|
export declare const bvhBoneMap: Record<string, VRMHumanBoneName>;
|
|
28
|
-
export declare const allBoneNames: string
|
|
28
|
+
export declare const allBoneNames: Array<string>;
|
package/dist/animation/index.js
CHANGED
|
@@ -4,10 +4,10 @@ import { BVHLoader } from 'three/examples/jsm/loaders/BVHLoader.js';
|
|
|
4
4
|
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
|
|
5
5
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
6
6
|
import { applyAnimationBoneMap } from './bone-map.js';
|
|
7
|
-
import _bvhBoneMap from './bvh-bone-map.
|
|
7
|
+
import _bvhBoneMap from './bvh-bone-map.js';
|
|
8
8
|
import { resolveDefaultCharacterAnimationUrl } from './default.js';
|
|
9
9
|
import { applyMask } from './mask.js';
|
|
10
|
-
import _mixamoBoneMap from './mixamo-bone-map.
|
|
10
|
+
import _mixamoBoneMap from './mixamo-bone-map.js';
|
|
11
11
|
import { scaleAnimationClipTime, trimAnimationClip } from './utils.js';
|
|
12
12
|
import { vrmaLoader } from '../model/index.js';
|
|
13
13
|
//helper variables for the quaternion retargeting
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { VRMHumanBoneName } from '@pixiv/three-vrm';
|
|
2
|
+
/**
|
|
3
|
+
* Maps Mixamo bone names (`mixamorig*`) to VRM humanoid bone names.
|
|
4
|
+
*
|
|
5
|
+
* Kept as a `.ts` module rather than a `.json` import on purpose: importing JSON requires
|
|
6
|
+
* import attributes (`with { type: 'json' }`), which survive into the published ESM build and
|
|
7
|
+
* break in-browser bundlers like the docs' Sandpack (Babel: "experimental syntax
|
|
8
|
+
* 'moduleAttributes' isn't currently enabled").
|
|
9
|
+
*/
|
|
10
|
+
declare const mixamoBoneMap: Record<string, VRMHumanBoneName>;
|
|
11
|
+
export default mixamoBoneMap;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps Mixamo bone names (`mixamorig*`) to VRM humanoid bone names.
|
|
3
|
+
*
|
|
4
|
+
* Kept as a `.ts` module rather than a `.json` import on purpose: importing JSON requires
|
|
5
|
+
* import attributes (`with { type: 'json' }`), which survive into the published ESM build and
|
|
6
|
+
* break in-browser bundlers like the docs' Sandpack (Babel: "experimental syntax
|
|
7
|
+
* 'moduleAttributes' isn't currently enabled").
|
|
8
|
+
*/
|
|
9
|
+
const mixamoBoneMap = {
|
|
10
|
+
mixamorigHips: 'hips',
|
|
11
|
+
mixamorigSpine: 'spine',
|
|
12
|
+
mixamorigSpine1: 'chest',
|
|
13
|
+
mixamorigSpine2: 'upperChest',
|
|
14
|
+
mixamorigNeck: 'neck',
|
|
15
|
+
mixamorigHead: 'head',
|
|
16
|
+
mixamorigLeftShoulder: 'leftShoulder',
|
|
17
|
+
mixamorigLeftArm: 'leftUpperArm',
|
|
18
|
+
mixamorigLeftForeArm: 'leftLowerArm',
|
|
19
|
+
mixamorigLeftHand: 'leftHand',
|
|
20
|
+
mixamorigLeftHandThumb1: 'leftThumbMetacarpal',
|
|
21
|
+
mixamorigLeftHandThumb2: 'leftThumbProximal',
|
|
22
|
+
mixamorigLeftHandThumb3: 'leftThumbDistal',
|
|
23
|
+
mixamorigLeftHandIndex1: 'leftIndexProximal',
|
|
24
|
+
mixamorigLeftHandIndex2: 'leftIndexIntermediate',
|
|
25
|
+
mixamorigLeftHandIndex3: 'leftIndexDistal',
|
|
26
|
+
mixamorigLeftHandMiddle1: 'leftMiddleProximal',
|
|
27
|
+
mixamorigLeftHandMiddle2: 'leftMiddleIntermediate',
|
|
28
|
+
mixamorigLeftHandMiddle3: 'leftMiddleDistal',
|
|
29
|
+
mixamorigLeftHandRing1: 'leftRingProximal',
|
|
30
|
+
mixamorigLeftHandRing2: 'leftRingIntermediate',
|
|
31
|
+
mixamorigLeftHandRing3: 'leftRingDistal',
|
|
32
|
+
mixamorigLeftHandPinky1: 'leftLittleProximal',
|
|
33
|
+
mixamorigLeftHandPinky2: 'leftLittleIntermediate',
|
|
34
|
+
mixamorigLeftHandPinky3: 'leftLittleDistal',
|
|
35
|
+
mixamorigRightShoulder: 'rightShoulder',
|
|
36
|
+
mixamorigRightArm: 'rightUpperArm',
|
|
37
|
+
mixamorigRightForeArm: 'rightLowerArm',
|
|
38
|
+
mixamorigRightHand: 'rightHand',
|
|
39
|
+
mixamorigRightHandPinky1: 'rightLittleProximal',
|
|
40
|
+
mixamorigRightHandPinky2: 'rightLittleIntermediate',
|
|
41
|
+
mixamorigRightHandPinky3: 'rightLittleDistal',
|
|
42
|
+
mixamorigRightHandRing1: 'rightRingProximal',
|
|
43
|
+
mixamorigRightHandRing2: 'rightRingIntermediate',
|
|
44
|
+
mixamorigRightHandRing3: 'rightRingDistal',
|
|
45
|
+
mixamorigRightHandMiddle1: 'rightMiddleProximal',
|
|
46
|
+
mixamorigRightHandMiddle2: 'rightMiddleIntermediate',
|
|
47
|
+
mixamorigRightHandMiddle3: 'rightMiddleDistal',
|
|
48
|
+
mixamorigRightHandIndex1: 'rightIndexProximal',
|
|
49
|
+
mixamorigRightHandIndex2: 'rightIndexIntermediate',
|
|
50
|
+
mixamorigRightHandIndex3: 'rightIndexDistal',
|
|
51
|
+
mixamorigRightHandThumb1: 'rightThumbMetacarpal',
|
|
52
|
+
mixamorigRightHandThumb2: 'rightThumbProximal',
|
|
53
|
+
mixamorigRightHandThumb3: 'rightThumbDistal',
|
|
54
|
+
mixamorigLeftUpLeg: 'leftUpperLeg',
|
|
55
|
+
mixamorigLeftLeg: 'leftLowerLeg',
|
|
56
|
+
mixamorigLeftFoot: 'leftFoot',
|
|
57
|
+
mixamorigLeftToeBase: 'leftToes',
|
|
58
|
+
mixamorigRightUpLeg: 'rightUpperLeg',
|
|
59
|
+
mixamorigRightLeg: 'rightLowerLeg',
|
|
60
|
+
mixamorigRightFoot: 'rightFoot',
|
|
61
|
+
mixamorigRightToeBase: 'rightToes',
|
|
62
|
+
};
|
|
63
|
+
export default mixamoBoneMap;
|
package/dist/physics/world.js
CHANGED
|
@@ -1,18 +1,62 @@
|
|
|
1
|
-
import { Box3, DoubleSide, InstancedMesh, Matrix4, Mesh, Ray, Vector3, } from 'three';
|
|
2
|
-
import {
|
|
1
|
+
import { BatchedMesh, Box3, BufferAttribute, BufferGeometry, DoubleSide, InstancedMesh, Matrix4, Mesh, Ray, SkinnedMesh, Vector3, } from 'three';
|
|
2
|
+
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
3
|
+
import { computeBoundsTree, ExtendedTriangle } from 'three-mesh-bvh';
|
|
3
4
|
const rayHelper = new Ray();
|
|
4
5
|
const farPointHelper = new Vector3();
|
|
5
6
|
const boxHelper = new Box3();
|
|
6
7
|
const triangleHelper = new ExtendedTriangle();
|
|
7
8
|
const matrixHelper = new Matrix4();
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Bakes a mesh's collision geometry into `matrix` space. A bvh only needs positions and (optionally) an index, so
|
|
11
|
+
* everything else is dropped - this keeps the merge below trivial and sidesteps three's "geometries must have the
|
|
12
|
+
* same attributes" restriction that a body mixing meshes with different attribute sets (e.g. gltf primitives) hits.
|
|
13
|
+
* Positions are read into a fresh float buffer so interleaved or quantized (e.g. meshopt/draco int) source
|
|
14
|
+
* attributes are de-interleaved and de-quantized - otherwise applyMatrix4 would overflow the source storage and
|
|
15
|
+
* mergeGeometries would reject the mismatching layouts.
|
|
12
16
|
*/
|
|
13
|
-
function
|
|
14
|
-
const
|
|
15
|
-
|
|
17
|
+
function bakeCollisionGeometry(mesh, matrix) {
|
|
18
|
+
const source = mesh.geometry.getAttribute('position');
|
|
19
|
+
const position = new BufferAttribute(new Float32Array(source.count * 3), 3);
|
|
20
|
+
for (let i = 0; i < source.count; i++) {
|
|
21
|
+
position.setXYZ(i, source.getX(i), source.getY(i), source.getZ(i));
|
|
22
|
+
}
|
|
23
|
+
const geometry = new BufferGeometry();
|
|
24
|
+
geometry.setAttribute('position', position);
|
|
25
|
+
if (mesh.geometry.index != null) {
|
|
26
|
+
geometry.setIndex(mesh.geometry.index.clone());
|
|
27
|
+
}
|
|
28
|
+
return geometry.applyMatrix4(matrix);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A mesh whose positions are actively displaced by morph targets - its resting geometry doesn't match what's drawn,
|
|
32
|
+
* so (like a skinned mesh) it is skipped rather than baked into a wrong-shaped collider.
|
|
33
|
+
*/
|
|
34
|
+
function isMorphDeformed(mesh) {
|
|
35
|
+
return (mesh.geometry.morphAttributes.position != null &&
|
|
36
|
+
(mesh.morphTargetInfluences?.some((influence) => influence !== 0) ?? false));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Extracts one geometry of a BatchedMesh into a standalone geometry in its local space. A BatchedMesh packs every
|
|
40
|
+
* geometry into one shared buffer, so a single bvh over that buffer would collide against all of them at once -
|
|
41
|
+
* instead each geometry gets its own bvh, referenced per instance with the instance's matrix at query time.
|
|
42
|
+
*/
|
|
43
|
+
function extractBatchedCollisionGeometry(mesh, geometryId) {
|
|
44
|
+
const range = mesh.getGeometryRangeAt(geometryId);
|
|
45
|
+
if (range == null) {
|
|
46
|
+
throw new Error(`BvhPhysicsWorld: BatchedMesh has no geometry ${geometryId}`);
|
|
47
|
+
}
|
|
48
|
+
const source = mesh.geometry.getAttribute('position');
|
|
49
|
+
const index = mesh.geometry.index;
|
|
50
|
+
const start = index != null ? range.indexStart : range.vertexStart;
|
|
51
|
+
const count = index != null ? range.indexCount : range.vertexCount;
|
|
52
|
+
const position = new BufferAttribute(new Float32Array(count * 3), 3);
|
|
53
|
+
for (let i = 0; i < count; i++) {
|
|
54
|
+
const vertexIndex = index != null ? index.getX(start + i) : start + i;
|
|
55
|
+
position.setXYZ(i, source.getX(vertexIndex), source.getY(vertexIndex), source.getZ(vertexIndex));
|
|
56
|
+
}
|
|
57
|
+
const geometry = new BufferGeometry();
|
|
58
|
+
geometry.setAttribute('position', position);
|
|
59
|
+
return geometry;
|
|
16
60
|
}
|
|
17
61
|
export class BvhPhysicsWorld {
|
|
18
62
|
bodies = [];
|
|
@@ -38,15 +82,23 @@ export class BvhPhysicsWorld {
|
|
|
38
82
|
}
|
|
39
83
|
computeBvhEntries(object, isStatic) {
|
|
40
84
|
object.updateWorldMatrix(true, true);
|
|
85
|
+
//Static bodies are baked in world space; kinematic bodies are baked in the body's local space so that its
|
|
86
|
+
//(changing) world matrix can be applied at query time instead (see computeMatrix), hence the inverse here.
|
|
87
|
+
const worldToBakeSpace = isStatic ? undefined : new Matrix4().copy(object.matrixWorld).invert();
|
|
88
|
+
const bakeMatrix = new Matrix4();
|
|
41
89
|
const result = [];
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
90
|
+
//A merge of collision geometries only works when they agree on being indexed, so keep indexed and
|
|
91
|
+
//non-indexed meshes apart and turn each group into its own bvh.
|
|
92
|
+
const indexedGeometries = [];
|
|
93
|
+
const nonIndexedGeometries = [];
|
|
94
|
+
//traverseVisible so hidden meshes (toggled decorations, LODs) don't silently become colliders.
|
|
95
|
+
object.traverseVisible((entry) => {
|
|
47
96
|
if (entry instanceof InstancedMesh) {
|
|
48
97
|
const bvh = computeBoundsTree.apply(entry.geometry);
|
|
49
|
-
result.push(
|
|
98
|
+
result.push(
|
|
99
|
+
//entry.count (active instances), not instanceMatrix.count (allocated capacity), to avoid phantom
|
|
100
|
+
//colliders at the stale matrices of unused instance slots.
|
|
101
|
+
...Array.from({ length: entry.count }, (_, instanceIndex) => ({
|
|
50
102
|
object: entry,
|
|
51
103
|
bvh,
|
|
52
104
|
instanceIndex,
|
|
@@ -54,30 +106,47 @@ export class BvhPhysicsWorld {
|
|
|
54
106
|
})));
|
|
55
107
|
return;
|
|
56
108
|
}
|
|
57
|
-
if (entry instanceof
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
109
|
+
if (entry instanceof BatchedMesh) {
|
|
110
|
+
//Each geometry in the batch gets its own bvh, referenced once per visible instance with the instance's
|
|
111
|
+
//matrix applied at query time (like InstancedMesh). Instances deleted before addBody aren't handled -
|
|
112
|
+
//three offers no way to enumerate active instances across the gaps a deletion leaves.
|
|
113
|
+
const geometryBvhs = new Map();
|
|
114
|
+
for (let instanceIndex = 0; instanceIndex < entry.instanceCount; instanceIndex++) {
|
|
115
|
+
if (!entry.getVisibleAt(instanceIndex)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const geometryId = entry.getGeometryIdAt(instanceIndex);
|
|
119
|
+
let bvh = geometryBvhs.get(geometryId);
|
|
120
|
+
if (bvh == null) {
|
|
121
|
+
bvh = computeBoundsTree.apply(extractBatchedCollisionGeometry(entry, geometryId));
|
|
122
|
+
geometryBvhs.set(geometryId, bvh);
|
|
123
|
+
}
|
|
124
|
+
result.push({ object: entry, bvh, instanceIndex, isStatic });
|
|
62
125
|
}
|
|
63
|
-
|
|
126
|
+
return;
|
|
64
127
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
128
|
+
//skip skinned and morph-deformed meshes (their shape comes from per-vertex deformation a single baked
|
|
129
|
+
//matrix can't capture - use a primitive collider) and meshes that have no positions to collide against.
|
|
130
|
+
if (!(entry instanceof Mesh) ||
|
|
131
|
+
entry instanceof SkinnedMesh ||
|
|
132
|
+
isMorphDeformed(entry) ||
|
|
133
|
+
entry.geometry.getAttribute('position') == null) {
|
|
134
|
+
return;
|
|
71
135
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
result.push({ object, bvh, isStatic });
|
|
136
|
+
bakeMatrix.copy(entry.matrixWorld);
|
|
137
|
+
if (worldToBakeSpace != null) {
|
|
138
|
+
bakeMatrix.premultiply(worldToBakeSpace);
|
|
76
139
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
140
|
+
const geometry = bakeCollisionGeometry(entry, bakeMatrix);
|
|
141
|
+
(geometry.index == null ? nonIndexedGeometries : indexedGeometries).push(geometry);
|
|
142
|
+
});
|
|
143
|
+
for (const geometries of [indexedGeometries, nonIndexedGeometries]) {
|
|
144
|
+
if (geometries.length === 0) {
|
|
145
|
+
continue;
|
|
80
146
|
}
|
|
147
|
+
const geometry = geometries.length === 1 ? geometries[0] : mergeGeometries(geometries);
|
|
148
|
+
const bvh = computeBoundsTree.apply(geometry);
|
|
149
|
+
result.push({ object, bvh, isStatic });
|
|
81
150
|
}
|
|
82
151
|
return result;
|
|
83
152
|
}
|
package/package.json
CHANGED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"Hips": "hips",
|
|
3
|
-
"Spine": "spine",
|
|
4
|
-
"Spine1": "chest",
|
|
5
|
-
"Spine2": "upperChest",
|
|
6
|
-
"Neck": "neck",
|
|
7
|
-
"Head": "head",
|
|
8
|
-
"LeftShoulder": "leftShoulder",
|
|
9
|
-
"LeftArm": "leftUpperArm",
|
|
10
|
-
"LeftForeArm": "leftLowerArm",
|
|
11
|
-
"LeftHand": "leftHand",
|
|
12
|
-
"RightShoulder": "rightShoulder",
|
|
13
|
-
"RightArm": "rightUpperArm",
|
|
14
|
-
"RightForeArm": "rightLowerArm",
|
|
15
|
-
"RightHand": "rightHand",
|
|
16
|
-
"LeftUpLeg": "leftUpperLeg",
|
|
17
|
-
"LeftLeg": "leftLowerLeg",
|
|
18
|
-
"LeftFoot": "leftFoot",
|
|
19
|
-
"LeftToe": "leftToes",
|
|
20
|
-
"RightUpLeg": "rightUpperLeg",
|
|
21
|
-
"RightLeg": "rightLowerLeg",
|
|
22
|
-
"RightFoot": "rightFoot",
|
|
23
|
-
"RightToe": "rightToes"
|
|
24
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mixamorigHips": "hips",
|
|
3
|
-
"mixamorigSpine": "spine",
|
|
4
|
-
"mixamorigSpine1": "chest",
|
|
5
|
-
"mixamorigSpine2": "upperChest",
|
|
6
|
-
"mixamorigNeck": "neck",
|
|
7
|
-
"mixamorigHead": "head",
|
|
8
|
-
"mixamorigLeftShoulder": "leftShoulder",
|
|
9
|
-
"mixamorigLeftArm": "leftUpperArm",
|
|
10
|
-
"mixamorigLeftForeArm": "leftLowerArm",
|
|
11
|
-
"mixamorigLeftHand": "leftHand",
|
|
12
|
-
"mixamorigLeftHandThumb1": "leftThumbMetacarpal",
|
|
13
|
-
"mixamorigLeftHandThumb2": "leftThumbProximal",
|
|
14
|
-
"mixamorigLeftHandThumb3": "leftThumbDistal",
|
|
15
|
-
"mixamorigLeftHandIndex1": "leftIndexProximal",
|
|
16
|
-
"mixamorigLeftHandIndex2": "leftIndexIntermediate",
|
|
17
|
-
"mixamorigLeftHandIndex3": "leftIndexDistal",
|
|
18
|
-
"mixamorigLeftHandMiddle1": "leftMiddleProximal",
|
|
19
|
-
"mixamorigLeftHandMiddle2": "leftMiddleIntermediate",
|
|
20
|
-
"mixamorigLeftHandMiddle3": "leftMiddleDistal",
|
|
21
|
-
"mixamorigLeftHandRing1": "leftRingProximal",
|
|
22
|
-
"mixamorigLeftHandRing2": "leftRingIntermediate",
|
|
23
|
-
"mixamorigLeftHandRing3": "leftRingDistal",
|
|
24
|
-
"mixamorigLeftHandPinky1": "leftLittleProximal",
|
|
25
|
-
"mixamorigLeftHandPinky2": "leftLittleIntermediate",
|
|
26
|
-
"mixamorigLeftHandPinky3": "leftLittleDistal",
|
|
27
|
-
"mixamorigRightShoulder": "rightShoulder",
|
|
28
|
-
"mixamorigRightArm": "rightUpperArm",
|
|
29
|
-
"mixamorigRightForeArm": "rightLowerArm",
|
|
30
|
-
"mixamorigRightHand": "rightHand",
|
|
31
|
-
"mixamorigRightHandPinky1": "rightLittleProximal",
|
|
32
|
-
"mixamorigRightHandPinky2": "rightLittleIntermediate",
|
|
33
|
-
"mixamorigRightHandPinky3": "rightLittleDistal",
|
|
34
|
-
"mixamorigRightHandRing1": "rightRingProximal",
|
|
35
|
-
"mixamorigRightHandRing2": "rightRingIntermediate",
|
|
36
|
-
"mixamorigRightHandRing3": "rightRingDistal",
|
|
37
|
-
"mixamorigRightHandMiddle1": "rightMiddleProximal",
|
|
38
|
-
"mixamorigRightHandMiddle2": "rightMiddleIntermediate",
|
|
39
|
-
"mixamorigRightHandMiddle3": "rightMiddleDistal",
|
|
40
|
-
"mixamorigRightHandIndex1": "rightIndexProximal",
|
|
41
|
-
"mixamorigRightHandIndex2": "rightIndexIntermediate",
|
|
42
|
-
"mixamorigRightHandIndex3": "rightIndexDistal",
|
|
43
|
-
"mixamorigRightHandThumb1": "rightThumbMetacarpal",
|
|
44
|
-
"mixamorigRightHandThumb2": "rightThumbProximal",
|
|
45
|
-
"mixamorigRightHandThumb3": "rightThumbDistal",
|
|
46
|
-
"mixamorigLeftUpLeg": "leftUpperLeg",
|
|
47
|
-
"mixamorigLeftLeg": "leftLowerLeg",
|
|
48
|
-
"mixamorigLeftFoot": "leftFoot",
|
|
49
|
-
"mixamorigLeftToeBase": "leftToes",
|
|
50
|
-
"mixamorigRightUpLeg": "rightUpperLeg",
|
|
51
|
-
"mixamorigRightLeg": "rightLowerLeg",
|
|
52
|
-
"mixamorigRightFoot": "rightFoot",
|
|
53
|
-
"mixamorigRightToeBase": "rightToes"
|
|
54
|
-
}
|