@flighthq/skeleton3d 0.3.1-next.407.d03a0bb → 0.3.1-next.425.a3192ab
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/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/skinMeshGeometry.d.ts.map +1 -1
- package/dist/skinMeshGeometry.js +27 -2
- package/dist/skinMeshGeometry.js.map +1 -1
- package/dist/skinVertices.d.ts +1 -0
- package/dist/skinVertices.d.ts.map +1 -1
- package/dist/skinVertices.js +50 -0
- package/dist/skinVertices.js.map +1 -1
- package/package.json +6 -6
- package/src/getMeshSkinBounds.test.ts +2 -0
- package/src/skinMeshGeometry.test.ts +54 -1
- package/src/skinVertices.test.ts +109 -1
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"}
|
|
@@ -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,CA8CN;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
|
}
|
|
@@ -64,11 +77,15 @@ export function captureMeshSkinBindPose(geometry) {
|
|
|
64
77
|
// the runtime slot and drives the palette is updateMeshSkin, beside this file.
|
|
65
78
|
export function skinMeshGeometry(geometry, skeleton, bindPose) {
|
|
66
79
|
skinVertices(bindPose.skinnedPositions, bindPose.skinnedNormals, bindPose.positions, bindPose.normals, bindPose.joints, bindPose.weights, skeleton.jointMatrices);
|
|
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 skinTangents(outTangents: Float32Array, tangents: Readonly<Float32Array>, joints: Readonly<ArrayLike<number>>, weights: Readonly<Float32Array>, jointMatrices: Readonly<Float32Array>): void;
|
|
1
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>): 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":"AAeA,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,CAsCN;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,GACpC,IAAI,CAkDN"}
|
package/dist/skinVertices.js
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
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
|
+
// ★ THE xyz TRANSFORM MUST STAY IDENTICAL TO THE ONE `skinVertices` APPLIES TO NORMALS — upper 3x3 of
|
|
9
|
+
// each palette matrix, no translation, no renormalization. Orthogonality of N and T survives skinning
|
|
10
|
+
// only because both go through the same transform; "improving" one side alone breaks N·T=0 for a
|
|
11
|
+
// reason that has nothing to do with the improvement. `skinVertices` and this function are checked
|
|
12
|
+
// against each other by a test that skins the same vector through both and requires equal results.
|
|
13
|
+
//
|
|
14
|
+
// `outTangents` may alias `tangents`: each vertex's input is read into locals before any output is
|
|
15
|
+
// written. Not renormalized, matching the normal path — a caller needing unit tangents does that after.
|
|
16
|
+
export function skinTangents(outTangents, tangents, joints, weights, jointMatrices) {
|
|
17
|
+
const vertexCount = (tangents.length / 4) | 0;
|
|
18
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
19
|
+
const t = v * 4;
|
|
20
|
+
const tx = tangents[t];
|
|
21
|
+
const ty = tangents[t + 1];
|
|
22
|
+
const tz = tangents[t + 2];
|
|
23
|
+
const handedness = tangents[t + 3];
|
|
24
|
+
let otx = 0;
|
|
25
|
+
let oty = 0;
|
|
26
|
+
let otz = 0;
|
|
27
|
+
for (let k = 0; k < 4; k++) {
|
|
28
|
+
const weight = weights[t + k];
|
|
29
|
+
if (weight === 0)
|
|
30
|
+
continue;
|
|
31
|
+
const m = joints[t + k] * 16;
|
|
32
|
+
const m0 = jointMatrices[m];
|
|
33
|
+
const m1 = jointMatrices[m + 1];
|
|
34
|
+
const m2 = jointMatrices[m + 2];
|
|
35
|
+
const m4 = jointMatrices[m + 4];
|
|
36
|
+
const m5 = jointMatrices[m + 5];
|
|
37
|
+
const m6 = jointMatrices[m + 6];
|
|
38
|
+
const m8 = jointMatrices[m + 8];
|
|
39
|
+
const m9 = jointMatrices[m + 9];
|
|
40
|
+
const m10 = jointMatrices[m + 10];
|
|
41
|
+
otx += weight * (m0 * tx + m4 * ty + m8 * tz);
|
|
42
|
+
oty += weight * (m1 * tx + m5 * ty + m9 * tz);
|
|
43
|
+
otz += weight * (m2 * tx + m6 * ty + m10 * tz);
|
|
44
|
+
}
|
|
45
|
+
outTangents[t] = otx;
|
|
46
|
+
outTangents[t + 1] = oty;
|
|
47
|
+
outTangents[t + 2] = otz;
|
|
48
|
+
outTangents[t + 3] = handedness;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
1
51
|
// CPU linear-blend skinning (a.k.a. smooth/matrix-palette skinning). Deforms each vertex on the CPU by the
|
|
2
52
|
// weighted sum of its influencing joints' palette matrices — the same math a GPU vertex shader runs, kept
|
|
3
53
|
// here as a deterministic, GPU-free path for offscreen bakes, physics proxies, and jsdom tests.
|
package/dist/skinVertices.js.map
CHANGED
|
@@ -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.1-next.
|
|
3
|
+
"version": "0.3.1-next.425.a3192ab",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/entity": "0.3.1-next.
|
|
42
|
-
"@flighthq/geometry": "0.3.1-next.
|
|
43
|
-
"@flighthq/mesh": "0.3.1-next.
|
|
44
|
-
"@flighthq/node": "0.3.1-next.
|
|
45
|
-
"@flighthq/types": "0.3.1-next.
|
|
41
|
+
"@flighthq/entity": "0.3.1-next.425.a3192ab",
|
|
42
|
+
"@flighthq/geometry": "0.3.1-next.425.a3192ab",
|
|
43
|
+
"@flighthq/mesh": "0.3.1-next.425.a3192ab",
|
|
44
|
+
"@flighthq/node": "0.3.1-next.425.a3192ab",
|
|
45
|
+
"@flighthq/types": "0.3.1-next.425.a3192ab"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@flighthq/scene3d": "*",
|
|
@@ -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
|
}
|
|
@@ -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,4 @@
|
|
|
1
|
-
import { skinVertices } from './skinVertices';
|
|
1
|
+
import { skinTangents, skinVertices } from './skinVertices';
|
|
2
2
|
|
|
3
3
|
// A column-major 4x4 identity, then variants with translation/scale, laid out as the 16-float palette entry.
|
|
4
4
|
function identity(): number[] {
|
|
@@ -19,6 +19,114 @@ function translation(tx: number, ty: number, tz: number): number[] {
|
|
|
19
19
|
return m;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
describe('skinTangents', () => {
|
|
23
|
+
// A 90-degree rotation about Z, column-major. A pure rotation is used deliberately: N·T = 0 survives
|
|
24
|
+
// skinning exactly only under a rigid transform, where transforming the tangent as a vector by M and
|
|
25
|
+
// the normal as a covector by M⁻ᵀ coincide. Under non-uniform scale they diverge and orthogonality is
|
|
26
|
+
// not something this code promises, so it is not asserted there.
|
|
27
|
+
// prettier-ignore
|
|
28
|
+
const rotateZ90 = [
|
|
29
|
+
0, 1, 0, 0,
|
|
30
|
+
-1, 0, 0, 0,
|
|
31
|
+
0, 0, 1, 0,
|
|
32
|
+
0, 0, 0, 1,
|
|
33
|
+
];
|
|
34
|
+
const singleJoint = { joints: new Float32Array([0, 0, 0, 0]), weights: new Float32Array([1, 0, 0, 0]) };
|
|
35
|
+
|
|
36
|
+
it('rotates the tangent direction with the pose', () => {
|
|
37
|
+
const tangents = new Float32Array([1, 0, 0, 1]);
|
|
38
|
+
const out = new Float32Array(4);
|
|
39
|
+
skinTangents(out, tangents, singleJoint.joints, singleJoint.weights, new Float32Array(rotateZ90));
|
|
40
|
+
expect(out[0]).toBeCloseTo(0);
|
|
41
|
+
expect(out[1]).toBeCloseTo(1);
|
|
42
|
+
expect(out[2]).toBeCloseTo(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('carries w through UNCHANGED, because it is handedness and not a coordinate', () => {
|
|
46
|
+
// Rotating or re-deriving w flips the bitangent across whole regions of the surface, which reaches
|
|
47
|
+
// the eye as inverted lighting rather than as a crash. Both signs are checked: a transform that
|
|
48
|
+
// happened to preserve +1 could still destroy -1.
|
|
49
|
+
const positive = new Float32Array(4);
|
|
50
|
+
const negative = new Float32Array(4);
|
|
51
|
+
skinTangents(
|
|
52
|
+
positive,
|
|
53
|
+
new Float32Array([1, 0, 0, 1]),
|
|
54
|
+
singleJoint.joints,
|
|
55
|
+
singleJoint.weights,
|
|
56
|
+
new Float32Array(rotateZ90),
|
|
57
|
+
);
|
|
58
|
+
skinTangents(
|
|
59
|
+
negative,
|
|
60
|
+
new Float32Array([1, 0, 0, -1]),
|
|
61
|
+
singleJoint.joints,
|
|
62
|
+
singleJoint.weights,
|
|
63
|
+
new Float32Array(rotateZ90),
|
|
64
|
+
);
|
|
65
|
+
expect(positive[3]).toBe(1);
|
|
66
|
+
expect(negative[3]).toBe(-1);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('keeps the tangent orthogonal to the normal it was orthogonal to', () => {
|
|
70
|
+
// The defect this fixes: the normal was skinned and the tangent was not, so N·T drifted away from
|
|
71
|
+
// zero in any pose off the bind pose. Starting orthogonal, they must stay orthogonal under a rotation.
|
|
72
|
+
const palette = new Float32Array(rotateZ90);
|
|
73
|
+
const outNormals = new Float32Array(3);
|
|
74
|
+
const outTangents = new Float32Array(4);
|
|
75
|
+
skinVertices(
|
|
76
|
+
new Float32Array(3),
|
|
77
|
+
outNormals,
|
|
78
|
+
new Float32Array([0, 0, 0]),
|
|
79
|
+
new Float32Array([0, 1, 0]),
|
|
80
|
+
singleJoint.joints,
|
|
81
|
+
singleJoint.weights,
|
|
82
|
+
palette,
|
|
83
|
+
);
|
|
84
|
+
skinTangents(outTangents, new Float32Array([1, 0, 0, 1]), singleJoint.joints, singleJoint.weights, palette);
|
|
85
|
+
const dot = outNormals[0] * outTangents[0] + outNormals[1] * outTangents[1] + outNormals[2] * outTangents[2];
|
|
86
|
+
expect(dot).toBeCloseTo(0);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('applies the SAME transform skinVertices applies to normals', () => {
|
|
90
|
+
// ★ THIS IS THE ANTI-DIVERGENCE GUARD, NOT A DUPLICATE OF THE ORTHOGONALITY TEST. Orthogonality is
|
|
91
|
+
// preserved only because both channels go through one transform; if a later change "improves" one
|
|
92
|
+
// path alone the two silently stop matching, and N·T fails for a reason unrelated to that change.
|
|
93
|
+
// Feeding the same vector through both and demanding equal xyz is what makes that divergence loud.
|
|
94
|
+
const palette = new Float32Array(rotateZ90);
|
|
95
|
+
const vector = [0.3, -0.7, 0.5];
|
|
96
|
+
const outNormals = new Float32Array(3);
|
|
97
|
+
const outTangents = new Float32Array(4);
|
|
98
|
+
skinVertices(
|
|
99
|
+
new Float32Array(3),
|
|
100
|
+
outNormals,
|
|
101
|
+
new Float32Array([0, 0, 0]),
|
|
102
|
+
new Float32Array(vector),
|
|
103
|
+
singleJoint.joints,
|
|
104
|
+
singleJoint.weights,
|
|
105
|
+
palette,
|
|
106
|
+
);
|
|
107
|
+
skinTangents(outTangents, new Float32Array([...vector, 1]), singleJoint.joints, singleJoint.weights, palette);
|
|
108
|
+
expect(outTangents[0]).toBeCloseTo(outNormals[0]);
|
|
109
|
+
expect(outTangents[1]).toBeCloseTo(outNormals[1]);
|
|
110
|
+
expect(outTangents[2]).toBeCloseTo(outNormals[2]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('is safe when the output aliases the input', () => {
|
|
114
|
+
const tangents = new Float32Array([1, 0, 0, -1]);
|
|
115
|
+
skinTangents(tangents, tangents, singleJoint.joints, singleJoint.weights, new Float32Array(rotateZ90));
|
|
116
|
+
expect(tangents[1]).toBeCloseTo(1);
|
|
117
|
+
expect(tangents[3]).toBe(-1);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('iterates nothing when the geometry carries no tangent channel', () => {
|
|
121
|
+
// A zero-length capture is how "this layout has no tangents" is expressed, so it must be a no-op
|
|
122
|
+
// rather than an out-of-range read.
|
|
123
|
+
const out = new Float32Array(0);
|
|
124
|
+
expect(() =>
|
|
125
|
+
skinTangents(out, new Float32Array(0), singleJoint.joints, singleJoint.weights, new Float32Array(rotateZ90)),
|
|
126
|
+
).not.toThrow();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
22
130
|
describe('skinVertices', () => {
|
|
23
131
|
it('passes vertices through unchanged when the only weighted joint is identity', () => {
|
|
24
132
|
const positions = new Float32Array([2, 3, 4]);
|