@flighthq/skeleton3d 0.3.0 → 0.3.1-next.1041.35b950c
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/contract.d.ts +1 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +1 -0
- package/dist/contract.js.map +1 -1
- package/dist/enableSkeleton3DGuards.d.ts +4 -0
- package/dist/enableSkeleton3DGuards.d.ts.map +1 -0
- package/dist/enableSkeleton3DGuards.js +29 -0
- package/dist/enableSkeleton3DGuards.js.map +1 -0
- package/dist/getMeshSkinBounds.d.ts.map +1 -1
- package/dist/getMeshSkinBounds.js +1 -1
- package/dist/getMeshSkinBounds.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/skeleton3d.d.ts +1 -0
- package/dist/skeleton3d.d.ts.map +1 -1
- package/dist/skeleton3d.js +42 -4
- package/dist/skeleton3d.js.map +1 -1
- package/dist/skinMeshGeometry.d.ts.map +1 -1
- package/dist/skinMeshGeometry.js +28 -3
- package/dist/skinMeshGeometry.js.map +1 -1
- package/dist/skinVertices.d.ts +2 -1
- package/dist/skinVertices.d.ts.map +1 -1
- package/dist/skinVertices.js +78 -10
- package/dist/skinVertices.js.map +1 -1
- package/package.json +7 -6
- package/src/enableSkeleton3DGuards.test.ts +66 -0
- package/src/getMeshSkinBounds.test.ts +3 -0
- package/src/skeleton3d.test.ts +68 -0
- package/src/skinMeshGeometry.test.ts +54 -1
- package/src/skinVertices.test.ts +297 -6
package/dist/contract.d.ts
CHANGED
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC"}
|
package/dist/contract.js
CHANGED
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enableSkeleton3DGuards.d.ts","sourceRoot":"","sources":["../src/enableSkeleton3DGuards.ts"],"names":[],"mappings":"AAMA,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAKD,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { logOnce } from '@flighthq/log/contract';
|
|
2
|
+
import { LogLevel } from '@flighthq/types/contract';
|
|
3
|
+
import { setSkeleton3DBindPoseGuard } from './skeleton3d';
|
|
4
|
+
export function areSkeleton3DGuardsEnabled() {
|
|
5
|
+
return skeleton3DGuardsEnabled;
|
|
6
|
+
}
|
|
7
|
+
export function disableSkeleton3DGuards() {
|
|
8
|
+
setSkeleton3DBindPoseGuard(null);
|
|
9
|
+
skeleton3DGuardsEnabled = false;
|
|
10
|
+
}
|
|
11
|
+
// Installs opt-in diagnostics for skeleton operations that substitute a value rather than compute one.
|
|
12
|
+
// The core modules stay message-free, so an application that omits this one sheds both the text and
|
|
13
|
+
// @flighthq/log.
|
|
14
|
+
export function enableSkeleton3DGuards() {
|
|
15
|
+
setSkeleton3DBindPoseGuard(warnOnDegenerateSkeleton3DBindPose);
|
|
16
|
+
skeleton3DGuardsEnabled = true;
|
|
17
|
+
}
|
|
18
|
+
// The substituted identity is a deliberate recovery, not a computed result: that one joint captures no
|
|
19
|
+
// bind pose and renders undeformed while the rest of the rig works. Nothing else reports it, and the
|
|
20
|
+
// symptom — one limb that will not deform — points at the mesh rather than at the joint's scale.
|
|
21
|
+
function warnOnDegenerateSkeleton3DBindPose(skeleton, jointIndex) {
|
|
22
|
+
logOnce(`skeleton3d:degenerate-bind-pose:${jointIndex}`, LogLevel.Warn, {
|
|
23
|
+
joint: skeleton.joints[jointIndex]?.name ?? '<unnamed>',
|
|
24
|
+
jointIndex,
|
|
25
|
+
message: 'setSkeleton3DBindPose: a joint has no invertible world matrix, so its inverse-bind entry was set to identity and that joint will not deform — a zero scale on the joint or an ancestor is the usual cause, and an imported rig can carry one.',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
let skeleton3DGuardsEnabled = false;
|
|
29
|
+
//# sourceMappingURL=enableSkeleton3DGuards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enableSkeleton3DGuards.js","sourceRoot":"","sources":["../src/enableSkeleton3DGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,UAAU,0BAA0B;IACxC,OAAO,uBAAuB,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,0BAA0B,CAAC,IAAI,CAAC,CAAC;IACjC,uBAAuB,GAAG,KAAK,CAAC;AAClC,CAAC;AAED,uGAAuG;AACvG,oGAAoG;AACpG,iBAAiB;AACjB,MAAM,UAAU,sBAAsB;IACpC,0BAA0B,CAAC,kCAAkC,CAAC,CAAC;IAC/D,uBAAuB,GAAG,IAAI,CAAC;AACjC,CAAC;AAED,uGAAuG;AACvG,qGAAqG;AACrG,iGAAiG;AACjG,SAAS,kCAAkC,CAAC,QAA8B,EAAE,UAAkB;IAC5F,OAAO,CAAC,mCAAmC,UAAU,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE;QACtE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,IAAI,WAAW;QACvD,UAAU;QACV,OAAO,EACL,+OAA+O;KAClP,CAAC,CAAC;AACL,CAAC;AAED,IAAI,uBAAuB,GAAG,KAAK,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getMeshSkinBounds.d.ts","sourceRoot":"","sources":["../src/getMeshSkinBounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAoBvF,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EACpC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC7B,IAAI,CAgFN;AASD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EACpC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC7B,IAAI,
|
|
1
|
+
{"version":3,"file":"getMeshSkinBounds.d.ts","sourceRoot":"","sources":["../src/getMeshSkinBounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAoBvF,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EACpC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC7B,IAAI,CAgFN;AASD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EACpC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC7B,IAAI,CAyCN"}
|
|
@@ -92,7 +92,7 @@ export function getMeshSkinConservativeBounds(out, bindPose, skeleton) {
|
|
|
92
92
|
// yields the empty box (min = +Infinity, max = -Infinity). Overwrites bindPose.skinnedPositions /
|
|
93
93
|
// skinnedNormals as scratch (the same buffers a subsequent skinMeshGeometry would rewrite).
|
|
94
94
|
export function getMeshSkinExactBounds(out, bindPose, skeleton) {
|
|
95
|
-
skinVertices(bindPose.skinnedPositions, bindPose.skinnedNormals, bindPose.positions, bindPose.normals, bindPose.joints, bindPose.weights, skeleton.jointMatrices);
|
|
95
|
+
skinVertices(bindPose.skinnedPositions, bindPose.skinnedNormals, bindPose.positions, bindPose.normals, bindPose.joints, bindPose.weights, skeleton.jointMatrices, skeleton.normalMatrices);
|
|
96
96
|
const skinned = bindPose.skinnedPositions;
|
|
97
97
|
const vertexCount = (skinned.length / 3) | 0;
|
|
98
98
|
let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, minZ = Number.POSITIVE_INFINITY;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getMeshSkinBounds.js","sourceRoot":"","sources":["../src/getMeshSkinBounds.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"getMeshSkinBounds.js","sourceRoot":"","sources":["../src/getMeshSkinBounds.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { captureMeshSkinBindPose, cloneSkeleton3D, cloneSkeleton3DJointHierarchy, computeSkeleton3DJointMatrices, createSkeleton3D, disposeSkeleton3D, equalsSkeleton3D, getMeshSkinConservativeBounds, getMeshSkinExactBounds, getSkeleton3DJointIndexByName, getSkeleton3DJointWorldMatrix, getSkeleton3DJointWorldMatrixByName, prepareMeshSkinning, prepareScene3DSkinning, setSkeleton3DBindPose, skinMeshGeometry, skinVertices, updateMeshDeformation, updateMeshSkin, updateMeshSkinBindPoseDeformInput, validateSkeleton3D, } from './contract';
|
|
1
|
+
export { captureMeshSkinBindPose, cloneSkeleton3D, cloneSkeleton3DJointHierarchy, computeSkeleton3DJointMatrices, createSkeleton3D, disposeSkeleton3D, equalsSkeleton3D, getMeshSkinConservativeBounds, getMeshSkinExactBounds, getSkeleton3DJointIndexByName, getSkeleton3DJointWorldMatrix, getSkeleton3DJointWorldMatrixByName, prepareMeshSkinning, prepareScene3DSkinning, setSkeleton3DBindPose, skinMeshGeometry, skinTangents, skinVertices, updateMeshDeformation, updateMeshSkin, updateMeshSkinBindPoseDeformInput, validateSkeleton3D, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,6BAA6B,EAC7B,8BAA8B,EAC9B,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,6BAA6B,EAC7B,sBAAsB,EACtB,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,iCAAiC,EACjC,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,6BAA6B,EAC7B,8BAA8B,EAC9B,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,6BAA6B,EAC7B,sBAAsB,EACtB,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,iCAAiC,EACjC,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { captureMeshSkinBindPose, cloneSkeleton3D, cloneSkeleton3DJointHierarchy, computeSkeleton3DJointMatrices, createSkeleton3D, disposeSkeleton3D, equalsSkeleton3D, getMeshSkinConservativeBounds, getMeshSkinExactBounds, getSkeleton3DJointIndexByName, getSkeleton3DJointWorldMatrix, getSkeleton3DJointWorldMatrixByName, prepareMeshSkinning, prepareScene3DSkinning, setSkeleton3DBindPose, skinMeshGeometry, skinVertices, updateMeshDeformation, updateMeshSkin, updateMeshSkinBindPoseDeformInput, validateSkeleton3D, } from './contract';
|
|
1
|
+
export { captureMeshSkinBindPose, cloneSkeleton3D, cloneSkeleton3DJointHierarchy, computeSkeleton3DJointMatrices, createSkeleton3D, disposeSkeleton3D, equalsSkeleton3D, getMeshSkinConservativeBounds, getMeshSkinExactBounds, getSkeleton3DJointIndexByName, getSkeleton3DJointWorldMatrix, getSkeleton3DJointWorldMatrixByName, prepareMeshSkinning, prepareScene3DSkinning, setSkeleton3DBindPose, skinMeshGeometry, skinTangents, skinVertices, updateMeshDeformation, updateMeshSkin, updateMeshSkinBindPoseDeformInput, validateSkeleton3D, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,6BAA6B,EAC7B,8BAA8B,EAC9B,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,6BAA6B,EAC7B,sBAAsB,EACtB,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,iCAAiC,EACjC,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,6BAA6B,EAC7B,8BAA8B,EAC9B,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,6BAA6B,EAC7B,sBAAsB,EACtB,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,iCAAiC,EACjC,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/skeleton3d.d.ts
CHANGED
|
@@ -9,5 +9,6 @@ export declare function getSkeleton3DJointIndexByName(skeleton: Readonly<Skeleto
|
|
|
9
9
|
export declare function getSkeleton3DJointWorldMatrix(out: Matrix4Like, skeleton: Readonly<Skeleton3D>, jointIndex: number): boolean;
|
|
10
10
|
export declare function getSkeleton3DJointWorldMatrixByName(out: Matrix4Like, skeleton: Readonly<Skeleton3D>, name: string): boolean;
|
|
11
11
|
export declare function setSkeleton3DBindPose(skeleton: Readonly<Skeleton3D>): void;
|
|
12
|
+
export declare function setSkeleton3DBindPoseGuard(guard: ((skeleton: Readonly<Skeleton3D>, jointIndex: number) => void) | null): void;
|
|
12
13
|
export declare function validateSkeleton3D(skeleton: Readonly<Skeleton3D>): Skeleton3DValidationDiagnostic | null;
|
|
13
14
|
//# sourceMappingURL=skeleton3d.d.ts.map
|
package/dist/skeleton3d.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton3d.d.ts","sourceRoot":"","sources":["../src/skeleton3d.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skeleton3d.d.ts","sourceRoot":"","sources":["../src/skeleton3d.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAEhH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,CAS1E;AAOD,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,GAClE,UAAU,CAuBZ;AAED,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAqBnF;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EAAE,EAChB,mBAAmB,CAAC,EAAE,YAAY,EAClC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAC/B,UAAU,CAWZ;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAG5D;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,OAAO,CAe1F;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlG;AAED,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,UAAU,EAAE,MAAM,GACjB,OAAO,CAKT;AAED,wBAAgB,mCAAmC,CACjD,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,IAAI,EAAE,MAAM,GACX,OAAO,CAET;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAmB1E;AAKD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,GAC3E,IAAI,CAEN;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,8BAA8B,GAAG,IAAI,CAWxG"}
|
package/dist/skeleton3d.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createEntity } from '@flighthq/entity/contract';
|
|
2
|
-
import { copyMatrix4, createMatrix4, inverseMatrix4, multiplyMatrix4 } from '@flighthq/geometry/contract';
|
|
2
|
+
import { copyMatrix4, createMatrix3, createMatrix4, inverseMatrix4, multiplyMatrix4, setMatrix3NormalFromMatrix4, setMatrix4Identity, } from '@flighthq/geometry/contract';
|
|
3
3
|
import { addNodeChild, getNodeParent, getNodeWorldMatrix4 } from '@flighthq/node/contract';
|
|
4
4
|
export function cloneSkeleton3D(skeleton) {
|
|
5
5
|
const clone = createEntity({
|
|
@@ -7,6 +7,7 @@ export function cloneSkeleton3D(skeleton) {
|
|
|
7
7
|
jointMatrices: new Float32Array(skeleton.jointMatrices),
|
|
8
8
|
joints: skeleton.joints.slice(),
|
|
9
9
|
names: skeleton.names === undefined ? undefined : skeleton.names === null ? null : skeleton.names.slice(),
|
|
10
|
+
normalMatrices: new Float32Array(skeleton.normalMatrices),
|
|
10
11
|
});
|
|
11
12
|
return clone;
|
|
12
13
|
}
|
|
@@ -38,16 +39,30 @@ export function cloneSkeleton3DJointHierarchy(skeleton, cloneJoint) {
|
|
|
38
39
|
jointMatrices: new Float32Array(skeleton.jointMatrices),
|
|
39
40
|
joints,
|
|
40
41
|
names: skeleton.names === undefined ? undefined : skeleton.names === null ? null : skeleton.names.slice(),
|
|
42
|
+
normalMatrices: new Float32Array(skeleton.normalMatrices),
|
|
41
43
|
});
|
|
42
44
|
}
|
|
43
45
|
export function computeSkeleton3DJointMatrices(skeleton) {
|
|
44
|
-
const { inverseBindMatrices, jointMatrices, joints } = skeleton;
|
|
46
|
+
const { inverseBindMatrices, jointMatrices, joints, normalMatrices } = skeleton;
|
|
45
47
|
for (let j = 0; j < joints.length; j++) {
|
|
46
48
|
const base = j * 16;
|
|
47
49
|
for (let i = 0; i < 16; i++)
|
|
48
50
|
_invBind.m[i] = inverseBindMatrices[base + i];
|
|
49
51
|
multiplyMatrix4(_result, getNodeWorldMatrix4(joints[j]), _invBind);
|
|
50
52
|
jointMatrices.set(_result.m, base);
|
|
53
|
+
// The normal palette is filled here rather than in the skinning loop because it is per JOINT, not
|
|
54
|
+
// per vertex — a few dozen inversions a frame against tens of thousands of vertices.
|
|
55
|
+
setMatrix3NormalFromMatrix4(_normal, _result);
|
|
56
|
+
// Written as three padded vec4 columns rather than a tight 3x3, so the array can be handed to the
|
|
57
|
+
// GPU data texture unchanged; the fourth float of each column is unused.
|
|
58
|
+
const n = j * 12;
|
|
59
|
+
const m = _normal.m;
|
|
60
|
+
for (let c = 0; c < 3; c++) {
|
|
61
|
+
normalMatrices[n + c * 4] = m[c * 3];
|
|
62
|
+
normalMatrices[n + c * 4 + 1] = m[c * 3 + 1];
|
|
63
|
+
normalMatrices[n + c * 4 + 2] = m[c * 3 + 2];
|
|
64
|
+
normalMatrices[n + c * 4 + 3] = 0;
|
|
65
|
+
}
|
|
51
66
|
}
|
|
52
67
|
}
|
|
53
68
|
export function createSkeleton3D(joints, inverseBindMatrices, names) {
|
|
@@ -57,6 +72,7 @@ export function createSkeleton3D(joints, inverseBindMatrices, names) {
|
|
|
57
72
|
jointMatrices: new Float32Array(count * 16),
|
|
58
73
|
joints,
|
|
59
74
|
names: names ?? null,
|
|
75
|
+
normalMatrices: new Float32Array(count * 12),
|
|
60
76
|
});
|
|
61
77
|
if (inverseBindMatrices === undefined)
|
|
62
78
|
setSkeleton3DBindPose(skeleton);
|
|
@@ -108,10 +124,30 @@ export function getSkeleton3DJointWorldMatrixByName(out, skeleton, name) {
|
|
|
108
124
|
export function setSkeleton3DBindPose(skeleton) {
|
|
109
125
|
const { inverseBindMatrices, joints } = skeleton;
|
|
110
126
|
for (let j = 0; j < joints.length; j++) {
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
// A joint's world matrix is singular when anything in its chain carries a zero scale, and that value
|
|
128
|
+
// is not necessarily the app's: glTF import writes node scale straight from unvalidated file data
|
|
129
|
+
// and joints ARE nodes, so a collapsed rig arrives from a file we do not control.
|
|
130
|
+
//
|
|
131
|
+
// Identity per joint, matching the AWD2 bind-pose recovery rather than declining the whole call: one
|
|
132
|
+
// degenerate joint costs its own bind pose and leaves it undeformed, while every other joint keeps
|
|
133
|
+
// working. Writing the failed inverse instead puts NaN in the palette, and NaN there does not stay
|
|
134
|
+
// put — it reaches the skinned vertices and takes the mesh with it, silently.
|
|
135
|
+
if (inverseMatrix4(_result, getNodeWorldMatrix4(joints[j]))) {
|
|
136
|
+
inverseBindMatrices.set(_result.m, j * 16);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
setMatrix4Identity(_result);
|
|
140
|
+
inverseBindMatrices.set(_result.m, j * 16);
|
|
141
|
+
skeleton3DBindPoseGuard?.(skeleton, j);
|
|
142
|
+
}
|
|
113
143
|
}
|
|
114
144
|
}
|
|
145
|
+
// The seam the guard layer installs into. This package has no importdiagnostics sink — it is not an
|
|
146
|
+
// importer, even though the degenerate value usually originates in one — so the caller-facing message
|
|
147
|
+
// lives in the guard layer, like `reparentNode`'s, rather than as a tally.
|
|
148
|
+
export function setSkeleton3DBindPoseGuard(guard) {
|
|
149
|
+
skeleton3DBindPoseGuard = guard;
|
|
150
|
+
}
|
|
115
151
|
export function validateSkeleton3D(skeleton) {
|
|
116
152
|
const jointCount = skeleton.joints.length;
|
|
117
153
|
const expectedInverseBindMatricesLength = jointCount * 16;
|
|
@@ -127,4 +163,6 @@ export function validateSkeleton3D(skeleton) {
|
|
|
127
163
|
}
|
|
128
164
|
const _invBind = createMatrix4();
|
|
129
165
|
const _result = createMatrix4();
|
|
166
|
+
const _normal = createMatrix3();
|
|
167
|
+
let skeleton3DBindPoseGuard = null;
|
|
130
168
|
//# sourceMappingURL=skeleton3d.js.map
|
package/dist/skeleton3d.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton3d.js","sourceRoot":"","sources":["../src/skeleton3d.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,
|
|
1
|
+
{"version":3,"file":"skeleton3d.js","sourceRoot":"","sources":["../src/skeleton3d.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skinMeshGeometry.d.ts","sourceRoot":"","sources":["../src/skinMeshGeometry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAyB,MAAM,0BAA0B,CAAC;AAWlH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"skinMeshGeometry.d.ts","sourceRoot":"","sources":["../src/skinMeshGeometry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAyB,MAAM,0BAA0B,CAAC;AAWlH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,gBAAgB,CA+D1F;AASD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GACnC,IAAI,CA+CN;AAMD,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,IAAI,CAsBpH"}
|
package/dist/skinMeshGeometry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getMeshGeometryVertexJoints0, getMeshGeometryVertexWeights0 } from '@flighthq/mesh/contract';
|
|
2
|
-
import { skinVertices } from './skinVertices';
|
|
2
|
+
import { skinTangents, skinVertices } from './skinVertices';
|
|
3
3
|
// Captures the de-interleaved CPU-skinning inputs for one skinned MeshGeometry: the bind-pose
|
|
4
4
|
// positions/normals and the static joints0/weights0 influences, read out of the interleaved
|
|
5
5
|
// `geometry.vertices` through `geometry.layout` (any offsets, any layout carrying the four
|
|
@@ -15,6 +15,10 @@ export function captureMeshSkinBindPose(geometry) {
|
|
|
15
15
|
const normalOffset = floatOffsetForSemantic(layout, 'normal');
|
|
16
16
|
const positions = new Float32Array(vertexCount * 3);
|
|
17
17
|
const normals = new Float32Array(vertexCount * 3);
|
|
18
|
+
// Zero-length when the layout carries no tangent semantic, so the per-frame deform iterates nothing
|
|
19
|
+
// rather than blending meaningless zeros back into a channel the geometry does not have.
|
|
20
|
+
const tangentOffset = floatOffsetForSemantic(layout, 'tangent');
|
|
21
|
+
const tangents = new Float32Array(tangentOffset >= 0 ? vertexCount * 4 : 0);
|
|
18
22
|
const joints = new Float32Array(vertexCount * 4);
|
|
19
23
|
const weights = new Float32Array(vertexCount * 4);
|
|
20
24
|
const joint = { w: 0, x: 0, y: 0, z: 0 };
|
|
@@ -33,6 +37,13 @@ export function captureMeshSkinBindPose(geometry) {
|
|
|
33
37
|
normals[p + 1] = vertices[base + normalOffset + 1];
|
|
34
38
|
normals[p + 2] = vertices[base + normalOffset + 2];
|
|
35
39
|
}
|
|
40
|
+
if (tangentOffset >= 0) {
|
|
41
|
+
// All four floats: xyz is re-blended every frame, w is the handedness sign and rides along.
|
|
42
|
+
tangents[w] = vertices[base + tangentOffset];
|
|
43
|
+
tangents[w + 1] = vertices[base + tangentOffset + 1];
|
|
44
|
+
tangents[w + 2] = vertices[base + tangentOffset + 2];
|
|
45
|
+
tangents[w + 3] = vertices[base + tangentOffset + 3];
|
|
46
|
+
}
|
|
36
47
|
if (getMeshGeometryVertexJoints0(joint, geometry, v)) {
|
|
37
48
|
joints[w] = joint.x;
|
|
38
49
|
joints[w + 1] = joint.y;
|
|
@@ -52,6 +63,8 @@ export function captureMeshSkinBindPose(geometry) {
|
|
|
52
63
|
positions,
|
|
53
64
|
skinnedNormals: new Float32Array(vertexCount * 3),
|
|
54
65
|
skinnedPositions: new Float32Array(vertexCount * 3),
|
|
66
|
+
skinnedTangents: new Float32Array(tangents.length),
|
|
67
|
+
tangents,
|
|
55
68
|
weights,
|
|
56
69
|
};
|
|
57
70
|
}
|
|
@@ -63,12 +76,16 @@ export function captureMeshSkinBindPose(geometry) {
|
|
|
63
76
|
// so tangent/uv0/joints0/weights0 stay intact. Scene3D-free by design — the node-level glue that owns
|
|
64
77
|
// the runtime slot and drives the palette is updateMeshSkin, beside this file.
|
|
65
78
|
export function skinMeshGeometry(geometry, skeleton, bindPose) {
|
|
66
|
-
skinVertices(bindPose.skinnedPositions, bindPose.skinnedNormals, bindPose.positions, bindPose.normals, bindPose.joints, bindPose.weights, skeleton.jointMatrices);
|
|
79
|
+
skinVertices(bindPose.skinnedPositions, bindPose.skinnedNormals, bindPose.positions, bindPose.normals, bindPose.joints, bindPose.weights, skeleton.jointMatrices, skeleton.normalMatrices);
|
|
80
|
+
skinTangents(bindPose.skinnedTangents, bindPose.tangents, bindPose.joints, bindPose.weights, skeleton.jointMatrices);
|
|
67
81
|
const { layout, vertices } = geometry;
|
|
68
82
|
const floatsPerVertex = layout.stride / 4;
|
|
69
83
|
const positionOffset = floatOffsetForSemantic(layout, 'position');
|
|
70
84
|
const normalOffset = floatOffsetForSemantic(layout, 'normal');
|
|
71
|
-
|
|
85
|
+
// Skinned from the BIND POSE every frame, never from the vertices written last frame — re-skinning an
|
|
86
|
+
// already-skinned tangent would compound the pose instead of replacing it.
|
|
87
|
+
const tangentOffset = bindPose.tangents.length > 0 ? floatOffsetForSemantic(layout, 'tangent') : -1;
|
|
88
|
+
const { skinnedNormals, skinnedPositions, skinnedTangents } = bindPose;
|
|
72
89
|
const vertexCount = (skinnedPositions.length / 3) | 0;
|
|
73
90
|
for (let v = 0; v < vertexCount; v++) {
|
|
74
91
|
const base = v * floatsPerVertex;
|
|
@@ -83,6 +100,14 @@ export function skinMeshGeometry(geometry, skeleton, bindPose) {
|
|
|
83
100
|
vertices[base + normalOffset + 1] = skinnedNormals[s + 1];
|
|
84
101
|
vertices[base + normalOffset + 2] = skinnedNormals[s + 2];
|
|
85
102
|
}
|
|
103
|
+
if (tangentOffset >= 0) {
|
|
104
|
+
// Four floats: the blended direction, then the handedness sign exactly as it was captured.
|
|
105
|
+
const t = v * 4;
|
|
106
|
+
vertices[base + tangentOffset] = skinnedTangents[t];
|
|
107
|
+
vertices[base + tangentOffset + 1] = skinnedTangents[t + 1];
|
|
108
|
+
vertices[base + tangentOffset + 2] = skinnedTangents[t + 2];
|
|
109
|
+
vertices[base + tangentOffset + 3] = skinnedTangents[t + 3];
|
|
110
|
+
}
|
|
86
111
|
}
|
|
87
112
|
geometry.version++;
|
|
88
113
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skinMeshGeometry.js","sourceRoot":"","sources":["../src/skinMeshGeometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAGtG,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"skinMeshGeometry.js","sourceRoot":"","sources":["../src/skinMeshGeometry.ts"],"names":[],"mappings":"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"}
|
package/dist/skinVertices.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function skinTangents(outTangents: Float32Array, tangents: Readonly<Float32Array>, joints: Readonly<ArrayLike<number>>, weights: Readonly<Float32Array>, jointMatrices: Readonly<Float32Array>): void;
|
|
2
|
+
export declare function skinVertices(outPositions: Float32Array, outNormals: Float32Array, positions: Readonly<Float32Array>, normals: Readonly<Float32Array>, joints: Readonly<ArrayLike<number>>, weights: Readonly<Float32Array>, jointMatrices: Readonly<Float32Array>, normalMatrices: Readonly<Float32Array>): void;
|
|
2
3
|
//# sourceMappingURL=skinVertices.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skinVertices.d.ts","sourceRoot":"","sources":["../src/skinVertices.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skinVertices.d.ts","sourceRoot":"","sources":["../src/skinVertices.ts"],"names":[],"mappings":"AAkBA,wBAAgB,YAAY,CAC1B,WAAW,EAAE,YAAY,EACzB,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,EAChC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EACnC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC/B,aAAa,EAAE,QAAQ,CAAC,YAAY,CAAC,GACpC,IAAI,CAyCN;AAiBD,wBAAgB,YAAY,CAC1B,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,YAAY,EACxB,SAAS,EAAE,QAAQ,CAAC,YAAY,CAAC,EACjC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC/B,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EACnC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC/B,aAAa,EAAE,QAAQ,CAAC,YAAY,CAAC,EACrC,cAAc,EAAE,QAAQ,CAAC,YAAY,CAAC,GACrC,IAAI,CA8DN"}
|
package/dist/skinVertices.js
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
|
+
// Linear-blend-skins tangents by the same palette, 4 floats per vertex in and out.
|
|
2
|
+
//
|
|
3
|
+
// ★ `w` IS HANDEDNESS, NOT A COORDINATE, AND IS COPIED THROUGH UNTOUCHED. It records which way the
|
|
4
|
+
// bitangent runs (B = w * cross(N, T)), so it is a sign rather than a direction: rotating it with the
|
|
5
|
+
// vector, or re-deriving it after skinning, flips the bitangent across whole regions of the surface.
|
|
6
|
+
// That reaches the eye as inverted lighting rather than as a crash, so it is a defect that ships.
|
|
7
|
+
//
|
|
8
|
+
// ★ A TANGENT AND A NORMAL DELIBERATELY DIVERGE UNDER NON-UNIFORM SCALE, AND THAT IS NOT AN OVERSIGHT.
|
|
9
|
+
// A tangent is a TRUE VECTOR: it lies along the surface, so it follows the same matrix a position does —
|
|
10
|
+
// the plain upper 3x3 of each palette matrix, no translation, no renormalization. A normal is a
|
|
11
|
+
// COVECTOR: it is defined by being perpendicular to the surface, so it follows the inverse-transpose,
|
|
12
|
+
// which is why `skinVertices` reads the separate per-joint normal palette and this function does not.
|
|
13
|
+
// They coincide exactly for a rigid joint, which is why one shared transform looked correct for as long
|
|
14
|
+
// as it did. The two are still checked against each other, but only on RIGID input, where agreement is
|
|
15
|
+
// the right expectation.
|
|
16
|
+
//
|
|
17
|
+
// `outTangents` may alias `tangents`: each vertex's input is read into locals before any output is
|
|
18
|
+
// written. Not renormalized, matching the normal path — a caller needing unit tangents does that after.
|
|
19
|
+
export function skinTangents(outTangents, tangents, joints, weights, jointMatrices) {
|
|
20
|
+
const vertexCount = (tangents.length / 4) | 0;
|
|
21
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
22
|
+
const t = v * 4;
|
|
23
|
+
const tx = tangents[t];
|
|
24
|
+
const ty = tangents[t + 1];
|
|
25
|
+
const tz = tangents[t + 2];
|
|
26
|
+
const handedness = tangents[t + 3];
|
|
27
|
+
let otx = 0;
|
|
28
|
+
let oty = 0;
|
|
29
|
+
let otz = 0;
|
|
30
|
+
let influenced = false;
|
|
31
|
+
for (let k = 0; k < 4; k++) {
|
|
32
|
+
const weight = weights[t + k];
|
|
33
|
+
if (weight === 0)
|
|
34
|
+
continue;
|
|
35
|
+
influenced = true;
|
|
36
|
+
const m = joints[t + k] * 16;
|
|
37
|
+
const m0 = jointMatrices[m];
|
|
38
|
+
const m1 = jointMatrices[m + 1];
|
|
39
|
+
const m2 = jointMatrices[m + 2];
|
|
40
|
+
const m4 = jointMatrices[m + 4];
|
|
41
|
+
const m5 = jointMatrices[m + 5];
|
|
42
|
+
const m6 = jointMatrices[m + 6];
|
|
43
|
+
const m8 = jointMatrices[m + 8];
|
|
44
|
+
const m9 = jointMatrices[m + 9];
|
|
45
|
+
const m10 = jointMatrices[m + 10];
|
|
46
|
+
otx += weight * (m0 * tx + m4 * ty + m8 * tz);
|
|
47
|
+
oty += weight * (m1 * tx + m5 * ty + m9 * tz);
|
|
48
|
+
otz += weight * (m2 * tx + m6 * ty + m10 * tz);
|
|
49
|
+
}
|
|
50
|
+
// No influence means bind pose, not the origin — see the position path for the contract.
|
|
51
|
+
outTangents[t] = influenced ? otx : tx;
|
|
52
|
+
outTangents[t + 1] = influenced ? oty : ty;
|
|
53
|
+
outTangents[t + 2] = influenced ? otz : tz;
|
|
54
|
+
outTangents[t + 3] = handedness;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
1
57
|
// CPU linear-blend skinning (a.k.a. smooth/matrix-palette skinning). Deforms each vertex on the CPU by the
|
|
2
58
|
// weighted sum of its influencing joints' palette matrices — the same math a GPU vertex shader runs, kept
|
|
3
59
|
// here as a deterministic, GPU-free path for offscreen bakes, physics proxies, and jsdom tests.
|
|
@@ -13,7 +69,7 @@
|
|
|
13
69
|
// palette matrix's upper 3×3 only (no translation) and are NOT renormalized — callers that need unit
|
|
14
70
|
// normals (e.g. non-uniform scale in the palette) renormalize afterward. `out*` may alias `positions` /
|
|
15
71
|
// `normals`: each vertex's inputs are read into locals before any output is written.
|
|
16
|
-
export function skinVertices(outPositions, outNormals, positions, normals, joints, weights, jointMatrices) {
|
|
72
|
+
export function skinVertices(outPositions, outNormals, positions, normals, joints, weights, jointMatrices, normalMatrices) {
|
|
17
73
|
const vertexCount = (positions.length / 3) | 0;
|
|
18
74
|
for (let v = 0; v < vertexCount; v++) {
|
|
19
75
|
const p = v * 3;
|
|
@@ -29,11 +85,13 @@ export function skinVertices(outPositions, outNormals, positions, normals, joint
|
|
|
29
85
|
let onx = 0;
|
|
30
86
|
let ony = 0;
|
|
31
87
|
let onz = 0;
|
|
88
|
+
let influenced = false;
|
|
32
89
|
const w = v * 4;
|
|
33
90
|
for (let k = 0; k < 4; k++) {
|
|
34
91
|
const weight = weights[w + k];
|
|
35
92
|
if (weight === 0)
|
|
36
93
|
continue;
|
|
94
|
+
influenced = true;
|
|
37
95
|
const m = joints[w + k] * 16;
|
|
38
96
|
const m0 = jointMatrices[m];
|
|
39
97
|
const m1 = jointMatrices[m + 1];
|
|
@@ -47,16 +105,26 @@ export function skinVertices(outPositions, outNormals, positions, normals, joint
|
|
|
47
105
|
opx += weight * (m0 * px + m4 * py + m8 * pz + jointMatrices[m + 12]);
|
|
48
106
|
opy += weight * (m1 * px + m5 * py + m9 * pz + jointMatrices[m + 13]);
|
|
49
107
|
opz += weight * (m2 * px + m6 * py + m10 * pz + jointMatrices[m + 14]);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
108
|
+
// Normals use the joint's NORMAL matrix, not the joint matrix. A normal is a covector: under
|
|
109
|
+
// non-uniform scale it transforms by the inverse-transpose, and using the position matrix tilts
|
|
110
|
+
// it off the surface. The two coincide for a rigid joint, which is why this was invisible.
|
|
111
|
+
// Columns are padded to four floats each, so column c starts at n + c*4.
|
|
112
|
+
const n = joints[w + k] * 12;
|
|
113
|
+
onx += weight * (normalMatrices[n] * nx + normalMatrices[n + 4] * ny + normalMatrices[n + 8] * nz);
|
|
114
|
+
ony += weight * (normalMatrices[n + 1] * nx + normalMatrices[n + 5] * ny + normalMatrices[n + 9] * nz);
|
|
115
|
+
onz += weight * (normalMatrices[n + 2] * nx + normalMatrices[n + 6] * ny + normalMatrices[n + 10] * nz);
|
|
53
116
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
117
|
+
// A vertex with no influence stays at its BIND POSE. That is the packer's documented contract —
|
|
118
|
+
// packSkinInfluences says a vertex with no influence "keeps all weights zero (it stays at its bind
|
|
119
|
+
// position)" — and accumulating from zero instead collapsed it onto the origin with a zero normal.
|
|
120
|
+
// Not a rounding error: an unweighted vertex teleported to (0,0,0) and dragged its triangle with it,
|
|
121
|
+
// and the skin bounds computed from these positions inherited the collapse.
|
|
122
|
+
outPositions[p] = influenced ? opx : px;
|
|
123
|
+
outPositions[p + 1] = influenced ? opy : py;
|
|
124
|
+
outPositions[p + 2] = influenced ? opz : pz;
|
|
125
|
+
outNormals[p] = influenced ? onx : nx;
|
|
126
|
+
outNormals[p + 1] = influenced ? ony : ny;
|
|
127
|
+
outNormals[p + 2] = influenced ? onz : nz;
|
|
60
128
|
}
|
|
61
129
|
}
|
|
62
130
|
//# sourceMappingURL=skinVertices.js.map
|
package/dist/skinVertices.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skinVertices.js","sourceRoot":"","sources":["../src/skinVertices.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,0GAA0G;AAC1G,gGAAgG;AAChG,EAAE;AACF,uEAAuE;AACvE,8DAA8D;AAC9D,8DAA8D;AAC9D,yFAAyF;AACzF,iFAAiF;AACjF,mFAAmF;AACnF,EAAE;AACF,qGAAqG;AACrG,qGAAqG;AACrG,wGAAwG;AACxG,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAC1B,YAA0B,EAC1B,UAAwB,EACxB,SAAiC,EACjC,OAA+B,EAC/B,MAAmC,EACnC,OAA+B,EAC/B,aAAqC;
|
|
1
|
+
{"version":3,"file":"skinVertices.js","sourceRoot":"","sources":["../src/skinVertices.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/skeleton3d",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1-next.1041.35b950c",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,11 +38,12 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/entity": "0.3.
|
|
42
|
-
"@flighthq/geometry": "0.3.
|
|
43
|
-
"@flighthq/
|
|
44
|
-
"@flighthq/
|
|
45
|
-
"@flighthq/
|
|
41
|
+
"@flighthq/entity": "0.3.1-next.1041.35b950c",
|
|
42
|
+
"@flighthq/geometry": "0.3.1-next.1041.35b950c",
|
|
43
|
+
"@flighthq/log": "0.3.1-next.1041.35b950c",
|
|
44
|
+
"@flighthq/mesh": "0.3.1-next.1041.35b950c",
|
|
45
|
+
"@flighthq/node": "0.3.1-next.1041.35b950c",
|
|
46
|
+
"@flighthq/types": "0.3.1-next.1041.35b950c"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
49
|
"@flighthq/scene3d": "*",
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { setVector3 } from '@flighthq/geometry/contract';
|
|
2
|
+
import { setLogSink } from '@flighthq/log/contract';
|
|
3
|
+
import { invalidateNodeLocalTransform } from '@flighthq/node/contract';
|
|
4
|
+
import { createNode3D } from '@flighthq/scene3d/contract';
|
|
5
|
+
import type { LogEntry } from '@flighthq/types/contract';
|
|
6
|
+
import { afterEach, describe, expect, test } from 'vitest';
|
|
7
|
+
|
|
8
|
+
import { areSkeleton3DGuardsEnabled, disableSkeleton3DGuards, enableSkeleton3DGuards } from './enableSkeleton3DGuards';
|
|
9
|
+
import { createSkeleton3D, setSkeleton3DBindPose } from './skeleton3d';
|
|
10
|
+
|
|
11
|
+
describe('areSkeleton3DGuardsEnabled', () => {
|
|
12
|
+
test('reports whether the guards are installed', () => {
|
|
13
|
+
expect(areSkeleton3DGuardsEnabled()).toBe(false);
|
|
14
|
+
enableSkeleton3DGuards();
|
|
15
|
+
expect(areSkeleton3DGuardsEnabled()).toBe(true);
|
|
16
|
+
disableSkeleton3DGuards();
|
|
17
|
+
expect(areSkeleton3DGuardsEnabled()).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('disableSkeleton3DGuards', () => {
|
|
22
|
+
test('leaves the core silent again once removed', () => {
|
|
23
|
+
enableSkeleton3DGuards();
|
|
24
|
+
disableSkeleton3DGuards();
|
|
25
|
+
expect(captureLog(() => setSkeleton3DBindPose(collapsedSkeleton()))).toHaveLength(0);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('enableSkeleton3DGuards', () => {
|
|
30
|
+
// `logOnce` keys on the joint index and has no reset, so only ONE test may trigger a given index — a
|
|
31
|
+
// repeat would be deduplicated away and assert nothing while still looking green.
|
|
32
|
+
test('warns, naming the joint, when a bind pose cannot be captured', () => {
|
|
33
|
+
enableSkeleton3DGuards();
|
|
34
|
+
const entries = captureLog(() => setSkeleton3DBindPose(collapsedSkeleton()));
|
|
35
|
+
expect(entries).toHaveLength(1);
|
|
36
|
+
expect(entries[0].data).toMatchObject({ jointIndex: 0 });
|
|
37
|
+
expect(String((entries[0].data as { message: string }).message)).toContain('will not deform');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('stays silent for a rig whose joints all invert', () => {
|
|
41
|
+
enableSkeleton3DGuards();
|
|
42
|
+
expect(captureLog(() => setSkeleton3DBindPose(createSkeleton3D([createNode3D()])))).toHaveLength(0);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
disableSkeleton3DGuards();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
function captureLog(run: () => void): LogEntry[] {
|
|
51
|
+
const entries: LogEntry[] = [];
|
|
52
|
+
setLogSink((entry) => entries.push(entry));
|
|
53
|
+
try {
|
|
54
|
+
run();
|
|
55
|
+
} finally {
|
|
56
|
+
setLogSink(null);
|
|
57
|
+
}
|
|
58
|
+
return entries;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function collapsedSkeleton(): ReturnType<typeof createSkeleton3D> {
|
|
62
|
+
const collapsed = createNode3D();
|
|
63
|
+
setVector3(collapsed.scale, 0, 0, 0);
|
|
64
|
+
invalidateNodeLocalTransform(collapsed);
|
|
65
|
+
return createSkeleton3D([collapsed]);
|
|
66
|
+
}
|
|
@@ -40,6 +40,8 @@ function bindPoseFor(positions: number[], jointIndices: number[]): MeshSkinBindP
|
|
|
40
40
|
positions: new Float32Array(positions),
|
|
41
41
|
skinnedNormals: new Float32Array(count * 3),
|
|
42
42
|
skinnedPositions: new Float32Array(count * 3),
|
|
43
|
+
skinnedTangents: new Float32Array(0),
|
|
44
|
+
tangents: new Float32Array(0),
|
|
43
45
|
weights,
|
|
44
46
|
};
|
|
45
47
|
}
|
|
@@ -48,6 +50,7 @@ function skeletonFor(palette: number[]): Skeleton3D {
|
|
|
48
50
|
return createEntity({
|
|
49
51
|
inverseBindMatrices: new Float32Array(palette.length),
|
|
50
52
|
jointMatrices: new Float32Array(palette),
|
|
53
|
+
normalMatrices: new Float32Array(0),
|
|
51
54
|
joints: [],
|
|
52
55
|
});
|
|
53
56
|
}
|
package/src/skeleton3d.test.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getSkeleton3DJointWorldMatrix,
|
|
15
15
|
getSkeleton3DJointWorldMatrixByName,
|
|
16
16
|
setSkeleton3DBindPose,
|
|
17
|
+
setSkeleton3DBindPoseGuard,
|
|
17
18
|
validateSkeleton3D,
|
|
18
19
|
} from './skeleton3d';
|
|
19
20
|
|
|
@@ -162,6 +163,31 @@ describe('computeSkeleton3DJointMatrices', () => {
|
|
|
162
163
|
});
|
|
163
164
|
});
|
|
164
165
|
|
|
166
|
+
describe('computeSkeleton3DJointMatrices normal palette', () => {
|
|
167
|
+
// ★ THIS COVERS THE FILL, WHICH NOTHING ELSE DID. The skinning tests build palettes directly, so they
|
|
168
|
+
// are structurally blind to whether this function writes the layout the shader and the CPU both read.
|
|
169
|
+
// A mutation that wrote the columns tightly instead of padded passed the entire suite until this
|
|
170
|
+
// existed — the same "a unit test of the callee says nothing about the caller" gap as elsewhere.
|
|
171
|
+
it('writes each joint as three vec4-padded columns, twelve floats apart', () => {
|
|
172
|
+
const joint = createNode3D();
|
|
173
|
+
// The bind pose is captured at construction, so the scale must be applied AFTER it — otherwise the
|
|
174
|
+
// joint matrix is world times inverse-world, the identity, and the palette says nothing.
|
|
175
|
+
const skeleton = createSkeleton3D([joint]);
|
|
176
|
+
setVector3(joint.scale, 2, 1, 1);
|
|
177
|
+
invalidateNodeLocalTransform(joint);
|
|
178
|
+
computeSkeleton3DJointMatrices(skeleton);
|
|
179
|
+
|
|
180
|
+
expect(skeleton.normalMatrices.length).toBe(12);
|
|
181
|
+
// A 2x stretch in x gives a normal matrix scaling x by 1/2 — the inverse-transpose, not the matrix.
|
|
182
|
+
expect(skeleton.normalMatrices[0]).toBeCloseTo(0.5);
|
|
183
|
+
// Column 1 starts at float 4, not float 3. If the stride were tight this would hold the y column's
|
|
184
|
+
// first element at index 3 and this assertion would read padding instead.
|
|
185
|
+
expect(skeleton.normalMatrices[3]).toBe(0);
|
|
186
|
+
expect(skeleton.normalMatrices[5]).toBeCloseTo(1);
|
|
187
|
+
expect(skeleton.normalMatrices[10]).toBeCloseTo(1);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
165
191
|
describe('createSkeleton3D', () => {
|
|
166
192
|
it('allocates a palette sized to the joint count when no inverse-bind is given', () => {
|
|
167
193
|
const skeleton = createSkeleton3D([createNode3D(), createNode3D()]);
|
|
@@ -259,6 +285,29 @@ describe('getSkeleton3DJointWorldMatrixByName', () => {
|
|
|
259
285
|
});
|
|
260
286
|
|
|
261
287
|
describe('setSkeleton3DBindPose', () => {
|
|
288
|
+
// A zero-scale joint makes its world matrix singular. Writing the failed inverse puts NaN in the
|
|
289
|
+
// palette, which reaches the skinned vertices silently; identity costs that one joint its bind pose
|
|
290
|
+
// and leaves every other joint working — the AWD2 recovery, applied per joint.
|
|
291
|
+
it('substitutes identity for a joint with no invertible world matrix, leaving the rest of the rig', () => {
|
|
292
|
+
const collapsed = createNode3D();
|
|
293
|
+
const healthy = createNode3D();
|
|
294
|
+
const skeleton = createSkeleton3D([collapsed, healthy]);
|
|
295
|
+
setVector3(collapsed.scale, 0, 0, 0);
|
|
296
|
+
setVector3(healthy.position, 3, 0, 0);
|
|
297
|
+
invalidateNodeLocalTransform(collapsed);
|
|
298
|
+
invalidateNodeLocalTransform(healthy);
|
|
299
|
+
|
|
300
|
+
setSkeleton3DBindPose(skeleton);
|
|
301
|
+
|
|
302
|
+
for (const value of skeleton.inverseBindMatrices) expect(Number.isFinite(value)).toBe(true);
|
|
303
|
+
// The collapsed joint got identity...
|
|
304
|
+
expect(Array.from(skeleton.inverseBindMatrices.slice(0, 16))).toEqual([
|
|
305
|
+
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
|
306
|
+
]);
|
|
307
|
+
// ...and the healthy joint still got its real inverse bind.
|
|
308
|
+
expect(skeleton.inverseBindMatrices[28]).toBeCloseTo(-3);
|
|
309
|
+
});
|
|
310
|
+
|
|
262
311
|
it('rebinds so the current pose becomes the rest pose', () => {
|
|
263
312
|
const joint = createNode3D();
|
|
264
313
|
const skeleton = createSkeleton3D([joint]);
|
|
@@ -272,6 +321,25 @@ describe('setSkeleton3DBindPose', () => {
|
|
|
272
321
|
});
|
|
273
322
|
});
|
|
274
323
|
|
|
324
|
+
describe('setSkeleton3DBindPoseGuard', () => {
|
|
325
|
+
it('is notified for the degenerate joint only', () => {
|
|
326
|
+
const seen: number[] = [];
|
|
327
|
+
setSkeleton3DBindPoseGuard((_skeleton, jointIndex) => seen.push(jointIndex));
|
|
328
|
+
try {
|
|
329
|
+
const collapsed = createNode3D();
|
|
330
|
+
const healthy = createNode3D();
|
|
331
|
+
const skeleton = createSkeleton3D([healthy, collapsed]);
|
|
332
|
+
setVector3(collapsed.scale, 0, 0, 0);
|
|
333
|
+
invalidateNodeLocalTransform(collapsed);
|
|
334
|
+
invalidateNodeLocalTransform(healthy);
|
|
335
|
+
setSkeleton3DBindPose(skeleton);
|
|
336
|
+
expect(seen).toEqual([1]);
|
|
337
|
+
} finally {
|
|
338
|
+
setSkeleton3DBindPoseGuard(null);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
275
343
|
describe('validateSkeleton3D', () => {
|
|
276
344
|
it('returns null for a well-formed skeleton', () => {
|
|
277
345
|
expect(validateSkeleton3D(createSkeleton3D([createNode3D(), createNode3D()]))).toBeNull();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setVector3 } from '@flighthq/geometry/contract';
|
|
1
|
+
import { setQuaternion, setVector3 } from '@flighthq/geometry/contract';
|
|
2
2
|
import { CANONICAL_SKINNED_MESH_GEOMETRY_LAYOUT, createMeshGeometry } from '@flighthq/mesh/contract';
|
|
3
3
|
import { invalidateNodeLocalTransform } from '@flighthq/node/contract';
|
|
4
4
|
import { createNode3D } from '@flighthq/scene3d/contract';
|
|
@@ -15,6 +15,7 @@ function createOneVertexSkinnedGeometry(
|
|
|
15
15
|
normal: readonly [number, number, number],
|
|
16
16
|
joints: readonly [number, number, number, number],
|
|
17
17
|
weights: readonly [number, number, number, number],
|
|
18
|
+
tangent: readonly [number, number, number, number] = [0, 0, 0, 0],
|
|
18
19
|
): MeshGeometry {
|
|
19
20
|
const vertices = new Float32Array(20);
|
|
20
21
|
vertices[0] = position[0];
|
|
@@ -23,6 +24,7 @@ function createOneVertexSkinnedGeometry(
|
|
|
23
24
|
vertices[3] = normal[0];
|
|
24
25
|
vertices[4] = normal[1];
|
|
25
26
|
vertices[5] = normal[2];
|
|
27
|
+
vertices.set(tangent, 6);
|
|
26
28
|
vertices.set(joints, 12);
|
|
27
29
|
vertices.set(weights, 16);
|
|
28
30
|
return createMeshGeometry({ layout: CANONICAL_SKINNED_MESH_GEOMETRY_LAYOUT, vertices });
|
|
@@ -110,6 +112,57 @@ describe('skinMeshGeometry', () => {
|
|
|
110
112
|
expect(geometry.vertices[4]).toBeCloseTo(1);
|
|
111
113
|
expect(geometry.vertices[16]).toBe(1);
|
|
112
114
|
});
|
|
115
|
+
|
|
116
|
+
it('rewrites the tangent channel in the geometry, not just the scratch', () => {
|
|
117
|
+
// ★ THIS IS THE ONE THAT CATCHES A MISSING WRITE-BACK. Every unit test of the blend itself passes
|
|
118
|
+
// while `skinMeshGeometry` never copies the result into `geometry.vertices`, because those tests
|
|
119
|
+
// call the blend directly. Only reading the interleaved buffer after a skin proves the channel was
|
|
120
|
+
// actually updated. A rotation is required to see it: under a translation a correct tangent and an
|
|
121
|
+
// un-skinned one are identical, so the assertion could not fail.
|
|
122
|
+
const geometry = createOneVertexSkinnedGeometry([1, 0, 0], [0, 1, 0], [0, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, -1]);
|
|
123
|
+
const joint = createNode3D();
|
|
124
|
+
const skeleton = createSkeleton3D([joint]);
|
|
125
|
+
const bindPose = captureMeshSkinBindPose(geometry);
|
|
126
|
+
// 90 degrees about Z.
|
|
127
|
+
setQuaternion(joint.rotation, 0, 0, Math.SQRT1_2, Math.SQRT1_2);
|
|
128
|
+
invalidateNodeLocalTransform(joint);
|
|
129
|
+
|
|
130
|
+
computeSkeleton3DJointMatrices(skeleton);
|
|
131
|
+
skinMeshGeometry(geometry, skeleton, bindPose);
|
|
132
|
+
|
|
133
|
+
// Tangent occupies floats 6..9: x rotates onto +y.
|
|
134
|
+
expect(geometry.vertices[6]).toBeCloseTo(0);
|
|
135
|
+
expect(geometry.vertices[7]).toBeCloseTo(1);
|
|
136
|
+
expect(geometry.vertices[8]).toBeCloseTo(0);
|
|
137
|
+
// w is handedness and must survive untouched, including the negative sign.
|
|
138
|
+
expect(geometry.vertices[9]).toBe(-1);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('keeps the skinned tangent orthogonal to the skinned normal', () => {
|
|
142
|
+
// The user-visible defect: normal skinned, tangent frozen at bind pose, so N·T drifted off zero in
|
|
143
|
+
// every pose away from bind. Read back from the interleaved buffer, which is what the shader sees.
|
|
144
|
+
const geometry = createOneVertexSkinnedGeometry([1, 0, 0], [0, 1, 0], [0, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 1]);
|
|
145
|
+
const joint = createNode3D();
|
|
146
|
+
const skeleton = createSkeleton3D([joint]);
|
|
147
|
+
const bindPose = captureMeshSkinBindPose(geometry);
|
|
148
|
+
setQuaternion(joint.rotation, 0, 0, Math.SQRT1_2, Math.SQRT1_2);
|
|
149
|
+
invalidateNodeLocalTransform(joint);
|
|
150
|
+
|
|
151
|
+
computeSkeleton3DJointMatrices(skeleton);
|
|
152
|
+
skinMeshGeometry(geometry, skeleton, bindPose);
|
|
153
|
+
|
|
154
|
+
// ★ NON-DEGENERACY FIRST. A zero tangent is orthogonal to everything, so the dot product below
|
|
155
|
+
// passes trivially on an un-skinned or unwritten channel — which it did, while the write-back was
|
|
156
|
+
// in fact missing. Requiring a real length is what makes the orthogonality assertion mean anything.
|
|
157
|
+
const length = Math.hypot(geometry.vertices[6], geometry.vertices[7], geometry.vertices[8]);
|
|
158
|
+
expect(length).toBeCloseTo(1);
|
|
159
|
+
|
|
160
|
+
const dot =
|
|
161
|
+
geometry.vertices[3] * geometry.vertices[6] +
|
|
162
|
+
geometry.vertices[4] * geometry.vertices[7] +
|
|
163
|
+
geometry.vertices[5] * geometry.vertices[8];
|
|
164
|
+
expect(dot).toBeCloseTo(0);
|
|
165
|
+
});
|
|
113
166
|
});
|
|
114
167
|
|
|
115
168
|
describe('updateMeshSkinBindPoseDeformInput', () => {
|
package/src/skinVertices.test.ts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createMatrix3, createMatrix4, setMatrix3NormalFromMatrix4 } from '@flighthq/geometry/contract';
|
|
2
|
+
|
|
3
|
+
import { skinTangents, skinVertices } from './skinVertices';
|
|
4
|
+
|
|
5
|
+
// The normal palette a real pose would carry: the inverse-transpose of each joint's upper 3x3. Derived
|
|
6
|
+
// here rather than hand-written so a test cannot accidentally assert against a palette that no pose
|
|
7
|
+
// could produce.
|
|
8
|
+
function normalPaletteFor(jointMatrices: readonly number[]): Float32Array {
|
|
9
|
+
const count = (jointMatrices.length / 16) | 0;
|
|
10
|
+
const out = new Float32Array(count * 12);
|
|
11
|
+
for (let j = 0; j < count; j += 1) {
|
|
12
|
+
const source = createMatrix4();
|
|
13
|
+
source.m.set(jointMatrices.slice(j * 16, j * 16 + 16));
|
|
14
|
+
const normal = createMatrix3();
|
|
15
|
+
setMatrix3NormalFromMatrix4(normal, source);
|
|
16
|
+
for (let c = 0; c < 3; c += 1) {
|
|
17
|
+
out[j * 12 + c * 4] = normal.m[c * 3]!;
|
|
18
|
+
out[j * 12 + c * 4 + 1] = normal.m[c * 3 + 1]!;
|
|
19
|
+
out[j * 12 + c * 4 + 2] = normal.m[c * 3 + 2]!;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
2
24
|
|
|
3
25
|
// A column-major 4x4 identity, then variants with translation/scale, laid out as the 16-float palette entry.
|
|
4
26
|
function identity(): number[] {
|
|
@@ -19,7 +41,165 @@ function translation(tx: number, ty: number, tz: number): number[] {
|
|
|
19
41
|
return m;
|
|
20
42
|
}
|
|
21
43
|
|
|
44
|
+
describe('skinTangents', () => {
|
|
45
|
+
// Same contract as the position path: no influence means bind pose. A zero tangent collapses the
|
|
46
|
+
// TBN basis the shader reconstructs the bitangent from.
|
|
47
|
+
it('leaves an uninfluenced tangent at its bind pose rather than zero', () => {
|
|
48
|
+
const tangents = new Float32Array([1, 0, 0, -1]);
|
|
49
|
+
const joints = new Uint16Array([0, 0, 0, 0]);
|
|
50
|
+
const weights = new Float32Array([0, 0, 0, 0]);
|
|
51
|
+
const palette = new Float32Array(identity());
|
|
52
|
+
palette[0] = 9;
|
|
53
|
+
const out = new Float32Array(4);
|
|
54
|
+
|
|
55
|
+
skinTangents(out, tangents, joints, weights, palette);
|
|
56
|
+
|
|
57
|
+
expect(Array.from(out)).toEqual([1, 0, 0, -1]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// A 90-degree rotation about Z, column-major. A pure rotation is used deliberately: N·T = 0 survives
|
|
61
|
+
// skinning exactly only under a rigid transform, where transforming the tangent as a vector by M and
|
|
62
|
+
// the normal as a covector by M⁻ᵀ coincide. Under non-uniform scale they diverge and orthogonality is
|
|
63
|
+
// not something this code promises, so it is not asserted there.
|
|
64
|
+
// prettier-ignore
|
|
65
|
+
const rotateZ90 = [
|
|
66
|
+
0, 1, 0, 0,
|
|
67
|
+
-1, 0, 0, 0,
|
|
68
|
+
0, 0, 1, 0,
|
|
69
|
+
0, 0, 0, 1,
|
|
70
|
+
];
|
|
71
|
+
const singleJoint = { joints: new Float32Array([0, 0, 0, 0]), weights: new Float32Array([1, 0, 0, 0]) };
|
|
72
|
+
|
|
73
|
+
it('rotates the tangent direction with the pose', () => {
|
|
74
|
+
const tangents = new Float32Array([1, 0, 0, 1]);
|
|
75
|
+
const out = new Float32Array(4);
|
|
76
|
+
skinTangents(out, tangents, singleJoint.joints, singleJoint.weights, new Float32Array(rotateZ90));
|
|
77
|
+
expect(out[0]).toBeCloseTo(0);
|
|
78
|
+
expect(out[1]).toBeCloseTo(1);
|
|
79
|
+
expect(out[2]).toBeCloseTo(0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('carries w through UNCHANGED, because it is handedness and not a coordinate', () => {
|
|
83
|
+
// Rotating or re-deriving w flips the bitangent across whole regions of the surface, which reaches
|
|
84
|
+
// the eye as inverted lighting rather than as a crash. Both signs are checked: a transform that
|
|
85
|
+
// happened to preserve +1 could still destroy -1.
|
|
86
|
+
const positive = new Float32Array(4);
|
|
87
|
+
const negative = new Float32Array(4);
|
|
88
|
+
skinTangents(
|
|
89
|
+
positive,
|
|
90
|
+
new Float32Array([1, 0, 0, 1]),
|
|
91
|
+
singleJoint.joints,
|
|
92
|
+
singleJoint.weights,
|
|
93
|
+
new Float32Array(rotateZ90),
|
|
94
|
+
);
|
|
95
|
+
skinTangents(
|
|
96
|
+
negative,
|
|
97
|
+
new Float32Array([1, 0, 0, -1]),
|
|
98
|
+
singleJoint.joints,
|
|
99
|
+
singleJoint.weights,
|
|
100
|
+
new Float32Array(rotateZ90),
|
|
101
|
+
);
|
|
102
|
+
expect(positive[3]).toBe(1);
|
|
103
|
+
expect(negative[3]).toBe(-1);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('keeps the tangent orthogonal to the normal it was orthogonal to', () => {
|
|
107
|
+
// The defect this fixes: the normal was skinned and the tangent was not, so N·T drifted away from
|
|
108
|
+
// zero in any pose off the bind pose. Starting orthogonal, they must stay orthogonal under a rotation.
|
|
109
|
+
const palette = new Float32Array(rotateZ90);
|
|
110
|
+
const outNormals = new Float32Array(3);
|
|
111
|
+
const outTangents = new Float32Array(4);
|
|
112
|
+
skinVertices(
|
|
113
|
+
new Float32Array(3),
|
|
114
|
+
outNormals,
|
|
115
|
+
new Float32Array([0, 0, 0]),
|
|
116
|
+
new Float32Array([0, 1, 0]),
|
|
117
|
+
singleJoint.joints,
|
|
118
|
+
singleJoint.weights,
|
|
119
|
+
palette,
|
|
120
|
+
normalPaletteFor([...palette]),
|
|
121
|
+
);
|
|
122
|
+
skinTangents(outTangents, new Float32Array([1, 0, 0, 1]), singleJoint.joints, singleJoint.weights, palette);
|
|
123
|
+
const dot = outNormals[0] * outTangents[0] + outNormals[1] * outTangents[1] + outNormals[2] * outTangents[2];
|
|
124
|
+
expect(dot).toBeCloseTo(0);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('applies the same transform skinVertices applies to normals FOR A RIGID JOINT', () => {
|
|
128
|
+
// ★ NARROWED 2026-08-10, AND THE NARROWING IS THE POINT. This began as a blanket anti-divergence
|
|
129
|
+
// guard, written when normals and tangents shared one transform. They no longer do: a normal is a
|
|
130
|
+
// covector and now follows the per-joint inverse-transpose, while a tangent is a true vector and
|
|
131
|
+
// still follows the plain matrix. Under non-uniform scale they SHOULD disagree, so asserting
|
|
132
|
+
// equality there would now be asserting the bug back into existence. For a RIGID joint the two
|
|
133
|
+
// matrices coincide, so agreement remains the right expectation and the guard still catches an
|
|
134
|
+
// accidental divergence in the case that covers almost all authored content.
|
|
135
|
+
const palette = new Float32Array(rotateZ90);
|
|
136
|
+
const vector = [0.3, -0.7, 0.5];
|
|
137
|
+
const outNormals = new Float32Array(3);
|
|
138
|
+
const outTangents = new Float32Array(4);
|
|
139
|
+
skinVertices(
|
|
140
|
+
new Float32Array(3),
|
|
141
|
+
outNormals,
|
|
142
|
+
new Float32Array([0, 0, 0]),
|
|
143
|
+
new Float32Array(vector),
|
|
144
|
+
singleJoint.joints,
|
|
145
|
+
singleJoint.weights,
|
|
146
|
+
palette,
|
|
147
|
+
normalPaletteFor([...palette]),
|
|
148
|
+
);
|
|
149
|
+
skinTangents(outTangents, new Float32Array([...vector, 1]), singleJoint.joints, singleJoint.weights, palette);
|
|
150
|
+
expect(outTangents[0]).toBeCloseTo(outNormals[0]);
|
|
151
|
+
expect(outTangents[1]).toBeCloseTo(outNormals[1]);
|
|
152
|
+
expect(outTangents[2]).toBeCloseTo(outNormals[2]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('is safe when the output aliases the input', () => {
|
|
156
|
+
const tangents = new Float32Array([1, 0, 0, -1]);
|
|
157
|
+
skinTangents(tangents, tangents, singleJoint.joints, singleJoint.weights, new Float32Array(rotateZ90));
|
|
158
|
+
expect(tangents[1]).toBeCloseTo(1);
|
|
159
|
+
expect(tangents[3]).toBe(-1);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('iterates nothing when the geometry carries no tangent channel', () => {
|
|
163
|
+
// A zero-length capture is how "this layout has no tangents" is expressed, so it must be a no-op
|
|
164
|
+
// rather than an out-of-range read.
|
|
165
|
+
const out = new Float32Array(0);
|
|
166
|
+
expect(() =>
|
|
167
|
+
skinTangents(out, new Float32Array(0), singleJoint.joints, singleJoint.weights, new Float32Array(rotateZ90)),
|
|
168
|
+
).not.toThrow();
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
22
172
|
describe('skinVertices', () => {
|
|
173
|
+
// packSkinInfluences documents that a vertex with no influence "keeps all weights zero (it stays at
|
|
174
|
+
// its bind position)". Accumulating the weighted sum from zero instead collapsed such a vertex onto
|
|
175
|
+
// the ORIGIN with a zero normal — it teleported and dragged its triangle with it, and the skin bounds
|
|
176
|
+
// computed from these positions inherited the collapse. The palette here is a translation, so a
|
|
177
|
+
// bind-pose pass-through and a "moved by the joint" answer cannot be confused.
|
|
178
|
+
it('leaves an uninfluenced vertex at its bind pose rather than the origin', () => {
|
|
179
|
+
const positions = new Float32Array([5, 6, 7]);
|
|
180
|
+
const normals = new Float32Array([0, 1, 0]);
|
|
181
|
+
const joints = new Uint16Array([0, 0, 0, 0]);
|
|
182
|
+
const weights = new Float32Array([0, 0, 0, 0]);
|
|
183
|
+
const palette = new Float32Array(identity());
|
|
184
|
+
palette[12] = 100;
|
|
185
|
+
const outPositions = new Float32Array(3);
|
|
186
|
+
const outNormals = new Float32Array(3);
|
|
187
|
+
|
|
188
|
+
skinVertices(
|
|
189
|
+
outPositions,
|
|
190
|
+
outNormals,
|
|
191
|
+
positions,
|
|
192
|
+
normals,
|
|
193
|
+
joints,
|
|
194
|
+
weights,
|
|
195
|
+
palette,
|
|
196
|
+
normalPaletteFor([...palette]),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(Array.from(outPositions)).toEqual([5, 6, 7]);
|
|
200
|
+
expect(Array.from(outNormals)).toEqual([0, 1, 0]);
|
|
201
|
+
});
|
|
202
|
+
|
|
23
203
|
it('passes vertices through unchanged when the only weighted joint is identity', () => {
|
|
24
204
|
const positions = new Float32Array([2, 3, 4]);
|
|
25
205
|
const normals = new Float32Array([0, 1, 0]);
|
|
@@ -29,7 +209,16 @@ describe('skinVertices', () => {
|
|
|
29
209
|
const outPositions = new Float32Array(3);
|
|
30
210
|
const outNormals = new Float32Array(3);
|
|
31
211
|
|
|
32
|
-
skinVertices(
|
|
212
|
+
skinVertices(
|
|
213
|
+
outPositions,
|
|
214
|
+
outNormals,
|
|
215
|
+
positions,
|
|
216
|
+
normals,
|
|
217
|
+
joints,
|
|
218
|
+
weights,
|
|
219
|
+
palette,
|
|
220
|
+
normalPaletteFor([...palette]),
|
|
221
|
+
);
|
|
33
222
|
|
|
34
223
|
expect(Array.from(outPositions)).toEqual([2, 3, 4]);
|
|
35
224
|
expect(Array.from(outNormals)).toEqual([0, 1, 0]);
|
|
@@ -44,7 +233,16 @@ describe('skinVertices', () => {
|
|
|
44
233
|
const outPositions = new Float32Array(3);
|
|
45
234
|
const outNormals = new Float32Array(3);
|
|
46
235
|
|
|
47
|
-
skinVertices(
|
|
236
|
+
skinVertices(
|
|
237
|
+
outPositions,
|
|
238
|
+
outNormals,
|
|
239
|
+
positions,
|
|
240
|
+
normals,
|
|
241
|
+
joints,
|
|
242
|
+
weights,
|
|
243
|
+
palette,
|
|
244
|
+
normalPaletteFor([...palette]),
|
|
245
|
+
);
|
|
48
246
|
|
|
49
247
|
expect(outPositions[0]).toBeCloseTo(11);
|
|
50
248
|
expect(outPositions[1]).toBeCloseTo(20);
|
|
@@ -66,7 +264,16 @@ describe('skinVertices', () => {
|
|
|
66
264
|
const outPositions = new Float32Array(3);
|
|
67
265
|
const outNormals = new Float32Array(3);
|
|
68
266
|
|
|
69
|
-
skinVertices(
|
|
267
|
+
skinVertices(
|
|
268
|
+
outPositions,
|
|
269
|
+
outNormals,
|
|
270
|
+
positions,
|
|
271
|
+
normals,
|
|
272
|
+
joints,
|
|
273
|
+
weights,
|
|
274
|
+
palette,
|
|
275
|
+
normalPaletteFor([...palette]),
|
|
276
|
+
);
|
|
70
277
|
|
|
71
278
|
// 0.25 * (10,0,0) + 0.75 * (0,10,0) = (2.5, 7.5, 0)
|
|
72
279
|
expect(outPositions[0]).toBeCloseTo(2.5);
|
|
@@ -83,7 +290,16 @@ describe('skinVertices', () => {
|
|
|
83
290
|
const outPositions = new Float32Array(6);
|
|
84
291
|
const outNormals = new Float32Array(6);
|
|
85
292
|
|
|
86
|
-
skinVertices(
|
|
293
|
+
skinVertices(
|
|
294
|
+
outPositions,
|
|
295
|
+
outNormals,
|
|
296
|
+
positions,
|
|
297
|
+
normals,
|
|
298
|
+
joints,
|
|
299
|
+
weights,
|
|
300
|
+
palette,
|
|
301
|
+
normalPaletteFor([...palette]),
|
|
302
|
+
);
|
|
87
303
|
|
|
88
304
|
expect(Array.from(outPositions)).toEqual([6, 0, 0, 5, 1, 0]);
|
|
89
305
|
});
|
|
@@ -95,8 +311,83 @@ describe('skinVertices', () => {
|
|
|
95
311
|
const weights = new Float32Array([1, 0, 0, 0]);
|
|
96
312
|
const palette = new Float32Array(translation(1, 1, 1));
|
|
97
313
|
|
|
98
|
-
skinVertices(positions, normals, positions, normals, joints, weights, palette);
|
|
314
|
+
skinVertices(positions, normals, positions, normals, joints, weights, palette, normalPaletteFor([...palette]));
|
|
99
315
|
|
|
100
316
|
expect(Array.from(positions)).toEqual([2, 3, 4]);
|
|
101
317
|
});
|
|
102
318
|
});
|
|
319
|
+
|
|
320
|
+
describe('skinVertices covector normals', () => {
|
|
321
|
+
const singleJoint = { joints: new Float32Array([0, 0, 0, 0]), weights: new Float32Array([1, 0, 0, 0]) };
|
|
322
|
+
// Non-uniform scale: 2x along x, 1x along y. A plane's normal must NOT follow this the way a position
|
|
323
|
+
// does — stretching a surface along x makes its normal lean the OTHER way.
|
|
324
|
+
// prettier-ignore
|
|
325
|
+
const scaleX2 = [
|
|
326
|
+
2, 0, 0, 0,
|
|
327
|
+
0, 1, 0, 0,
|
|
328
|
+
0, 0, 1, 0,
|
|
329
|
+
0, 0, 0, 1,
|
|
330
|
+
];
|
|
331
|
+
|
|
332
|
+
it('leans a normal AGAINST a non-uniform stretch, not with it', () => {
|
|
333
|
+
// ★ THE DEFECT THIS FIXES. A 45-degree normal on a surface stretched 2x in x must come out with its
|
|
334
|
+
// x component HALVED relative to y (the inverse-transpose), not DOUBLED (the position matrix). The
|
|
335
|
+
// two answers differ by a factor of four in the ratio, so this cannot pass by accident.
|
|
336
|
+
const palette = new Float32Array(scaleX2);
|
|
337
|
+
const out = new Float32Array(3);
|
|
338
|
+
skinVertices(
|
|
339
|
+
new Float32Array(3),
|
|
340
|
+
out,
|
|
341
|
+
new Float32Array([0, 0, 0]),
|
|
342
|
+
new Float32Array([1, 1, 0]),
|
|
343
|
+
singleJoint.joints,
|
|
344
|
+
singleJoint.weights,
|
|
345
|
+
palette,
|
|
346
|
+
normalPaletteFor(scaleX2),
|
|
347
|
+
);
|
|
348
|
+
expect(out[0] / out[1]).toBeCloseTo(0.5);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('leaves a RIGID joint bit-for-bit unchanged, which is what protects existing content', () => {
|
|
352
|
+
// ★ THE HALF THAT MATTERS MOST. For rotation+translation the inverse-transpose EQUALS the matrix in
|
|
353
|
+
// exact arithmetic — but it is computed via an inverse and a transpose in floating point, so it need
|
|
354
|
+
// not agree BIT-FOR-BIT. MD5 and most authored content is rigid, so any drift here would perturb
|
|
355
|
+
// every skinned scene in the repo for no benefit. Compared with toBe, not toBeCloseTo, deliberately:
|
|
356
|
+
// "close enough" is exactly the answer that would let a few ULPs through unnoticed.
|
|
357
|
+
// prettier-ignore
|
|
358
|
+
const rigid = [
|
|
359
|
+
0, 1, 0, 0,
|
|
360
|
+
-1, 0, 0, 0,
|
|
361
|
+
0, 0, 1, 0,
|
|
362
|
+
3, 4, 5, 1,
|
|
363
|
+
];
|
|
364
|
+
const palette = new Float32Array(rigid);
|
|
365
|
+
const viaNormalPalette = new Float32Array(3);
|
|
366
|
+
const viaJointMatrix = new Float32Array(3);
|
|
367
|
+
const normal = new Float32Array([0.3, -0.7, 0.5]);
|
|
368
|
+
skinVertices(
|
|
369
|
+
new Float32Array(3),
|
|
370
|
+
viaNormalPalette,
|
|
371
|
+
new Float32Array(3),
|
|
372
|
+
normal,
|
|
373
|
+
singleJoint.joints,
|
|
374
|
+
singleJoint.weights,
|
|
375
|
+
palette,
|
|
376
|
+
normalPaletteFor(rigid),
|
|
377
|
+
);
|
|
378
|
+
// The pre-fix behaviour: the joint matrix used as its own normal matrix.
|
|
379
|
+
skinVertices(
|
|
380
|
+
new Float32Array(3),
|
|
381
|
+
viaJointMatrix,
|
|
382
|
+
new Float32Array(3),
|
|
383
|
+
normal,
|
|
384
|
+
singleJoint.joints,
|
|
385
|
+
singleJoint.weights,
|
|
386
|
+
palette,
|
|
387
|
+
new Float32Array([0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0]),
|
|
388
|
+
);
|
|
389
|
+
expect(viaNormalPalette[0]).toBe(viaJointMatrix[0]);
|
|
390
|
+
expect(viaNormalPalette[1]).toBe(viaJointMatrix[1]);
|
|
391
|
+
expect(viaNormalPalette[2]).toBe(viaJointMatrix[2]);
|
|
392
|
+
});
|
|
393
|
+
});
|