@driftengine/assets 3.61.0
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/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +9 -0
- package/dist/assetPath.d.ts +51 -0
- package/dist/assetPath.js +59 -0
- package/dist/coarseLevel.d.ts +94 -0
- package/dist/coarseLevel.js +606 -0
- package/dist/dds.d.ts +41 -0
- package/dist/dds.js +425 -0
- package/dist/drawKey.d.ts +64 -0
- package/dist/drawKey.js +42 -0
- package/dist/drftLoader.d.ts +420 -0
- package/dist/drftLoader.js +996 -0
- package/dist/drftTextures.d.ts +87 -0
- package/dist/drftTextures.js +138 -0
- package/dist/fbx.d.ts +86 -0
- package/dist/fbx.js +792 -0
- package/dist/fbxHarness.d.ts +68 -0
- package/dist/fbxHarness.js +185 -0
- package/dist/fbxInflate.d.ts +60 -0
- package/dist/fbxInflate.js +204 -0
- package/dist/fbxMaterial.d.ts +87 -0
- package/dist/fbxMaterial.js +345 -0
- package/dist/fbxRig.d.ts +130 -0
- package/dist/fbxRig.js +601 -0
- package/dist/gltf.d.ts +242 -0
- package/dist/gltf.js +904 -0
- package/dist/gltfAccessor.d.ts +2 -0
- package/dist/gltfAccessor.js +106 -0
- package/dist/gltfSkin.d.ts +32 -0
- package/dist/gltfSkin.js +144 -0
- package/dist/iesPhotometry.d.ts +44 -0
- package/dist/iesPhotometry.js +94 -0
- package/dist/imageInfo.d.ts +31 -0
- package/dist/imageInfo.js +119 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.js +132 -0
- package/dist/kn5.d.ts +158 -0
- package/dist/kn5.js +557 -0
- package/dist/loadProgress.d.ts +118 -0
- package/dist/loadProgress.js +1 -0
- package/dist/localise.d.ts +35 -0
- package/dist/localise.js +253 -0
- package/dist/obj.d.ts +54 -0
- package/dist/obj.js +335 -0
- package/dist/orient.d.ts +104 -0
- package/dist/orient.js +241 -0
- package/dist/radianceHdr.d.ts +36 -0
- package/dist/radianceHdr.js +172 -0
- package/dist/readModel.d.ts +153 -0
- package/dist/readModel.js +386 -0
- package/dist/recognise.d.ts +38 -0
- package/dist/recognise.js +97 -0
- package/dist/stl.d.ts +22 -0
- package/dist/stl.js +131 -0
- package/dist/tangentOrder.d.ts +24 -0
- package/dist/tangentOrder.js +31 -0
- package/dist/threemf.d.ts +46 -0
- package/dist/threemf.js +254 -0
- package/dist/uploadBudget.d.ts +82 -0
- package/dist/uploadBudget.js +86 -0
- package/dist/usd.d.ts +49 -0
- package/dist/usd.js +542 -0
- package/dist/weld.d.ts +44 -0
- package/dist/weld.js +237 -0
- package/dist/zip.d.ts +35 -0
- package/dist/zip.js +110 -0
- package/package.json +61 -0
- package/src/assetPath.ts +79 -0
- package/src/coarseLevel.ts +720 -0
- package/src/dds.ts +507 -0
- package/src/drawKey.ts +91 -0
- package/src/drftLoader.ts +1197 -0
- package/src/drftTextures.ts +153 -0
- package/src/fbx.ts +934 -0
- package/src/fbxHarness.ts +215 -0
- package/src/fbxInflate.ts +258 -0
- package/src/fbxMaterial.ts +410 -0
- package/src/fbxRig.ts +652 -0
- package/src/gltf.ts +1161 -0
- package/src/gltfAccessor.ts +127 -0
- package/src/gltfSkin.ts +210 -0
- package/src/iesPhotometry.ts +136 -0
- package/src/imageInfo.ts +130 -0
- package/src/index.ts +162 -0
- package/src/kn5.ts +705 -0
- package/src/loadProgress.ts +131 -0
- package/src/localise.ts +275 -0
- package/src/obj.ts +386 -0
- package/src/orient.ts +262 -0
- package/src/radianceHdr.ts +195 -0
- package/src/readModel.ts +515 -0
- package/src/recognise.ts +124 -0
- package/src/stl.ts +147 -0
- package/src/tangentOrder.ts +32 -0
- package/src/threemf.ts +303 -0
- package/src/uploadBudget.ts +90 -0
- package/src/usd.ts +642 -0
- package/src/weld.ts +264 -0
- package/src/zip.ts +130 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { MeshHandle } from '@driftengine/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The vocabulary of a load in flight: which phase it is in, how far it has got, and what a
|
|
5
|
+
* finished part is.
|
|
6
|
+
*
|
|
7
|
+
* Separate from the loader because these three are what a consumer's progress bar is written
|
|
8
|
+
* against, and reading them should not mean paging through a thousand-line class.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Where a load has got to, in the order a file delivers it.
|
|
13
|
+
*
|
|
14
|
+
* These are the chunk kinds rather than invented steps, which is the argument docs/FORMAT.md
|
|
15
|
+
* §4.6 makes for the whole design: the format's own layout is the sequence a viewer sees.
|
|
16
|
+
*/
|
|
17
|
+
export type DrftLoadPhase =
|
|
18
|
+
| 'idle'
|
|
19
|
+
| 'connecting'
|
|
20
|
+
| 'manifest'
|
|
21
|
+
/** A coarse whole model has landed: the asset is on screen, at the resolution it arrived at. */
|
|
22
|
+
| 'outline'
|
|
23
|
+
| 'materials'
|
|
24
|
+
| 'geometry'
|
|
25
|
+
| 'textures'
|
|
26
|
+
| 'ready'
|
|
27
|
+
| 'absent'
|
|
28
|
+
| 'failed';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* How far a load has got, and every field here now answers about the *picture* rather than about
|
|
32
|
+
* the work.
|
|
33
|
+
*
|
|
34
|
+
* **This was not true until it was reported.** `imagesDone` counted an image when its bytes
|
|
35
|
+
* arrived, and the decode that follows is deliberately not awaited so a slow one never holds up
|
|
36
|
+
* the stream. So there was a window in which `fraction` was 1, every part was uploaded and
|
|
37
|
+
* `imagesDone` equalled `imagesTotal`, while the surfaces wearing those images still drew
|
|
38
|
+
* untextured. Measured by a consumer across a scenario switch: **one and three quarter seconds.**
|
|
39
|
+
*
|
|
40
|
+
* It cost more than a harness photographing the wrong frame, which is how it was found. The same
|
|
41
|
+
* consumer drives a loading bar off these counters, so the bar reached 100% and the model then
|
|
42
|
+
* visibly changed underneath somebody who had been told it was finished. Their argument for the
|
|
43
|
+
* trade is the one that decided it: a bar that sits still for a moment is honest about being
|
|
44
|
+
* busy, and a bar that finishes early and then lets the thing it loaded change is not, and nobody
|
|
45
|
+
* can tell the second one is happening.
|
|
46
|
+
*
|
|
47
|
+
* So an image counts when it is **on the GPU**. `fraction` reaches 1 when the picture is right,
|
|
48
|
+
* and the cost is that it pauses near the end while the last decodes finish. On a weighted bar
|
|
49
|
+
* that pause is not at 99%: parts and images carry separate shares, so it climbs to roughly two
|
|
50
|
+
* thirds on the uploads and waits there, and a bar that stops at two thirds reads as working
|
|
51
|
+
* where one that stops at 99% reads as stuck.
|
|
52
|
+
*
|
|
53
|
+
* `phase === 'ready'` remains the signal to *act* on, and is what anything judging the finished
|
|
54
|
+
* picture should gate on.
|
|
55
|
+
*/
|
|
56
|
+
export interface DrftLoadProgress {
|
|
57
|
+
readonly phase: DrftLoadPhase;
|
|
58
|
+
/** 0 to 1, weighted by what the manifest says the file is actually made of. */
|
|
59
|
+
readonly fraction: number;
|
|
60
|
+
readonly partsDone: number;
|
|
61
|
+
readonly partsTotal: number;
|
|
62
|
+
/**
|
|
63
|
+
* Images that are **on the GPU**, not images whose bytes have arrived.
|
|
64
|
+
*
|
|
65
|
+
* A decode that fails counts too, because the alternative to counting it is a bar that can
|
|
66
|
+
* never finish as the price of one image that was never going to draw.
|
|
67
|
+
*/
|
|
68
|
+
readonly imagesDone: number;
|
|
69
|
+
readonly imagesTotal: number;
|
|
70
|
+
readonly totalBytes: number;
|
|
71
|
+
/** Present only when the phase is `failed` or `absent`. */
|
|
72
|
+
readonly message: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** One drawable piece of a loaded model. */
|
|
76
|
+
export interface DrftPart {
|
|
77
|
+
readonly mesh: MeshHandle;
|
|
78
|
+
/** Which of the asset's images this surface wears, or -1 for none. */
|
|
79
|
+
readonly albedo: number;
|
|
80
|
+
/** Which image carries its occlusion, roughness and metallic, or -1 for none. */
|
|
81
|
+
readonly orm: number;
|
|
82
|
+
/**
|
|
83
|
+
* Which image carries its surface-space normals, or -1 for none.
|
|
84
|
+
*
|
|
85
|
+
* **Carried by the container since `MATL` reached stride 72 and dropped here until 2026-08-23**,
|
|
86
|
+
* which is the whole of why a bought model looked smoother than the one its maker shipped: the
|
|
87
|
+
* baker wrote the index, the reader read it, the renderer has taken a normal map through
|
|
88
|
+
* `SurfaceMaterial.normal` since normal maps landed, and this was the one step that did not pass
|
|
89
|
+
* it on. Panel seams, stitching, tread and every other detail an exporter bakes into a normal
|
|
90
|
+
* map rather than into geometry was arriving and going nowhere.
|
|
91
|
+
*/
|
|
92
|
+
readonly normal: number;
|
|
93
|
+
/**
|
|
94
|
+
* Which image carries its emission, or -1 for none.
|
|
95
|
+
*
|
|
96
|
+
* **The fourth and last index `MATL` carries, passed on from 2026-08-24.** It was written by the
|
|
97
|
+
* baker, read by the reader and dropped here for the same stretch the normal map was — but for a
|
|
98
|
+
* stated reason rather than by oversight: no renderer took an emissive map until now, so there
|
|
99
|
+
* was nowhere to pass it. `SurfaceMaterial.emissive` is that somewhere.
|
|
100
|
+
*/
|
|
101
|
+
readonly emissive: number;
|
|
102
|
+
/**
|
|
103
|
+
* glTF's three factors, in the shape `SurfaceMaterial` takes them.
|
|
104
|
+
*
|
|
105
|
+
* Carried on the part rather than looked up from the material, because a caller building a
|
|
106
|
+
* `setMaterial` call has the part and not the index that produced it.
|
|
107
|
+
*/
|
|
108
|
+
readonly roughnessScale: number;
|
|
109
|
+
readonly metallicScale: number;
|
|
110
|
+
readonly occlusionStrength: number;
|
|
111
|
+
readonly opacity: number;
|
|
112
|
+
readonly reflectivity: number;
|
|
113
|
+
/**
|
|
114
|
+
* Alpha below which this surface's fragments are discarded, 0 for one that discards nothing.
|
|
115
|
+
*
|
|
116
|
+
* The pair to `opacity` and not a weaker version of it: a cutout decides which texels of the
|
|
117
|
+
* surface exist, an opacity decides how much light passes through the ones that do. It is what
|
|
118
|
+
* `SurfaceMaterial.cutout` takes, and until `MATL` grew the field there was no way for a source
|
|
119
|
+
* format to say it — a masked grille arrived as a solid rectangle, and a vehicle format's alpha
|
|
120
|
+
* *test* was being spent on the opacity, which drew nine surfaces of a hundred and two as
|
|
121
|
+
* nothing at all.
|
|
122
|
+
*/
|
|
123
|
+
readonly cutout: number;
|
|
124
|
+
/**
|
|
125
|
+
* 0 to 1 as this part arrives, for a caller that would rather it faded in than appeared.
|
|
126
|
+
*
|
|
127
|
+
* Advanced by `update`, so it follows the frame's own clock and holds when the frame holds.
|
|
128
|
+
* A caller that wants parts to pop in can ignore it; one that wants a build fades on it.
|
|
129
|
+
*/
|
|
130
|
+
reveal: number;
|
|
131
|
+
}
|
package/src/localise.ts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World-space meshes plus their graph, as parts each expressed about its own node.
|
|
3
|
+
*
|
|
4
|
+
* **Why this exists at all.** `MESH` holds world-space positions, deliberately: `docs/FORMAT.md`
|
|
5
|
+
* §4.4 rule 4 forbids a minor version from changing what an existing byte means, so geometry
|
|
6
|
+
* could not move into node-local space without breaking every reader that predates the
|
|
7
|
+
* hierarchy. The consequence is that a consumer holding a vehicle and its graph still cannot
|
|
8
|
+
* turn a wheel, because the wheel's vertices are expressed around the model's origin and not
|
|
9
|
+
* around the hub's. Turning one into the other is exact and mechanical, so the engine does it
|
|
10
|
+
* once here instead of every consumer deriving it slightly differently.
|
|
11
|
+
*
|
|
12
|
+
* **`DrftLoader` deliberately does not call this.** Its own note says placing parts under a graph
|
|
13
|
+
* is a scene decision, and that is still true — this is the arithmetic that decision needs,
|
|
14
|
+
* offered to whoever makes it.
|
|
15
|
+
*
|
|
16
|
+
* **What it costs.** One 4x4 inversion per node and one transform per vertex: 221k vertices for
|
|
17
|
+
* the largest asset this was measured against, once, at load. Not per frame. A caller loading a
|
|
18
|
+
* large model should run it behind a frame budget instead of in one block.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { DrftNode, MeshData } from '@driftengine/drft';
|
|
22
|
+
|
|
23
|
+
/** Column-major 4x4 from a node's TRS, matching what a caller hands a renderer. */
|
|
24
|
+
function compose(node: DrftNode): Float32Array {
|
|
25
|
+
const [x, y, z, w] = node.rotation;
|
|
26
|
+
const [sx, sy, sz] = node.scale;
|
|
27
|
+
const out = new Float32Array(16);
|
|
28
|
+
out[0] = (1 - 2 * (y * y + z * z)) * sx;
|
|
29
|
+
out[1] = 2 * (x * y + z * w) * sx;
|
|
30
|
+
out[2] = 2 * (x * z - y * w) * sx;
|
|
31
|
+
out[4] = 2 * (x * y - z * w) * sy;
|
|
32
|
+
out[5] = (1 - 2 * (x * x + z * z)) * sy;
|
|
33
|
+
out[6] = 2 * (y * z + x * w) * sy;
|
|
34
|
+
out[8] = 2 * (x * z + y * w) * sz;
|
|
35
|
+
out[9] = 2 * (y * z - x * w) * sz;
|
|
36
|
+
out[10] = (1 - 2 * (x * x + y * y)) * sz;
|
|
37
|
+
out[12] = node.translation[0];
|
|
38
|
+
out[13] = node.translation[1];
|
|
39
|
+
out[14] = node.translation[2];
|
|
40
|
+
out[15] = 1;
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** `out = a * b`, column-major. */
|
|
45
|
+
function multiply(a: Float32Array, b: Float32Array): Float32Array {
|
|
46
|
+
const out = new Float32Array(16);
|
|
47
|
+
for (let column = 0; column < 4; column++) {
|
|
48
|
+
for (let row = 0; row < 4; row++) {
|
|
49
|
+
let sum = 0;
|
|
50
|
+
for (let k = 0; k < 4; k++) sum += (a[k * 4 + row] as number) * (b[column * 4 + k] as number);
|
|
51
|
+
out[column * 4 + row] = sum;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A full 4x4 inverse, or null where the matrix is singular. */
|
|
58
|
+
function invert(m: Float32Array): Float32Array | null {
|
|
59
|
+
const a = (i: number): number => m[i] as number;
|
|
60
|
+
const inv = new Float32Array(16);
|
|
61
|
+
inv[0] =
|
|
62
|
+
a(5) * a(10) * a(15) -
|
|
63
|
+
a(5) * a(11) * a(14) -
|
|
64
|
+
a(9) * a(6) * a(15) +
|
|
65
|
+
a(9) * a(7) * a(14) +
|
|
66
|
+
a(13) * a(6) * a(11) -
|
|
67
|
+
a(13) * a(7) * a(10);
|
|
68
|
+
inv[4] =
|
|
69
|
+
-a(4) * a(10) * a(15) +
|
|
70
|
+
a(4) * a(11) * a(14) +
|
|
71
|
+
a(8) * a(6) * a(15) -
|
|
72
|
+
a(8) * a(7) * a(14) -
|
|
73
|
+
a(12) * a(6) * a(11) +
|
|
74
|
+
a(12) * a(7) * a(10);
|
|
75
|
+
inv[8] =
|
|
76
|
+
a(4) * a(9) * a(15) -
|
|
77
|
+
a(4) * a(11) * a(13) -
|
|
78
|
+
a(8) * a(5) * a(15) +
|
|
79
|
+
a(8) * a(7) * a(13) +
|
|
80
|
+
a(12) * a(5) * a(11) -
|
|
81
|
+
a(12) * a(7) * a(9);
|
|
82
|
+
inv[12] =
|
|
83
|
+
-a(4) * a(9) * a(14) +
|
|
84
|
+
a(4) * a(10) * a(13) +
|
|
85
|
+
a(8) * a(5) * a(14) -
|
|
86
|
+
a(8) * a(6) * a(13) -
|
|
87
|
+
a(12) * a(5) * a(10) +
|
|
88
|
+
a(12) * a(6) * a(9);
|
|
89
|
+
inv[1] =
|
|
90
|
+
-a(1) * a(10) * a(15) +
|
|
91
|
+
a(1) * a(11) * a(14) +
|
|
92
|
+
a(9) * a(2) * a(15) -
|
|
93
|
+
a(9) * a(3) * a(14) -
|
|
94
|
+
a(13) * a(2) * a(11) +
|
|
95
|
+
a(13) * a(3) * a(10);
|
|
96
|
+
inv[5] =
|
|
97
|
+
a(0) * a(10) * a(15) -
|
|
98
|
+
a(0) * a(11) * a(14) -
|
|
99
|
+
a(8) * a(2) * a(15) +
|
|
100
|
+
a(8) * a(3) * a(14) +
|
|
101
|
+
a(12) * a(2) * a(11) -
|
|
102
|
+
a(12) * a(3) * a(10);
|
|
103
|
+
inv[9] =
|
|
104
|
+
-a(0) * a(9) * a(15) +
|
|
105
|
+
a(0) * a(11) * a(13) +
|
|
106
|
+
a(8) * a(1) * a(15) -
|
|
107
|
+
a(8) * a(3) * a(13) -
|
|
108
|
+
a(12) * a(1) * a(11) +
|
|
109
|
+
a(12) * a(3) * a(9);
|
|
110
|
+
inv[13] =
|
|
111
|
+
a(0) * a(9) * a(14) -
|
|
112
|
+
a(0) * a(10) * a(13) -
|
|
113
|
+
a(8) * a(1) * a(14) +
|
|
114
|
+
a(8) * a(2) * a(13) +
|
|
115
|
+
a(12) * a(1) * a(10) -
|
|
116
|
+
a(12) * a(2) * a(9);
|
|
117
|
+
inv[2] =
|
|
118
|
+
a(1) * a(6) * a(15) -
|
|
119
|
+
a(1) * a(7) * a(14) -
|
|
120
|
+
a(5) * a(2) * a(15) +
|
|
121
|
+
a(5) * a(3) * a(14) +
|
|
122
|
+
a(13) * a(2) * a(7) -
|
|
123
|
+
a(13) * a(3) * a(6);
|
|
124
|
+
inv[6] =
|
|
125
|
+
-a(0) * a(6) * a(15) +
|
|
126
|
+
a(0) * a(7) * a(14) +
|
|
127
|
+
a(4) * a(2) * a(15) -
|
|
128
|
+
a(4) * a(3) * a(14) -
|
|
129
|
+
a(12) * a(2) * a(7) +
|
|
130
|
+
a(12) * a(3) * a(6);
|
|
131
|
+
inv[10] =
|
|
132
|
+
a(0) * a(5) * a(15) -
|
|
133
|
+
a(0) * a(7) * a(13) -
|
|
134
|
+
a(4) * a(1) * a(15) +
|
|
135
|
+
a(4) * a(3) * a(13) +
|
|
136
|
+
a(12) * a(1) * a(7) -
|
|
137
|
+
a(12) * a(3) * a(5);
|
|
138
|
+
inv[14] =
|
|
139
|
+
-a(0) * a(5) * a(14) +
|
|
140
|
+
a(0) * a(6) * a(13) +
|
|
141
|
+
a(4) * a(1) * a(14) -
|
|
142
|
+
a(4) * a(2) * a(13) -
|
|
143
|
+
a(12) * a(1) * a(6) +
|
|
144
|
+
a(12) * a(2) * a(5);
|
|
145
|
+
inv[3] =
|
|
146
|
+
-a(1) * a(6) * a(11) +
|
|
147
|
+
a(1) * a(7) * a(10) +
|
|
148
|
+
a(5) * a(2) * a(11) -
|
|
149
|
+
a(5) * a(3) * a(10) -
|
|
150
|
+
a(9) * a(2) * a(7) +
|
|
151
|
+
a(9) * a(3) * a(6);
|
|
152
|
+
inv[7] =
|
|
153
|
+
a(0) * a(6) * a(11) -
|
|
154
|
+
a(0) * a(7) * a(10) -
|
|
155
|
+
a(4) * a(2) * a(11) +
|
|
156
|
+
a(4) * a(3) * a(10) +
|
|
157
|
+
a(8) * a(2) * a(7) -
|
|
158
|
+
a(8) * a(3) * a(6);
|
|
159
|
+
inv[11] =
|
|
160
|
+
-a(0) * a(5) * a(11) +
|
|
161
|
+
a(0) * a(7) * a(9) +
|
|
162
|
+
a(4) * a(1) * a(11) -
|
|
163
|
+
a(4) * a(3) * a(9) -
|
|
164
|
+
a(8) * a(1) * a(7) +
|
|
165
|
+
a(8) * a(3) * a(5);
|
|
166
|
+
inv[15] =
|
|
167
|
+
a(0) * a(5) * a(10) -
|
|
168
|
+
a(0) * a(6) * a(9) -
|
|
169
|
+
a(4) * a(1) * a(10) +
|
|
170
|
+
a(4) * a(2) * a(9) +
|
|
171
|
+
a(8) * a(1) * a(6) -
|
|
172
|
+
a(8) * a(2) * a(5);
|
|
173
|
+
|
|
174
|
+
const determinant =
|
|
175
|
+
a(0) * (inv[0] as number) +
|
|
176
|
+
a(1) * (inv[4] as number) +
|
|
177
|
+
a(2) * (inv[8] as number) +
|
|
178
|
+
a(3) * (inv[12] as number);
|
|
179
|
+
if (determinant === 0 || !Number.isFinite(determinant)) return null;
|
|
180
|
+
for (let i = 0; i < 16; i++) inv[i] = (inv[i] as number) / determinant;
|
|
181
|
+
return inv;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface Localised {
|
|
185
|
+
/** Parallel to the meshes given, each about the origin of the node that placed it. */
|
|
186
|
+
parts: MeshData[];
|
|
187
|
+
/** Parallel to the nodes given: the accumulated world matrix, column-major. */
|
|
188
|
+
world: Float32Array[];
|
|
189
|
+
/** Nodes whose geometry could not be localised, named so a person can look at them. */
|
|
190
|
+
warnings: string[];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Move each mesh into the frame of the node that placed it, and report every node's world matrix.
|
|
195
|
+
*
|
|
196
|
+
* A mesh no node claims is passed through untouched, which is what a format carrying no hierarchy
|
|
197
|
+
* yields and is the correct no-op.
|
|
198
|
+
*/
|
|
199
|
+
export function localiseNodes(meshes: readonly MeshData[], nodes: readonly DrftNode[]): Localised {
|
|
200
|
+
const world: Float32Array[] = [];
|
|
201
|
+
for (const node of nodes) {
|
|
202
|
+
const local = compose(node);
|
|
203
|
+
world.push(node.parent < 0 ? local : multiply(world[node.parent] as Float32Array, local));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const warnings: string[] = [];
|
|
207
|
+
const parts: MeshData[] = meshes.map((mesh) => mesh);
|
|
208
|
+
for (let index = 0; index < nodes.length; index++) {
|
|
209
|
+
const node = nodes[index] as DrftNode;
|
|
210
|
+
if (node.mesh < 0) continue;
|
|
211
|
+
const mesh = meshes[node.mesh];
|
|
212
|
+
if (mesh === undefined) continue;
|
|
213
|
+
const inverse = invert(world[index] as Float32Array);
|
|
214
|
+
if (inverse === null) {
|
|
215
|
+
/*
|
|
216
|
+
* A singular basis has no inverse and no rotation worth recovering, so the mesh stays where
|
|
217
|
+
* it is. Named, because a part that cannot be animated is something a person needs told
|
|
218
|
+
* rather than left to discover when it will not turn.
|
|
219
|
+
*/
|
|
220
|
+
warnings.push(
|
|
221
|
+
`node "${node.name}" has a singular transform, so its mesh is left in world space and ` +
|
|
222
|
+
'cannot be animated about its own origin.',
|
|
223
|
+
);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const positions = new Float32Array(mesh.positions.length);
|
|
228
|
+
for (let at = 0; at < mesh.positions.length; at += 3) {
|
|
229
|
+
const x = mesh.positions[at] as number;
|
|
230
|
+
const y = mesh.positions[at + 1] as number;
|
|
231
|
+
const z = mesh.positions[at + 2] as number;
|
|
232
|
+
positions[at] =
|
|
233
|
+
x * (inverse[0] as number) +
|
|
234
|
+
y * (inverse[4] as number) +
|
|
235
|
+
z * (inverse[8] as number) +
|
|
236
|
+
(inverse[12] as number);
|
|
237
|
+
positions[at + 1] =
|
|
238
|
+
x * (inverse[1] as number) +
|
|
239
|
+
y * (inverse[5] as number) +
|
|
240
|
+
z * (inverse[9] as number) +
|
|
241
|
+
(inverse[13] as number);
|
|
242
|
+
positions[at + 2] =
|
|
243
|
+
x * (inverse[2] as number) +
|
|
244
|
+
y * (inverse[6] as number) +
|
|
245
|
+
z * (inverse[10] as number) +
|
|
246
|
+
(inverse[14] as number);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/*
|
|
250
|
+
* Normals take the inverse transpose, which for the inverse already in hand is the transpose
|
|
251
|
+
* of that inverse — the same correction `gltf.ts` applies when it flattens, in the opposite
|
|
252
|
+
* direction. Renormalised, because a node carrying a scale would otherwise leave them short.
|
|
253
|
+
*/
|
|
254
|
+
const normals = new Float32Array(mesh.normals.length);
|
|
255
|
+
for (let at = 0; at < mesh.normals.length; at += 3) {
|
|
256
|
+
const x = mesh.normals[at] as number;
|
|
257
|
+
const y = mesh.normals[at + 1] as number;
|
|
258
|
+
const z = mesh.normals[at + 2] as number;
|
|
259
|
+
const nx =
|
|
260
|
+
x * (inverse[0] as number) + y * (inverse[1] as number) + z * (inverse[2] as number);
|
|
261
|
+
const ny =
|
|
262
|
+
x * (inverse[4] as number) + y * (inverse[5] as number) + z * (inverse[6] as number);
|
|
263
|
+
const nz =
|
|
264
|
+
x * (inverse[8] as number) + y * (inverse[9] as number) + z * (inverse[10] as number);
|
|
265
|
+
const length = Math.hypot(nx, ny, nz) || 1;
|
|
266
|
+
normals[at] = nx / length;
|
|
267
|
+
normals[at + 1] = ny / length;
|
|
268
|
+
normals[at + 2] = nz / length;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
parts[node.mesh] = { ...mesh, positions, normals };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return { parts, world, warnings };
|
|
275
|
+
}
|