@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.
@@ -1,3 +1,4 @@
1
+ export * from './enableSkeleton3DGuards';
1
2
  export * from './getMeshSkinBounds';
2
3
  export * from './prepareScene3DSkinning';
3
4
  export * from './skeleton3d';
@@ -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
@@ -1,3 +1,4 @@
1
+ export * from './enableSkeleton3DGuards';
1
2
  export * from './getMeshSkinBounds';
2
3
  export * from './prepareScene3DSkinning';
3
4
  export * from './skeleton3d';
@@ -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,4 @@
1
+ export declare function areSkeleton3DGuardsEnabled(): boolean;
2
+ export declare function disableSkeleton3DGuards(): void;
3
+ export declare function enableSkeleton3DGuards(): void;
4
+ //# sourceMappingURL=enableSkeleton3DGuards.d.ts.map
@@ -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,CAwCN"}
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
@@ -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"}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton3d.d.ts","sourceRoot":"","sources":["../src/skeleton3d.ts"],"names":[],"mappings":"AAGA,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,CAQ1E;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,CAsBZ;AAED,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAQnF;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,CAUZ;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,CAM1E;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,8BAA8B,GAAG,IAAI,CAWxG"}
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"}
@@ -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
- inverseMatrix4(_result, getNodeWorldMatrix4(joints[j]));
112
- inverseBindMatrices.set(_result.m, j * 16);
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
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton3d.js","sourceRoot":"","sources":["../src/skeleton3d.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skeleton3d.js","sourceRoot":"","sources":["../src/skeleton3d.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,2BAA2B,EAC3B,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAG3F,MAAM,UAAU,eAAe,CAAC,QAA8B;IAC5D,MAAM,KAAK,GAAG,YAAY,CAAC;QACzB,mBAAmB,EAAE,IAAI,YAAY,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACnE,aAAa,EAAE,IAAI,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC;QACvD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE;QAC/B,KAAK,EAAE,QAAQ,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE;QACzG,cAAc,EAAE,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC;KAC1D,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gGAAgG;AAChG,qGAAqG;AACrG,kGAAkG;AAClG,mGAAmG;AACnG,wGAAwG;AACxG,MAAM,UAAU,6BAA6B,CAC3C,QAA8B,EAC9B,UAAmE;IAEnE,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,KAAK,CAAS,YAAY,CAAC,MAAM,CAAC,CAAC;IACtD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;QAClB,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpC,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,IAAI,YAAY,KAAK,IAAI;YAAE,SAAS;QACpC,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACrD,IAAI,WAAW,KAAK,SAAS;YAAE,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,YAAY,CAAC;QAClB,mBAAmB,EAAE,IAAI,YAAY,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACnE,aAAa,EAAE,IAAI,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC;QACvD,MAAM;QACN,KAAK,EAAE,QAAQ,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE;QACzG,cAAc,EAAE,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC;KAC1D,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,QAA8B;IAC3E,MAAM,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,QAAQ,CAAC;IAChF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;YAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAC3E,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACnE,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACnC,kGAAkG;QAClG,qFAAqF;QACrF,2BAA2B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9C,kGAAkG;QAClG,yEAAyE;QACzE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QACjB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,cAAc,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,cAAc,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,cAAc,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,cAAc,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAAgB,EAChB,mBAAkC,EAClC,KAAgC;IAEhC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5B,MAAM,QAAQ,GAAG,YAAY,CAAC;QAC5B,mBAAmB,EAAE,mBAAmB,IAAI,IAAI,YAAY,CAAC,KAAK,GAAG,EAAE,CAAC;QACxE,aAAa,EAAE,IAAI,YAAY,CAAC,KAAK,GAAG,EAAE,CAAC;QAC3C,MAAM;QACN,KAAK,EAAE,KAAK,IAAI,IAAI;QACpB,cAAc,EAAE,IAAI,YAAY,CAAC,KAAK,GAAG,EAAE,CAAC;KAC7C,CAAC,CAAC;IACH,IAAI,mBAAmB,KAAK,SAAS;QAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACvE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAoB;IACpD,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3B,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAuB,EAAE,CAAuB;IAC/E,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACtD,IAAI,CAAC,CAAC,mBAAmB,CAAC,MAAM,KAAK,CAAC,CAAC,mBAAmB,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAChF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtD,IAAI,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC1E,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;IAC/B,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;IAC/B,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,KAAK,MAAM,CAAC;IACjE,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,QAA8B,EAAE,IAAY;IACxF,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;IAC3B,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,CAAC,CAAC,CAAC;IAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,GAAgB,EAChB,QAA8B,EAC9B,UAAkB;IAElB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAChE,WAAW,CAAC,GAAG,EAAE,mBAAmB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mCAAmC,CACjD,GAAgB,EAChB,QAA8B,EAC9B,IAAY;IAEZ,OAAO,6BAA6B,CAAC,GAAG,EAAE,QAAQ,EAAE,6BAA6B,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;AACrG,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAA8B;IAClE,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,qGAAqG;QACrG,kGAAkG;QAClG,kFAAkF;QAClF,EAAE;QACF,qGAAqG;QACrG,mGAAmG;QACnG,mGAAmG;QACnG,8EAA8E;QAC9E,IAAI,cAAc,CAAC,OAAO,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAC5B,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;YAC3C,uBAAuB,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;AACH,CAAC;AAED,oGAAoG;AACpG,sGAAsG;AACtG,2EAA2E;AAC3E,MAAM,UAAU,0BAA0B,CACxC,KAA4E;IAE5E,uBAAuB,GAAG,KAAK,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAA8B;IAC/D,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IAC1C,MAAM,iCAAiC,GAAG,UAAU,GAAG,EAAE,CAAC;IAC1D,MAAM,yBAAyB,GAAG,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC;IACtE,IAAI,yBAAyB,KAAK,iCAAiC;QAAE,OAAO,IAAI,CAAC;IACjF,OAAO;QACL,iCAAiC;QACjC,yBAAyB;QACzB,UAAU;QACV,OAAO,EAAE,yCAAyC,yBAAyB,8BAA8B,UAAU,WAAW,iCAAiC,GAAG;KACnK,CAAC;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;AACjC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;AAChC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;AAEhC,IAAI,uBAAuB,GAA0E,IAAI,CAAC"}
@@ -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,CAkD1F;AASD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GACnC,IAAI,CAkCN;AAMD,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,IAAI,CAsBpH"}
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"}
@@ -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
- const { skinnedNormals, skinnedPositions } = bindPose;
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":"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"}
1
+ {"version":3,"file":"skinMeshGeometry.js","sourceRoot":"","sources":["../src/skinMeshGeometry.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,3 @@
1
- export declare function skinVertices(outPositions: Float32Array, outNormals: Float32Array, positions: Readonly<Float32Array>, normals: Readonly<Float32Array>, joints: Readonly<ArrayLike<number>>, weights: Readonly<Float32Array>, jointMatrices: Readonly<Float32Array>): void;
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":"AAeA,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,GACpC,IAAI,CAkDN"}
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"}
@@ -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
- onx += weight * (m0 * nx + m4 * ny + m8 * nz);
51
- ony += weight * (m1 * nx + m5 * ny + m9 * nz);
52
- onz += weight * (m2 * nx + m6 * ny + m10 * nz);
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
- outPositions[p] = opx;
55
- outPositions[p + 1] = opy;
56
- outPositions[p + 2] = opz;
57
- outNormals[p] = onx;
58
- outNormals[p + 1] = ony;
59
- outNormals[p + 2] = onz;
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
@@ -1 +1 @@
1
- {"version":3,"file":"skinVertices.js","sourceRoot":"","sources":["../src/skinVertices.ts"],"names":[],"mappings":"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"}
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.0",
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.0",
42
- "@flighthq/geometry": "0.3.0",
43
- "@flighthq/mesh": "0.3.0",
44
- "@flighthq/node": "0.3.0",
45
- "@flighthq/types": "0.3.0"
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
  }
@@ -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', () => {
@@ -1,4 +1,26 @@
1
- import { skinVertices } from './skinVertices';
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(outPositions, outNormals, positions, normals, joints, weights, palette);
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(outPositions, outNormals, positions, normals, joints, weights, palette);
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(outPositions, outNormals, positions, normals, joints, weights, palette);
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(outPositions, outNormals, positions, normals, joints, weights, palette);
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
+ });