@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,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A loaded asset's textures, addressed by name. One responsibility: which image is which.
|
|
3
|
+
*
|
|
4
|
+
* **A caller must never hold a texture index.** An index is a position in whatever order a
|
|
5
|
+
* reader met its records, which is an accident of parsing rather than anything the asset
|
|
6
|
+
* promised, and code holding one is coupled to a decision nobody meant to publish. Reorder
|
|
7
|
+
* the source, re-export it, or regroup the meshes for drawing, and the index still resolves
|
|
8
|
+
* — to the wrong surface, with no error anywhere. That is the failure this exists to remove.
|
|
9
|
+
*
|
|
10
|
+
* So a consumer says `set('Tire_05_DM.jpg', bitmap)` and an unknown name **throws at the
|
|
11
|
+
* call**, naming what it has. Failing loudly at the moment of the mistake is the whole
|
|
12
|
+
* difference from an index, which fails silently at some later frame.
|
|
13
|
+
*
|
|
14
|
+
* Names come from `TEXS`, which stores what the source called each image. Matching is on the
|
|
15
|
+
* basename as well as the full declared path, because a material may name
|
|
16
|
+
* `textures\Tire_05_DM.jpg` while a person reasonably says `Tire_05_DM.jpg`, and requiring
|
|
17
|
+
* the exact original spelling would put the ordinal problem back with extra steps.
|
|
18
|
+
*/
|
|
19
|
+
import type { DrftTexture } from '@driftengine/drft';
|
|
20
|
+
/**
|
|
21
|
+
* Whatever a consumer creates from a decoded texture, kept as it was handed over.
|
|
22
|
+
*
|
|
23
|
+
* Generic because this module must not know what a GPU texture is: `src/asset/` describes
|
|
24
|
+
* files and `src/render/` owns the context. A caller parameterises this with its own handle
|
|
25
|
+
* and gets its own type back.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* How each of an asset's images should be sampled, decided from what its materials call them.
|
|
29
|
+
*
|
|
30
|
+
* **A colour map and a data map need opposite treatment and the container does not say which is
|
|
31
|
+
* which** — it says only that material *n* names image *k* as its albedo, or its ORM, or its
|
|
32
|
+
* normal. So the roles are read off the materials, and an image nothing names falls to `linear`,
|
|
33
|
+
* which is the harmless answer for an image nothing samples.
|
|
34
|
+
*
|
|
35
|
+
* `srgb` for a base colour and an emissive map: glTF specifies both as sRGB-encoded, and handing
|
|
36
|
+
* those bytes to a shader undecoded treats display values as light — mid-tones arrive far brighter
|
|
37
|
+
* than the author's, and it stays invisible until an output transform washes the surface out.
|
|
38
|
+
*
|
|
39
|
+
* `linear` for a normal or ORM map, whose numbers *are* the data. Decoding a direction or a
|
|
40
|
+
* roughness as though it were a colour bends every one of them toward its floor.
|
|
41
|
+
*
|
|
42
|
+
* **A conflict resolves to `linear`.** An image named as a colour map by one material and as a
|
|
43
|
+
* data map by another is a file nobody meant to write, and of the two ways to be wrong this is the
|
|
44
|
+
* milder: an sRGB-decoded ORM map bends roughness and metallic toward zero and turns the surface
|
|
45
|
+
* to polished chrome, where an undecoded colour map is merely pale.
|
|
46
|
+
*/
|
|
47
|
+
export declare function textureColorSpaces(materials: readonly {
|
|
48
|
+
readonly albedo: number;
|
|
49
|
+
readonly normalMap: number;
|
|
50
|
+
readonly ormMap: number;
|
|
51
|
+
readonly emissiveMap: number;
|
|
52
|
+
}[], count: number): ('srgb' | 'linear')[];
|
|
53
|
+
export declare class TextureSet<T> {
|
|
54
|
+
private readonly byName;
|
|
55
|
+
/**
|
|
56
|
+
* By the texture's index **in the file**, with a gap where one did not decode.
|
|
57
|
+
*
|
|
58
|
+
* Sparse on purpose. A material stores the index the file gave its map, so packing the
|
|
59
|
+
* successes together would shift every texture after a failed one and repaint the model
|
|
60
|
+
* with its neighbours' images. That is the ordinal hazard this class exists to remove,
|
|
61
|
+
* reappearing inside the thing removing it, which is exactly where it would be missed.
|
|
62
|
+
*/
|
|
63
|
+
private readonly byIndex;
|
|
64
|
+
/**
|
|
65
|
+
* Build the lookup as the textures are created, in file order.
|
|
66
|
+
*
|
|
67
|
+
* `create` returning null means that image could not be decoded, which is survivable: the
|
|
68
|
+
* surface draws untextured and the slot stays addressable, so a later `replace` can still
|
|
69
|
+
* put something there. Dropping the entry instead would renumber everything after it.
|
|
70
|
+
*/
|
|
71
|
+
static from<T>(textures: readonly DrftTexture[], create: (texture: DrftTexture, at: number) => T | null): TextureSet<T>;
|
|
72
|
+
/** How many textures were created, which is not the number the file carried. */
|
|
73
|
+
get size(): number;
|
|
74
|
+
/** Every created texture, for disposal rather than for addressing. */
|
|
75
|
+
all(): readonly T[];
|
|
76
|
+
/** The texture a material named, by its index in the file, or null. */
|
|
77
|
+
at(index: number): T | null;
|
|
78
|
+
/** Whether a name resolves, for a caller that wants to ask rather than to handle a throw. */
|
|
79
|
+
has(name: string): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* The texture called this, or a refusal naming every texture the asset does have.
|
|
82
|
+
*
|
|
83
|
+
* Throwing beats returning null. A caller asking by name has a specific image in mind, and
|
|
84
|
+
* a null it forgets to check is the silent-wrong-surface failure that indices already had.
|
|
85
|
+
*/
|
|
86
|
+
get(name: string): T;
|
|
87
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A loaded asset's textures, addressed by name. One responsibility: which image is which.
|
|
3
|
+
*
|
|
4
|
+
* **A caller must never hold a texture index.** An index is a position in whatever order a
|
|
5
|
+
* reader met its records, which is an accident of parsing rather than anything the asset
|
|
6
|
+
* promised, and code holding one is coupled to a decision nobody meant to publish. Reorder
|
|
7
|
+
* the source, re-export it, or regroup the meshes for drawing, and the index still resolves
|
|
8
|
+
* — to the wrong surface, with no error anywhere. That is the failure this exists to remove.
|
|
9
|
+
*
|
|
10
|
+
* So a consumer says `set('Tire_05_DM.jpg', bitmap)` and an unknown name **throws at the
|
|
11
|
+
* call**, naming what it has. Failing loudly at the moment of the mistake is the whole
|
|
12
|
+
* difference from an index, which fails silently at some later frame.
|
|
13
|
+
*
|
|
14
|
+
* Names come from `TEXS`, which stores what the source called each image. Matching is on the
|
|
15
|
+
* basename as well as the full declared path, because a material may name
|
|
16
|
+
* `textures\Tire_05_DM.jpg` while a person reasonably says `Tire_05_DM.jpg`, and requiring
|
|
17
|
+
* the exact original spelling would put the ordinal problem back with extra steps.
|
|
18
|
+
*/
|
|
19
|
+
import { basenameOf } from './assetPath.js';
|
|
20
|
+
import { DrftError } from '@driftengine/drft';
|
|
21
|
+
/**
|
|
22
|
+
* Whatever a consumer creates from a decoded texture, kept as it was handed over.
|
|
23
|
+
*
|
|
24
|
+
* Generic because this module must not know what a GPU texture is: `src/asset/` describes
|
|
25
|
+
* files and `src/render/` owns the context. A caller parameterises this with its own handle
|
|
26
|
+
* and gets its own type back.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* How each of an asset's images should be sampled, decided from what its materials call them.
|
|
30
|
+
*
|
|
31
|
+
* **A colour map and a data map need opposite treatment and the container does not say which is
|
|
32
|
+
* which** — it says only that material *n* names image *k* as its albedo, or its ORM, or its
|
|
33
|
+
* normal. So the roles are read off the materials, and an image nothing names falls to `linear`,
|
|
34
|
+
* which is the harmless answer for an image nothing samples.
|
|
35
|
+
*
|
|
36
|
+
* `srgb` for a base colour and an emissive map: glTF specifies both as sRGB-encoded, and handing
|
|
37
|
+
* those bytes to a shader undecoded treats display values as light — mid-tones arrive far brighter
|
|
38
|
+
* than the author's, and it stays invisible until an output transform washes the surface out.
|
|
39
|
+
*
|
|
40
|
+
* `linear` for a normal or ORM map, whose numbers *are* the data. Decoding a direction or a
|
|
41
|
+
* roughness as though it were a colour bends every one of them toward its floor.
|
|
42
|
+
*
|
|
43
|
+
* **A conflict resolves to `linear`.** An image named as a colour map by one material and as a
|
|
44
|
+
* data map by another is a file nobody meant to write, and of the two ways to be wrong this is the
|
|
45
|
+
* milder: an sRGB-decoded ORM map bends roughness and metallic toward zero and turns the surface
|
|
46
|
+
* to polished chrome, where an undecoded colour map is merely pale.
|
|
47
|
+
*/
|
|
48
|
+
export function textureColorSpaces(materials, count) {
|
|
49
|
+
const colour = new Set();
|
|
50
|
+
const data = new Set();
|
|
51
|
+
for (const material of materials) {
|
|
52
|
+
if (material.albedo >= 0)
|
|
53
|
+
colour.add(material.albedo);
|
|
54
|
+
if (material.emissiveMap >= 0)
|
|
55
|
+
colour.add(material.emissiveMap);
|
|
56
|
+
if (material.normalMap >= 0)
|
|
57
|
+
data.add(material.normalMap);
|
|
58
|
+
if (material.ormMap >= 0)
|
|
59
|
+
data.add(material.ormMap);
|
|
60
|
+
}
|
|
61
|
+
const out = [];
|
|
62
|
+
for (let at = 0; at < count; at++) {
|
|
63
|
+
out.push(colour.has(at) && !data.has(at) ? 'srgb' : 'linear');
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
export class TextureSet {
|
|
68
|
+
byName = new Map();
|
|
69
|
+
/**
|
|
70
|
+
* By the texture's index **in the file**, with a gap where one did not decode.
|
|
71
|
+
*
|
|
72
|
+
* Sparse on purpose. A material stores the index the file gave its map, so packing the
|
|
73
|
+
* successes together would shift every texture after a failed one and repaint the model
|
|
74
|
+
* with its neighbours' images. That is the ordinal hazard this class exists to remove,
|
|
75
|
+
* reappearing inside the thing removing it, which is exactly where it would be missed.
|
|
76
|
+
*/
|
|
77
|
+
byIndex = [];
|
|
78
|
+
/**
|
|
79
|
+
* Build the lookup as the textures are created, in file order.
|
|
80
|
+
*
|
|
81
|
+
* `create` returning null means that image could not be decoded, which is survivable: the
|
|
82
|
+
* surface draws untextured and the slot stays addressable, so a later `replace` can still
|
|
83
|
+
* put something there. Dropping the entry instead would renumber everything after it.
|
|
84
|
+
*/
|
|
85
|
+
static from(textures, create) {
|
|
86
|
+
const set = new TextureSet();
|
|
87
|
+
for (let at = 0; at < textures.length; at++) {
|
|
88
|
+
const texture = textures[at];
|
|
89
|
+
if (texture === undefined)
|
|
90
|
+
continue;
|
|
91
|
+
const made = create(texture, at);
|
|
92
|
+
/* The slot is kept either way, so the indices materials carry stay true. */
|
|
93
|
+
set.byIndex[at] = made;
|
|
94
|
+
if (made === null)
|
|
95
|
+
continue;
|
|
96
|
+
/*
|
|
97
|
+
* Both spellings, so a caller may use either. The full path wins a collision because
|
|
98
|
+
* it is what the file actually said; a basename is a convenience over it.
|
|
99
|
+
*/
|
|
100
|
+
const base = basenameOf(texture.name);
|
|
101
|
+
if (base !== '' && !set.byName.has(base))
|
|
102
|
+
set.byName.set(base, made);
|
|
103
|
+
if (texture.name !== '')
|
|
104
|
+
set.byName.set(texture.name, made);
|
|
105
|
+
}
|
|
106
|
+
return set;
|
|
107
|
+
}
|
|
108
|
+
/** How many textures were created, which is not the number the file carried. */
|
|
109
|
+
get size() {
|
|
110
|
+
return this.byIndex.filter((t) => t !== null).length;
|
|
111
|
+
}
|
|
112
|
+
/** Every created texture, for disposal rather than for addressing. */
|
|
113
|
+
all() {
|
|
114
|
+
return this.byIndex.filter((t) => t !== null);
|
|
115
|
+
}
|
|
116
|
+
/** The texture a material named, by its index in the file, or null. */
|
|
117
|
+
at(index) {
|
|
118
|
+
return index >= 0 ? (this.byIndex[index] ?? null) : null;
|
|
119
|
+
}
|
|
120
|
+
/** Whether a name resolves, for a caller that wants to ask rather than to handle a throw. */
|
|
121
|
+
has(name) {
|
|
122
|
+
return this.byName.has(name) || this.byName.has(basenameOf(name));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The texture called this, or a refusal naming every texture the asset does have.
|
|
126
|
+
*
|
|
127
|
+
* Throwing beats returning null. A caller asking by name has a specific image in mind, and
|
|
128
|
+
* a null it forgets to check is the silent-wrong-surface failure that indices already had.
|
|
129
|
+
*/
|
|
130
|
+
get(name) {
|
|
131
|
+
const found = this.byName.get(name) ?? this.byName.get(basenameOf(name));
|
|
132
|
+
if (found === undefined) {
|
|
133
|
+
const known = [...this.byName.keys()].join(', ');
|
|
134
|
+
throw new DrftError(`no texture called "${name}" in this asset. It carries: ${known === '' ? 'none' : known}`);
|
|
135
|
+
}
|
|
136
|
+
return found;
|
|
137
|
+
}
|
|
138
|
+
}
|
package/dist/fbx.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary FBX → `MeshData`. Tier 2: a real attempt, and explicitly not a guarantee.
|
|
3
|
+
*
|
|
4
|
+
* FBX is what an asset store hands you as the source, so reading it removes a round trip
|
|
5
|
+
* through an export dialog for the common case. The obstacle was never the format — it is
|
|
6
|
+
* Autodesk's *SDK licence*, and nothing here uses or ships any of it. The binary container
|
|
7
|
+
* is a self-describing tree of typed records, which is why a reader can be written against
|
|
8
|
+
* it at all.
|
|
9
|
+
*
|
|
10
|
+
* **Inflate is injected.** Array properties are usually deflate-compressed, and the only
|
|
11
|
+
* decompressor available without a dependency is Node's `zlib` — which must not be
|
|
12
|
+
* imported here, because this file is part of an engine that runs in a browser. So the
|
|
13
|
+
* caller supplies one. The baker passes `zlib.inflateSync`; a browser could pass
|
|
14
|
+
* `DecompressionStream`. Neither is this module's business.
|
|
15
|
+
*
|
|
16
|
+
* What it reads: geometry, its normals and UVs, and per-model transforms. What it refuses:
|
|
17
|
+
* anything it cannot understand, by name. It never returns the part of a scene it managed
|
|
18
|
+
* — a model with holes in it is a worse outcome than an error, because the error says what
|
|
19
|
+
* to do next.
|
|
20
|
+
*
|
|
21
|
+
* **It reports orientation and does not apply it.** The file's declared up axis comes back
|
|
22
|
+
* as `declaredUp`, and standing the asset up is `orient.ts`, one implementation shared by
|
|
23
|
+
* every format. That split is deliberate: a reader that quietly corrected its own files
|
|
24
|
+
* would make this format's habits into the engine's defaults, and the next reader would be
|
|
25
|
+
* written to match those rather than its own specification.
|
|
26
|
+
*/
|
|
27
|
+
import type { MeshData } from '@driftengine/drft';
|
|
28
|
+
import type { UpAxis } from './orient.ts';
|
|
29
|
+
import type { DrftMaterial } from '@driftengine/drft';
|
|
30
|
+
import type { AssetReference } from './assetPath.ts';
|
|
31
|
+
import type { AnimationClip, DrftSkin } from '@driftengine/drft';
|
|
32
|
+
/** Turn a deflate stream into bytes. Supplied by the caller; see the note above. */
|
|
33
|
+
export type Inflate = (compressed: Uint8Array, expectedBytes: number) => Uint8Array;
|
|
34
|
+
/** A node in the FBX record tree. */
|
|
35
|
+
export interface FbxNode {
|
|
36
|
+
name: string;
|
|
37
|
+
properties: unknown[];
|
|
38
|
+
children: FbxNode[];
|
|
39
|
+
}
|
|
40
|
+
/** Parse the record tree. Structure only — nothing here knows what a mesh is. */
|
|
41
|
+
export declare function parseFbxTree(buffer: ArrayBuffer, inflate: Inflate): {
|
|
42
|
+
root: FbxNode;
|
|
43
|
+
version: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Geometry out of a parsed tree, one `MeshData` per `Geometry` record.
|
|
47
|
+
*
|
|
48
|
+
* FBX stores polygons of any size as a flat index list where a **negative index marks the
|
|
49
|
+
* last corner of a polygon**, encoded as its bitwise complement. Triangulating as a fan is
|
|
50
|
+
* correct for the convex polygons these files contain and is what every other reader does.
|
|
51
|
+
*
|
|
52
|
+
* Normals and UVs arrive as layer elements with their own mapping and reference modes, and
|
|
53
|
+
* the combination decides how to look a value up. Getting that wrong does not fail — it
|
|
54
|
+
* shades the model wrongly — so each supported combination is handled explicitly and an
|
|
55
|
+
* unsupported one is named rather than approximated.
|
|
56
|
+
*/
|
|
57
|
+
export declare function fbxToMeshes(buffer: ArrayBuffer, inflate: Inflate): {
|
|
58
|
+
meshes: MeshData[];
|
|
59
|
+
warnings: string[];
|
|
60
|
+
version: number;
|
|
61
|
+
declaredUp: UpAxis;
|
|
62
|
+
/**
|
|
63
|
+
* Parallel to `meshes`: the surface each one wears, including which texture colours it.
|
|
64
|
+
*
|
|
65
|
+
* A parallel array rather than a field on `MeshData`, because `MeshData` is the engine's
|
|
66
|
+
* own vertex data and a texture *reference* is a fact about a file that has not been
|
|
67
|
+
* resolved yet. Folding an unresolved path into the thing the renderer uploads would put a
|
|
68
|
+
* bake-time concern inside a runtime type.
|
|
69
|
+
*/
|
|
70
|
+
materials: DrftMaterial[];
|
|
71
|
+
/** Textures the file names, with bytes where it embedded them itself. */
|
|
72
|
+
textures: AssetReference[];
|
|
73
|
+
/**
|
|
74
|
+
* The rig, where the file carries one. Empty for the static meshes this reader began with.
|
|
75
|
+
*
|
|
76
|
+
* **A skinned geometry keeps its vertices in the space its own file put them in**, and does not
|
|
77
|
+
* take the model's world transform the way a static one does. That is not an omission: a
|
|
78
|
+
* cluster's bind matrices already carry where the mesh was, so applying the transform as well
|
|
79
|
+
* places the character twice — which throws the rig across the scene rather than shifting it,
|
|
80
|
+
* and is the same rule the glTF reader states for a skinned primitive.
|
|
81
|
+
*/
|
|
82
|
+
skins: DrftSkin[];
|
|
83
|
+
clips: AnimationClip[];
|
|
84
|
+
/** Metres per source unit, which this format states. See `unitScaleOf`. */
|
|
85
|
+
unitScale: number;
|
|
86
|
+
};
|