@developerz.ai/ts23d 0.1.0 → 0.2.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/CHANGELOG.md +11 -0
- package/CLAUDE.md +1 -1
- package/README.md +10 -5
- package/dist/{chunk-a8fxakcj.js → chunk-6b05mnmx.js} +2 -2
- package/dist/{chunk-kgvbpqqw.js → chunk-7rtfjh9f.js} +6 -5
- package/dist/chunk-7rtfjh9f.js.map +10 -0
- package/dist/{chunk-1ypfs7ga.js → chunk-8j4c28jt.js} +790 -276
- package/dist/chunk-8j4c28jt.js.map +46 -0
- package/dist/{chunk-wtqhq529.js → chunk-d1fv6hrm.js} +6 -6
- package/dist/{chunk-wtqhq529.js.map → chunk-d1fv6hrm.js.map} +1 -1
- package/dist/{chunk-gcyp9b4d.js → chunk-dbq4qf52.js} +362 -215
- package/dist/chunk-dbq4qf52.js.map +25 -0
- package/dist/{chunk-xnt2sdhf.js → chunk-drna2rny.js} +2 -2
- package/dist/{chunk-ravbb06q.js → chunk-dxvypr7y.js} +2 -2
- package/dist/{chunk-11v28977.js → chunk-f6yme003.js} +85 -71
- package/dist/{chunk-11v28977.js.map → chunk-f6yme003.js.map} +6 -6
- package/dist/{chunk-4ddzsqtc.js → chunk-hg7pf34j.js} +4 -3
- package/dist/{chunk-4ddzsqtc.js.map → chunk-hg7pf34j.js.map} +5 -5
- package/dist/{chunk-w1zyhj40.js → chunk-jq4e17tj.js} +2 -2
- package/dist/{chunk-kvcep7ft.js → chunk-y63c6zcv.js} +967 -218
- package/dist/chunk-y63c6zcv.js.map +53 -0
- package/dist/cli/args.d.ts +7 -1
- package/dist/cli/bin.js +66 -25
- package/dist/cli/bin.js.map +6 -5
- package/dist/cli/manifest.d.ts +5 -1
- package/dist/cli/texture-cache.d.ts +4 -0
- package/dist/core/definition.d.ts +7 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/export/credits.d.ts +4 -0
- package/dist/export/glb-options.d.ts +48 -0
- package/dist/export/glb.d.ts +5 -35
- package/dist/export/hierarchy.d.ts +23 -0
- package/dist/export/index.d.ts +2 -1
- package/dist/export/index.js +21 -7
- package/dist/export/index.js.map +1 -1
- package/dist/export/lod-coverage.d.ts +12 -0
- package/dist/export/metadata.d.ts +2 -0
- package/dist/export/version.d.ts +2 -2
- package/dist/grammar/index.js +2 -2
- package/dist/index.js +63 -17
- package/dist/index.js.map +1 -1
- package/dist/kinds/head-armour.d.ts +3 -7
- package/dist/kinds/head-bust.d.ts +3 -2
- package/dist/kinds/head-face.d.ts +3 -1
- package/dist/kinds/head-garb.d.ts +4 -0
- package/dist/kinds/head-mesh.d.ts +4 -0
- package/dist/kinds/head-mouth.d.ts +4 -0
- package/dist/kinds/head-params.d.ts +9 -1
- package/dist/kinds/head-tone.d.ts +10 -0
- package/dist/kinds/head-torso.d.ts +35 -0
- package/dist/kinds/index.js +6 -6
- package/dist/material/cc0.d.ts +4 -0
- package/dist/material/define.d.ts +34 -0
- package/dist/material/generator.d.ts +1 -1
- package/dist/material/index.d.ts +8 -3
- package/dist/material/index.js +39 -7
- package/dist/material/index.js.map +1 -1
- package/dist/material/library.d.ts +7 -0
- package/dist/material/material-def.d.ts +30 -0
- package/dist/material/paint/canvas.d.ts +7 -0
- package/dist/material/paint/default-sheet.d.ts +3 -1
- package/dist/material/paint/fabric.d.ts +4 -0
- package/dist/material/paint/image-strip.d.ts +4 -0
- package/dist/material/paint/kit.d.ts +5 -0
- package/dist/material/paint/metal.d.ts +3 -0
- package/dist/material/paint/orm.d.ts +1 -1
- package/dist/material/paint/strip.d.ts +1 -1
- package/dist/material/paint/types.d.ts +32 -2
- package/dist/material/palette.d.ts +2 -0
- package/dist/material/slots.d.ts +5 -0
- package/dist/material/texture-source.d.ts +34 -0
- package/dist/material/trim-sheet.d.ts +20 -4
- package/dist/neural/index.js +2 -2
- package/dist/passes/index.js +2 -2
- package/dist/primitives/index.js +3 -3
- package/dist/qa/index.js +2 -2
- package/dist/render/beauty.d.ts +1 -1
- package/dist/render/index.js +3 -3
- package/dist/render/lighting.d.ts +7 -0
- package/dist/render/shade.d.ts +1 -1
- package/dist/testing/index.js +5 -5
- package/docs/README.md +4 -0
- package/docs/architecture/gltf-capabilities.md +38 -1
- package/docs/architecture/materials.md +151 -0
- package/docs/idea/10-sculpting.md +166 -0
- package/docs/idea/11-materials-authoring.md +132 -0
- package/docs/idea/12-blender-bridge.md +136 -0
- package/docs/idea/13-asset-pipeline-research.md +89 -0
- package/docs/plans/roadmap.md +12 -0
- package/package.json +2 -1
- package/recipes/boxcar/README.md +7 -0
- package/recipes/boxcar/boxcar.ts +118 -34
- package/recipes/goblin_head/README.md +27 -14
- package/recipes/goblin_head/goblin_head.ts +11 -9
- package/recipes/human_head/README.md +8 -4
- package/recipes/human_head/human_head.ts +4 -3
- package/recipes/material_swatches/material_swatches.ts +11 -5
- package/recipes/orc_head/README.md +32 -20
- package/recipes/orc_head/orc_head.ts +9 -7
- package/src/cli/args.ts +16 -3
- package/src/cli/manifest.ts +6 -0
- package/src/cli/run.ts +33 -9
- package/src/cli/texture-cache.ts +24 -0
- package/src/core/asset.ts +1 -0
- package/src/core/definition.ts +7 -0
- package/src/core/errors.ts +6 -1
- package/src/export/credits.ts +25 -0
- package/src/export/glb-options.ts +53 -0
- package/src/export/glb.ts +100 -113
- package/src/export/hierarchy.ts +122 -0
- package/src/export/index.ts +17 -1
- package/src/export/lod-coverage.ts +71 -0
- package/src/export/metadata.ts +3 -0
- package/src/export/version.ts +1 -1
- package/src/kinds/head-armour.ts +103 -73
- package/src/kinds/head-bust.ts +49 -86
- package/src/kinds/head-face.ts +94 -74
- package/src/kinds/head-garb.ts +181 -0
- package/src/kinds/head-hair.ts +74 -33
- package/src/kinds/head-mesh.ts +43 -5
- package/src/kinds/head-mouth.ts +111 -0
- package/src/kinds/head-params.ts +11 -2
- package/src/kinds/head-presets.ts +30 -27
- package/src/kinds/head-tone.ts +52 -0
- package/src/kinds/head-torso.ts +230 -0
- package/src/kinds/head.ts +8 -3
- package/src/material/cc0.ts +41 -0
- package/src/material/define.ts +130 -0
- package/src/material/generator.ts +15 -8
- package/src/material/index.ts +34 -3
- package/src/material/library.ts +196 -0
- package/src/material/material-def.ts +84 -0
- package/src/material/paint/canvas.ts +11 -1
- package/src/material/paint/compose.ts +1 -1
- package/src/material/paint/decode-png.ts +19 -13
- package/src/material/paint/default-sheet.ts +40 -28
- package/src/material/paint/fabric.ts +63 -0
- package/src/material/paint/image-strip.ts +88 -0
- package/src/material/paint/kit.ts +37 -0
- package/src/material/paint/masks.ts +3 -1
- package/src/material/paint/metal.ts +109 -0
- package/src/material/paint/orm.ts +14 -1
- package/src/material/paint/planks.ts +49 -4
- package/src/material/paint/strip.ts +35 -29
- package/src/material/paint/types.ts +45 -2
- package/src/material/paint/validate.ts +19 -3
- package/src/material/palette.ts +3 -0
- package/src/material/slots.ts +18 -0
- package/src/material/texture-source.ts +86 -0
- package/src/material/trim-sheet.ts +79 -13
- package/src/render/beauty.ts +2 -2
- package/src/render/lighting.ts +26 -0
- package/src/render/shade.ts +10 -5
- package/dist/chunk-1ypfs7ga.js.map +0 -42
- package/dist/chunk-gcyp9b4d.js.map +0 -22
- package/dist/chunk-kgvbpqqw.js.map +0 -10
- package/dist/chunk-kvcep7ft.js.map +0 -43
- /package/dist/{chunk-a8fxakcj.js.map → chunk-6b05mnmx.js.map} +0 -0
- /package/dist/{chunk-xnt2sdhf.js.map → chunk-drna2rny.js.map} +0 -0
- /package/dist/{chunk-ravbb06q.js.map → chunk-dxvypr7y.js.map} +0 -0
- /package/dist/{chunk-w1zyhj40.js.map → chunk-jq4e17tj.js.map} +0 -0
|
@@ -5,14 +5,16 @@ import {
|
|
|
5
5
|
quatFromAxisAngle2,
|
|
6
6
|
worldTransforms2,
|
|
7
7
|
toWorld2,
|
|
8
|
-
rotateZ2
|
|
9
|
-
|
|
8
|
+
rotateZ2,
|
|
9
|
+
worldMeshes2
|
|
10
|
+
} from "./chunk-hg7pf34j.js";
|
|
10
11
|
import {
|
|
11
|
-
hex2
|
|
12
|
-
|
|
12
|
+
hex2,
|
|
13
|
+
stripCredits2
|
|
14
|
+
} from "./chunk-y63c6zcv.js";
|
|
13
15
|
import {
|
|
14
16
|
optimize2
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-drna2rny.js";
|
|
16
18
|
|
|
17
19
|
// src/export/bin-writer.ts
|
|
18
20
|
var ARRAY_BUFFER = 34962;
|
|
@@ -111,6 +113,28 @@ function concat(a, b) {
|
|
|
111
113
|
return out;
|
|
112
114
|
}
|
|
113
115
|
|
|
116
|
+
// src/export/credits.ts
|
|
117
|
+
function creditsOf(asset) {
|
|
118
|
+
const out = new Set;
|
|
119
|
+
for (const p of asset.parts) {
|
|
120
|
+
const uv = p.mesh?.uvs;
|
|
121
|
+
if (!uv)
|
|
122
|
+
continue;
|
|
123
|
+
const v = new Float32Array(uv.length >> 1);
|
|
124
|
+
for (let i = 0;i < v.length; i++)
|
|
125
|
+
v[i] = uv[i * 2 + 1] ?? 0;
|
|
126
|
+
for (const c of stripCredits2(v))
|
|
127
|
+
out.add(c);
|
|
128
|
+
}
|
|
129
|
+
return [...out].sort();
|
|
130
|
+
}
|
|
131
|
+
function withCredits(asset, meta) {
|
|
132
|
+
const credits = creditsOf(asset);
|
|
133
|
+
if (!credits.length)
|
|
134
|
+
return meta;
|
|
135
|
+
return { ...meta, credits: [...meta?.credits ?? [], ...credits] };
|
|
136
|
+
}
|
|
137
|
+
|
|
114
138
|
// src/export/lights.ts
|
|
115
139
|
var LIGHTS = "KHR_lights_punctual";
|
|
116
140
|
function between(a, b) {
|
|
@@ -148,6 +172,273 @@ function lightOf(part) {
|
|
|
148
172
|
};
|
|
149
173
|
}
|
|
150
174
|
|
|
175
|
+
// src/export/motion.ts
|
|
176
|
+
var LOOP_SECONDS = 4;
|
|
177
|
+
var cyclesOf = (rate) => Math.max(1, Math.round(Math.abs(rate) * LOOP_SECONDS)) * Math.sign(rate || 1);
|
|
178
|
+
var timeAccessors = new WeakMap;
|
|
179
|
+
function times(bin, keys) {
|
|
180
|
+
const t = new Float32Array(keys + 1).map((_, i) => i / keys * LOOP_SECONDS);
|
|
181
|
+
const byBin = timeAccessors.get(bin) ?? new Map;
|
|
182
|
+
timeAccessors.set(bin, byBin);
|
|
183
|
+
let input = byBin.get(keys);
|
|
184
|
+
if (input === undefined) {
|
|
185
|
+
input = bin.accessor(t, "SCALAR", undefined, true);
|
|
186
|
+
byBin.set(keys, input);
|
|
187
|
+
}
|
|
188
|
+
return { input, t };
|
|
189
|
+
}
|
|
190
|
+
function motionChannel(bin, motion, node, rest) {
|
|
191
|
+
const rate = motion.kind === "spin" ? motion.rps : motion.hz;
|
|
192
|
+
const cycles = cyclesOf(rate);
|
|
193
|
+
const keys = Math.max(24, Math.abs(cycles) * (motion.kind === "spin" ? 12 : 16));
|
|
194
|
+
const { input, t } = times(bin, keys);
|
|
195
|
+
const phase = (time) => time / LOOP_SECONDS * cycles * Math.PI * 2;
|
|
196
|
+
const wave = (time) => motion.kind !== "spin" && motion.oneWay ? (1 - Math.cos(phase(time))) / 2 : Math.sin(phase(time));
|
|
197
|
+
if (motion.kind === "slide") {
|
|
198
|
+
const values = new Float32Array((keys + 1) * 3);
|
|
199
|
+
t.forEach((time, i) => {
|
|
200
|
+
const s = wave(time);
|
|
201
|
+
values.set([0, 1, 2].map((k) => (rest[k] ?? 0) + (motion.offset[k] ?? 0) * s), i * 3);
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
sampler: { input, output: bin.accessor(values, "VEC3"), interpolation: "LINEAR" },
|
|
205
|
+
channel: { target: { node, path: "translation" } }
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const values = new Float32Array((keys + 1) * 4);
|
|
209
|
+
const peak = motion.kind === "sway" ? motion.degrees * Math.PI / 180 : 0;
|
|
210
|
+
t.forEach((time, i) => {
|
|
211
|
+
const angle = motion.kind === "spin" ? phase(time) : peak * wave(time);
|
|
212
|
+
values.set(quatFromAxisAngle2(motion.axis, angle), i * 4);
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
sampler: { input, output: bin.accessor(values, "VEC4"), interpolation: "LINEAR" },
|
|
216
|
+
channel: { target: { node, path: "rotation" } }
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/export/tangents.ts
|
|
221
|
+
function tangentsOf(m) {
|
|
222
|
+
const n = m.positions.length / 3;
|
|
223
|
+
const tan = new Float32Array(n * 3);
|
|
224
|
+
const bit = new Float32Array(n * 3);
|
|
225
|
+
const P = m.positions;
|
|
226
|
+
const U = m.uvs;
|
|
227
|
+
for (let t = 0;t < m.indices.length; t += 3) {
|
|
228
|
+
const a = m.indices[t] ?? 0;
|
|
229
|
+
const b = m.indices[t + 1] ?? 0;
|
|
230
|
+
const c = m.indices[t + 2] ?? 0;
|
|
231
|
+
const e1x = (P[b * 3] ?? 0) - (P[a * 3] ?? 0);
|
|
232
|
+
const e1y = (P[b * 3 + 1] ?? 0) - (P[a * 3 + 1] ?? 0);
|
|
233
|
+
const e1z = (P[b * 3 + 2] ?? 0) - (P[a * 3 + 2] ?? 0);
|
|
234
|
+
const e2x = (P[c * 3] ?? 0) - (P[a * 3] ?? 0);
|
|
235
|
+
const e2y = (P[c * 3 + 1] ?? 0) - (P[a * 3 + 1] ?? 0);
|
|
236
|
+
const e2z = (P[c * 3 + 2] ?? 0) - (P[a * 3 + 2] ?? 0);
|
|
237
|
+
const du1 = (U[b * 2] ?? 0) - (U[a * 2] ?? 0);
|
|
238
|
+
const dv1 = -((U[b * 2 + 1] ?? 0) - (U[a * 2 + 1] ?? 0));
|
|
239
|
+
const du2 = (U[c * 2] ?? 0) - (U[a * 2] ?? 0);
|
|
240
|
+
const dv2 = -((U[c * 2 + 1] ?? 0) - (U[a * 2 + 1] ?? 0));
|
|
241
|
+
const det = du1 * dv2 - du2 * dv1;
|
|
242
|
+
if (Math.abs(det) < 0.000000000001)
|
|
243
|
+
continue;
|
|
244
|
+
const r = 1 / det;
|
|
245
|
+
const tx = (e1x * dv2 - e2x * dv1) * r;
|
|
246
|
+
const ty = (e1y * dv2 - e2y * dv1) * r;
|
|
247
|
+
const tz = (e1z * dv2 - e2z * dv1) * r;
|
|
248
|
+
const bx = (e2x * du1 - e1x * du2) * r;
|
|
249
|
+
const by = (e2y * du1 - e1y * du2) * r;
|
|
250
|
+
const bz = (e2z * du1 - e1z * du2) * r;
|
|
251
|
+
for (const v of [a, b, c]) {
|
|
252
|
+
tan[v * 3] = (tan[v * 3] ?? 0) + tx;
|
|
253
|
+
tan[v * 3 + 1] = (tan[v * 3 + 1] ?? 0) + ty;
|
|
254
|
+
tan[v * 3 + 2] = (tan[v * 3 + 2] ?? 0) + tz;
|
|
255
|
+
bit[v * 3] = (bit[v * 3] ?? 0) + bx;
|
|
256
|
+
bit[v * 3 + 1] = (bit[v * 3 + 1] ?? 0) + by;
|
|
257
|
+
bit[v * 3 + 2] = (bit[v * 3 + 2] ?? 0) + bz;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const out = new Float32Array(n * 4);
|
|
261
|
+
for (let v = 0;v < n; v++) {
|
|
262
|
+
const nx = m.normals[v * 3] ?? 0;
|
|
263
|
+
const ny = m.normals[v * 3 + 1] ?? 0;
|
|
264
|
+
const nz = m.normals[v * 3 + 2] ?? 1;
|
|
265
|
+
let tx = tan[v * 3] ?? 0;
|
|
266
|
+
let ty = tan[v * 3 + 1] ?? 0;
|
|
267
|
+
let tz = tan[v * 3 + 2] ?? 0;
|
|
268
|
+
const d = nx * tx + ny * ty + nz * tz;
|
|
269
|
+
tx -= nx * d;
|
|
270
|
+
ty -= ny * d;
|
|
271
|
+
tz -= nz * d;
|
|
272
|
+
let len = Math.hypot(tx, ty, tz);
|
|
273
|
+
if (len < 0.00000001) {
|
|
274
|
+
[tx, ty, tz] = Math.abs(nx) < 0.9 ? [0, -nz, ny] : [nz, 0, -nx];
|
|
275
|
+
len = Math.hypot(tx, ty, tz) || 1;
|
|
276
|
+
}
|
|
277
|
+
tx /= len;
|
|
278
|
+
ty /= len;
|
|
279
|
+
tz /= len;
|
|
280
|
+
const cx = ny * tz - nz * ty;
|
|
281
|
+
const cy = nz * tx - nx * tz;
|
|
282
|
+
const cz = nx * ty - ny * tx;
|
|
283
|
+
const w = cx * (bit[v * 3] ?? 0) + cy * (bit[v * 3 + 1] ?? 0) + cz * (bit[v * 3 + 2] ?? 0);
|
|
284
|
+
out.set([tx, ty, tz, w < 0 ? -1 : 1], v * 4);
|
|
285
|
+
}
|
|
286
|
+
return out;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// src/export/primitive.ts
|
|
290
|
+
function writePrimitive(bin, m, material, tangents) {
|
|
291
|
+
const colors = new Uint16Array(m.colors.length / 3 * 4);
|
|
292
|
+
const q = (v) => Math.round(Math.min(1, Math.max(0, v)) * 65535);
|
|
293
|
+
for (let i = 0;i < m.colors.length / 3; i++)
|
|
294
|
+
colors.set([q(m.colors[i * 3] ?? 1), q(m.colors[i * 3 + 1] ?? 1), q(m.colors[i * 3 + 2] ?? 1), 65535], i * 4);
|
|
295
|
+
return {
|
|
296
|
+
attributes: {
|
|
297
|
+
POSITION: bin.accessor(m.positions, "VEC3", ARRAY_BUFFER, true),
|
|
298
|
+
NORMAL: bin.accessor(m.normals, "VEC3", ARRAY_BUFFER),
|
|
299
|
+
TEXCOORD_0: bin.accessor(m.uvs, "VEC2", ARRAY_BUFFER),
|
|
300
|
+
COLOR_0: bin.accessor(colors, "VEC4", ARRAY_BUFFER, false, true),
|
|
301
|
+
...tangents ? { TANGENT: bin.accessor(tangentsOf(m), "VEC4", ARRAY_BUFFER) } : {}
|
|
302
|
+
},
|
|
303
|
+
indices: bin.accessor(m.positions.length / 3 <= 65535 ? Uint16Array.from(m.indices) : m.indices, "SCALAR", ELEMENT_ARRAY_BUFFER),
|
|
304
|
+
material
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/export/hierarchy.ts
|
|
309
|
+
var newDoc = (bin) => ({
|
|
310
|
+
bin,
|
|
311
|
+
nodes: [],
|
|
312
|
+
meshes: [],
|
|
313
|
+
lights: [],
|
|
314
|
+
samplers: [],
|
|
315
|
+
channels: [],
|
|
316
|
+
motionSamplers: new Map,
|
|
317
|
+
lightIndex: new Map
|
|
318
|
+
});
|
|
319
|
+
function attach(doc, parentId, id) {
|
|
320
|
+
const parent = doc.nodes[parentId];
|
|
321
|
+
if (!parent)
|
|
322
|
+
return;
|
|
323
|
+
parent["children"] = [...parent["children"] ?? [], id];
|
|
324
|
+
}
|
|
325
|
+
function lightIndexOf(doc, light) {
|
|
326
|
+
const key = JSON.stringify(light);
|
|
327
|
+
const known = doc.lightIndex.get(key);
|
|
328
|
+
if (known !== undefined)
|
|
329
|
+
return known;
|
|
330
|
+
doc.lights.push(light);
|
|
331
|
+
doc.lightIndex.set(key, doc.lights.length - 1);
|
|
332
|
+
return doc.lights.length - 1;
|
|
333
|
+
}
|
|
334
|
+
function addMotion(doc, part, id) {
|
|
335
|
+
if (!part.motion)
|
|
336
|
+
return;
|
|
337
|
+
const key = JSON.stringify([part.motion, part.at]);
|
|
338
|
+
let sampler = doc.motionSamplers.get(key);
|
|
339
|
+
let channel;
|
|
340
|
+
if (sampler === undefined) {
|
|
341
|
+
const written = motionChannel(doc.bin, part.motion, id, part.at);
|
|
342
|
+
doc.samplers.push(written.sampler);
|
|
343
|
+
sampler = doc.samplers.length - 1;
|
|
344
|
+
doc.motionSamplers.set(key, sampler);
|
|
345
|
+
channel = written.channel;
|
|
346
|
+
} else {
|
|
347
|
+
channel = {
|
|
348
|
+
target: { node: id, path: part.motion.kind === "slide" ? "translation" : "rotation" }
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
doc.channels.push({ ...channel, sampler });
|
|
352
|
+
}
|
|
353
|
+
function writeHierarchy(doc, asset, rootName, o) {
|
|
354
|
+
doc.nodes.push({ name: rootName, children: [] });
|
|
355
|
+
const root = doc.nodes.length - 1;
|
|
356
|
+
const index = new Map;
|
|
357
|
+
asset.parts.forEach((part, i) => {
|
|
358
|
+
const node = { name: part.name, translation: [...part.at] };
|
|
359
|
+
if (part.yaw)
|
|
360
|
+
node["rotation"] = [...quatFromAxisAngle2([0, 0, 1], part.yaw)];
|
|
361
|
+
if (part.emitter || part.socket) {
|
|
362
|
+
node["extras"] = {
|
|
363
|
+
ts23d: {
|
|
364
|
+
...part.emitter ? { emitter: part.emitter } : {},
|
|
365
|
+
...part.socket ? { socket: part.socket } : {}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
if (part.mesh && part.mesh.indices.length > 0) {
|
|
370
|
+
doc.meshes.push({
|
|
371
|
+
name: part.name,
|
|
372
|
+
primitives: [writePrimitive(doc.bin, part.mesh, o.materialOf(part, i), o.withSheet)]
|
|
373
|
+
});
|
|
374
|
+
node["mesh"] = doc.meshes.length - 1;
|
|
375
|
+
}
|
|
376
|
+
doc.nodes.push(node);
|
|
377
|
+
const id = doc.nodes.length - 1;
|
|
378
|
+
index.set(part.name, id);
|
|
379
|
+
attach(doc, part.parent === null ? root : index.get(part.parent) ?? root, id);
|
|
380
|
+
const lit = lightOf(part);
|
|
381
|
+
if (lit) {
|
|
382
|
+
doc.nodes.push({
|
|
383
|
+
name: `${part.name}_light`,
|
|
384
|
+
rotation: [...lit.rotation],
|
|
385
|
+
extensions: { [LIGHTS]: { light: lightIndexOf(doc, lit.light) } }
|
|
386
|
+
});
|
|
387
|
+
attach(doc, id, doc.nodes.length - 1);
|
|
388
|
+
}
|
|
389
|
+
if (o.animations)
|
|
390
|
+
addMotion(doc, part, id);
|
|
391
|
+
});
|
|
392
|
+
return root;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/export/lod-coverage.ts
|
|
396
|
+
var MSFT_LOD2 = "MSFT_lod";
|
|
397
|
+
var SCREEN_COVERAGE2 = "MSFT_screencoverage";
|
|
398
|
+
var tris = (a) => a.parts.reduce((s, p) => s + (p.mesh ? p.mesh.indices.length / 3 : 0), 0);
|
|
399
|
+
function extent(a) {
|
|
400
|
+
if (a.real)
|
|
401
|
+
return Math.max(a.real.length, a.real.width, a.real.height);
|
|
402
|
+
const lo = [Infinity, Infinity, Infinity];
|
|
403
|
+
const hi = [-Infinity, -Infinity, -Infinity];
|
|
404
|
+
for (const mesh of worldMeshes2(a.parts).values()) {
|
|
405
|
+
const p = mesh.positions;
|
|
406
|
+
for (let i = 0;i < p.length; i++) {
|
|
407
|
+
const k = i % 3;
|
|
408
|
+
const v = p[i] ?? 0;
|
|
409
|
+
lo[k] = Math.min(lo[k] ?? 0, v);
|
|
410
|
+
hi[k] = Math.max(hi[k] ?? 0, v);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return Math.max(0, ...hi.map((h, k) => h - (lo[k] ?? 0)));
|
|
414
|
+
}
|
|
415
|
+
var clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
|
|
416
|
+
var round = (v) => Math.round(v * 1000) / 1000;
|
|
417
|
+
function defaultCoverage2(lods) {
|
|
418
|
+
const byLod = new Map(lods.map((a) => [a.lod, tris(a)]));
|
|
419
|
+
const top = lods[0];
|
|
420
|
+
const t0 = Math.max(1, top ? tris(top) : 1);
|
|
421
|
+
const ratio = (lod) => (byLod.get(lod) ?? t0) / t0;
|
|
422
|
+
const c1 = round(clamp(Math.sqrt(ratio(1)), 0.1, 0.6));
|
|
423
|
+
const c2 = round(clamp(Math.sqrt(ratio(2)), 0.02, c1 / 2));
|
|
424
|
+
const cull = top && extent(top) >= 10 ? 0.002 : 0.01;
|
|
425
|
+
return [c1, c2, Math.min(cull, round(c2 / 2))];
|
|
426
|
+
}
|
|
427
|
+
function checkCoverage2(c, asset) {
|
|
428
|
+
const [a = -1, b = -1, cull = -1] = c;
|
|
429
|
+
if (c.length !== 3 || !(a < 1 && a > b && b > cull && cull >= 0))
|
|
430
|
+
throw new Ts23dError2("T3D_RECIPE_INVALID", {
|
|
431
|
+
cause: `lodCoverage ${JSON.stringify(c)} on '${asset}' is not strictly descending in [0, 1)`,
|
|
432
|
+
fix: "give [LOD0→LOD1, LOD1→LOD2, cull] screen-height fractions, e.g. [0.5, 0.2, 0.01]; 0 = never cull"
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
function coverageFor2(levels, c) {
|
|
436
|
+
return levels.map((_, j) => {
|
|
437
|
+
const next = levels[j + 1];
|
|
438
|
+
return next === undefined ? c[2] : c[next - 1] ?? c[2];
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
151
442
|
// src/export/materials.ts
|
|
152
443
|
var MATERIALS = {
|
|
153
444
|
opaque: {
|
|
@@ -341,7 +632,7 @@ function mergeToPivots2(asset, glow = []) {
|
|
|
341
632
|
}
|
|
342
633
|
|
|
343
634
|
// src/export/version.ts
|
|
344
|
-
var VERSION = "0.
|
|
635
|
+
var VERSION = "0.2.0";
|
|
345
636
|
var GENERATOR = `@developerz.ai/ts23d ${VERSION}`;
|
|
346
637
|
|
|
347
638
|
// src/export/metadata.ts
|
|
@@ -371,6 +662,7 @@ function metadata(name, meta) {
|
|
|
371
662
|
...meta.copyright ? { "dc:rights": alt(meta.copyright) } : {},
|
|
372
663
|
...meta.license ? { "xmpRights:UsageTerms": alt(meta.license) } : {},
|
|
373
664
|
...meta.sources?.length ? { "dc:relation": { "@set": [...meta.sources] } } : {},
|
|
665
|
+
...meta.credits?.length ? { "dc:contributor": { "@set": [...meta.credits] } } : {},
|
|
374
666
|
"xmp:CreatorTool": GENERATOR
|
|
375
667
|
};
|
|
376
668
|
return {
|
|
@@ -380,51 +672,6 @@ function metadata(name, meta) {
|
|
|
380
672
|
};
|
|
381
673
|
}
|
|
382
674
|
|
|
383
|
-
// src/export/motion.ts
|
|
384
|
-
var LOOP_SECONDS = 4;
|
|
385
|
-
var cyclesOf = (rate) => Math.max(1, Math.round(Math.abs(rate) * LOOP_SECONDS)) * Math.sign(rate || 1);
|
|
386
|
-
var timeAccessors = new WeakMap;
|
|
387
|
-
function times(bin, keys) {
|
|
388
|
-
const t = new Float32Array(keys + 1).map((_, i) => i / keys * LOOP_SECONDS);
|
|
389
|
-
const byBin = timeAccessors.get(bin) ?? new Map;
|
|
390
|
-
timeAccessors.set(bin, byBin);
|
|
391
|
-
let input = byBin.get(keys);
|
|
392
|
-
if (input === undefined) {
|
|
393
|
-
input = bin.accessor(t, "SCALAR", undefined, true);
|
|
394
|
-
byBin.set(keys, input);
|
|
395
|
-
}
|
|
396
|
-
return { input, t };
|
|
397
|
-
}
|
|
398
|
-
function motionChannel(bin, motion, node, rest) {
|
|
399
|
-
const rate = motion.kind === "spin" ? motion.rps : motion.hz;
|
|
400
|
-
const cycles = cyclesOf(rate);
|
|
401
|
-
const keys = Math.max(24, Math.abs(cycles) * (motion.kind === "spin" ? 12 : 16));
|
|
402
|
-
const { input, t } = times(bin, keys);
|
|
403
|
-
const phase = (time) => time / LOOP_SECONDS * cycles * Math.PI * 2;
|
|
404
|
-
const wave = (time) => motion.kind !== "spin" && motion.oneWay ? (1 - Math.cos(phase(time))) / 2 : Math.sin(phase(time));
|
|
405
|
-
if (motion.kind === "slide") {
|
|
406
|
-
const values = new Float32Array((keys + 1) * 3);
|
|
407
|
-
t.forEach((time, i) => {
|
|
408
|
-
const s = wave(time);
|
|
409
|
-
values.set([0, 1, 2].map((k) => (rest[k] ?? 0) + (motion.offset[k] ?? 0) * s), i * 3);
|
|
410
|
-
});
|
|
411
|
-
return {
|
|
412
|
-
sampler: { input, output: bin.accessor(values, "VEC3"), interpolation: "LINEAR" },
|
|
413
|
-
channel: { target: { node, path: "translation" } }
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
const values = new Float32Array((keys + 1) * 4);
|
|
417
|
-
const peak = motion.kind === "sway" ? motion.degrees * Math.PI / 180 : 0;
|
|
418
|
-
t.forEach((time, i) => {
|
|
419
|
-
const angle = motion.kind === "spin" ? phase(time) : peak * wave(time);
|
|
420
|
-
values.set(quatFromAxisAngle2(motion.axis, angle), i * 4);
|
|
421
|
-
});
|
|
422
|
-
return {
|
|
423
|
-
sampler: { input, output: bin.accessor(values, "VEC4"), interpolation: "LINEAR" },
|
|
424
|
-
channel: { target: { node, path: "rotation" } }
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
|
|
428
675
|
// src/export/optimize-parts.ts
|
|
429
676
|
function summarize2(parts, optimized) {
|
|
430
677
|
const sum = (f) => parts.reduce((s, r) => s + f(r), 0);
|
|
@@ -476,94 +723,6 @@ function optimizeParts2(asset, o) {
|
|
|
476
723
|
return { asset: { ...asset, parts }, report: summarize2(reports, o !== false) };
|
|
477
724
|
}
|
|
478
725
|
|
|
479
|
-
// src/export/tangents.ts
|
|
480
|
-
function tangentsOf(m) {
|
|
481
|
-
const n = m.positions.length / 3;
|
|
482
|
-
const tan = new Float32Array(n * 3);
|
|
483
|
-
const bit = new Float32Array(n * 3);
|
|
484
|
-
const P = m.positions;
|
|
485
|
-
const U = m.uvs;
|
|
486
|
-
for (let t = 0;t < m.indices.length; t += 3) {
|
|
487
|
-
const a = m.indices[t] ?? 0;
|
|
488
|
-
const b = m.indices[t + 1] ?? 0;
|
|
489
|
-
const c = m.indices[t + 2] ?? 0;
|
|
490
|
-
const e1x = (P[b * 3] ?? 0) - (P[a * 3] ?? 0);
|
|
491
|
-
const e1y = (P[b * 3 + 1] ?? 0) - (P[a * 3 + 1] ?? 0);
|
|
492
|
-
const e1z = (P[b * 3 + 2] ?? 0) - (P[a * 3 + 2] ?? 0);
|
|
493
|
-
const e2x = (P[c * 3] ?? 0) - (P[a * 3] ?? 0);
|
|
494
|
-
const e2y = (P[c * 3 + 1] ?? 0) - (P[a * 3 + 1] ?? 0);
|
|
495
|
-
const e2z = (P[c * 3 + 2] ?? 0) - (P[a * 3 + 2] ?? 0);
|
|
496
|
-
const du1 = (U[b * 2] ?? 0) - (U[a * 2] ?? 0);
|
|
497
|
-
const dv1 = -((U[b * 2 + 1] ?? 0) - (U[a * 2 + 1] ?? 0));
|
|
498
|
-
const du2 = (U[c * 2] ?? 0) - (U[a * 2] ?? 0);
|
|
499
|
-
const dv2 = -((U[c * 2 + 1] ?? 0) - (U[a * 2 + 1] ?? 0));
|
|
500
|
-
const det = du1 * dv2 - du2 * dv1;
|
|
501
|
-
if (Math.abs(det) < 0.000000000001)
|
|
502
|
-
continue;
|
|
503
|
-
const r = 1 / det;
|
|
504
|
-
const tx = (e1x * dv2 - e2x * dv1) * r;
|
|
505
|
-
const ty = (e1y * dv2 - e2y * dv1) * r;
|
|
506
|
-
const tz = (e1z * dv2 - e2z * dv1) * r;
|
|
507
|
-
const bx = (e2x * du1 - e1x * du2) * r;
|
|
508
|
-
const by = (e2y * du1 - e1y * du2) * r;
|
|
509
|
-
const bz = (e2z * du1 - e1z * du2) * r;
|
|
510
|
-
for (const v of [a, b, c]) {
|
|
511
|
-
tan[v * 3] = (tan[v * 3] ?? 0) + tx;
|
|
512
|
-
tan[v * 3 + 1] = (tan[v * 3 + 1] ?? 0) + ty;
|
|
513
|
-
tan[v * 3 + 2] = (tan[v * 3 + 2] ?? 0) + tz;
|
|
514
|
-
bit[v * 3] = (bit[v * 3] ?? 0) + bx;
|
|
515
|
-
bit[v * 3 + 1] = (bit[v * 3 + 1] ?? 0) + by;
|
|
516
|
-
bit[v * 3 + 2] = (bit[v * 3 + 2] ?? 0) + bz;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
const out = new Float32Array(n * 4);
|
|
520
|
-
for (let v = 0;v < n; v++) {
|
|
521
|
-
const nx = m.normals[v * 3] ?? 0;
|
|
522
|
-
const ny = m.normals[v * 3 + 1] ?? 0;
|
|
523
|
-
const nz = m.normals[v * 3 + 2] ?? 1;
|
|
524
|
-
let tx = tan[v * 3] ?? 0;
|
|
525
|
-
let ty = tan[v * 3 + 1] ?? 0;
|
|
526
|
-
let tz = tan[v * 3 + 2] ?? 0;
|
|
527
|
-
const d = nx * tx + ny * ty + nz * tz;
|
|
528
|
-
tx -= nx * d;
|
|
529
|
-
ty -= ny * d;
|
|
530
|
-
tz -= nz * d;
|
|
531
|
-
let len = Math.hypot(tx, ty, tz);
|
|
532
|
-
if (len < 0.00000001) {
|
|
533
|
-
[tx, ty, tz] = Math.abs(nx) < 0.9 ? [0, -nz, ny] : [nz, 0, -nx];
|
|
534
|
-
len = Math.hypot(tx, ty, tz) || 1;
|
|
535
|
-
}
|
|
536
|
-
tx /= len;
|
|
537
|
-
ty /= len;
|
|
538
|
-
tz /= len;
|
|
539
|
-
const cx = ny * tz - nz * ty;
|
|
540
|
-
const cy = nz * tx - nx * tz;
|
|
541
|
-
const cz = nx * ty - ny * tx;
|
|
542
|
-
const w = cx * (bit[v * 3] ?? 0) + cy * (bit[v * 3 + 1] ?? 0) + cz * (bit[v * 3 + 2] ?? 0);
|
|
543
|
-
out.set([tx, ty, tz, w < 0 ? -1 : 1], v * 4);
|
|
544
|
-
}
|
|
545
|
-
return out;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// src/export/primitive.ts
|
|
549
|
-
function writePrimitive(bin, m, material, tangents) {
|
|
550
|
-
const colors = new Uint16Array(m.colors.length / 3 * 4);
|
|
551
|
-
const q = (v) => Math.round(Math.min(1, Math.max(0, v)) * 65535);
|
|
552
|
-
for (let i = 0;i < m.colors.length / 3; i++)
|
|
553
|
-
colors.set([q(m.colors[i * 3] ?? 1), q(m.colors[i * 3 + 1] ?? 1), q(m.colors[i * 3 + 2] ?? 1), 65535], i * 4);
|
|
554
|
-
return {
|
|
555
|
-
attributes: {
|
|
556
|
-
POSITION: bin.accessor(m.positions, "VEC3", ARRAY_BUFFER, true),
|
|
557
|
-
NORMAL: bin.accessor(m.normals, "VEC3", ARRAY_BUFFER),
|
|
558
|
-
TEXCOORD_0: bin.accessor(m.uvs, "VEC2", ARRAY_BUFFER),
|
|
559
|
-
COLOR_0: bin.accessor(colors, "VEC4", ARRAY_BUFFER, false, true),
|
|
560
|
-
...tangents ? { TANGENT: bin.accessor(tangentsOf(m), "VEC4", ARRAY_BUFFER) } : {}
|
|
561
|
-
},
|
|
562
|
-
indices: bin.accessor(m.positions.length / 3 <= 65535 ? Uint16Array.from(m.indices) : m.indices, "SCALAR", ELEMENT_ARRAY_BUFFER),
|
|
563
|
-
material
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
|
|
567
726
|
// src/export/textures.ts
|
|
568
727
|
var SHEET_MAPS2 = ["albedo", "normal", "orm"];
|
|
569
728
|
var sheetFileName2 = (map, prefix = "trim_sheet") => `${prefix}_${map}.png`;
|
|
@@ -620,18 +779,25 @@ function sheetGltf(sheet, views, offset) {
|
|
|
620
779
|
|
|
621
780
|
// src/export/glb.ts
|
|
622
781
|
var Z_UP_TO_Y_UP = [-0.5, -0.5, -0.5, 0.5];
|
|
623
|
-
function restClip(bin) {
|
|
782
|
+
function restClip(bin, roots) {
|
|
624
783
|
const input = bin.accessor(new Float32Array([0, 1]), "SCALAR", undefined, true);
|
|
625
784
|
const output = bin.accessor(new Float32Array([...Z_UP_TO_Y_UP, ...Z_UP_TO_Y_UP]), "VEC4");
|
|
626
785
|
return {
|
|
627
786
|
name: "rest",
|
|
628
787
|
samplers: [{ input, output, interpolation: "STEP" }],
|
|
629
|
-
channels:
|
|
788
|
+
channels: roots.map((node) => ({ sampler: 0, target: { node, path: "rotation" } }))
|
|
630
789
|
};
|
|
631
790
|
}
|
|
632
791
|
function toGlb2(input, o = {}) {
|
|
633
792
|
return exportGlb2(input, o).glb;
|
|
634
793
|
}
|
|
794
|
+
function exportGlb2(input, o = {}) {
|
|
795
|
+
const { glb, reports } = exportLodGlb2([input], o);
|
|
796
|
+
return { glb, report: reports[0] ?? summarize2([], false) };
|
|
797
|
+
}
|
|
798
|
+
function toLodGlb2(lods, o = {}) {
|
|
799
|
+
return exportLodGlb2(lods, o).glb;
|
|
800
|
+
}
|
|
635
801
|
function checkGlow(rules) {
|
|
636
802
|
for (const r of rules)
|
|
637
803
|
if ((r.strength ?? 4) < 0 || (r.color ?? [0, 0, 0]).some((c) => c < 0 || c > 1))
|
|
@@ -640,106 +806,87 @@ function checkGlow(rules) {
|
|
|
640
806
|
fix: "colour is linear 0..1 (hex() converts sRGB); brightness goes in `strength`"
|
|
641
807
|
});
|
|
642
808
|
}
|
|
643
|
-
function
|
|
644
|
-
const
|
|
645
|
-
|
|
809
|
+
function checkLods(lods) {
|
|
810
|
+
const names = new Set(lods.map((l) => l.name));
|
|
811
|
+
const levels = lods.map((l) => l.lod);
|
|
812
|
+
if (lods.length === 0 || names.size !== 1 || levels.some((l, i) => i > 0 && l <= (levels[i - 1] ?? 0)))
|
|
813
|
+
throw new Ts23dError2("T3D_RECIPE_INVALID", {
|
|
814
|
+
cause: `exportLodGlb got LODs [${levels.join(", ")}] of [${[...names].join(", ")}]`,
|
|
815
|
+
fix: "pass compile(asset, { lod }) results of ONE asset, highest detail first: LOD0, LOD1, LOD2"
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
function prepare(input, o, glow) {
|
|
646
819
|
const opt = o.optimize === false ? false : o.optimize === true ? {} : o.optimize ?? {};
|
|
647
820
|
const merged = o.keepParts ? input : mergeToPivots2(input, glow.map((g) => g.parts));
|
|
648
821
|
const { asset, report } = optimizeParts2(merged, opt);
|
|
649
822
|
const glowRes = glow.map((g) => g.parts.map(globRe));
|
|
650
823
|
const glowOf = (p, i) => glowLayer.get(merged.parts[i] ?? p) ?? (o.keepParts ? glowRes.findIndex((rs) => rs.some((r) => r.test(p.name))) : -1);
|
|
651
|
-
|
|
824
|
+
return { asset, report, glowOf };
|
|
825
|
+
}
|
|
826
|
+
function exportLodGlb2(lods, o = {}) {
|
|
827
|
+
checkLods(lods);
|
|
828
|
+
const top = lods[0];
|
|
829
|
+
const glow = o.glow ?? top.glow ?? [];
|
|
830
|
+
checkGlow(glow);
|
|
831
|
+
const preps = lods.map((l) => prepare(l, o, glow));
|
|
832
|
+
const withSheet = o.sheet !== undefined;
|
|
833
|
+
const mats = materialsFor(new Set(preps.flatMap((p) => p.asset.parts.flatMap((q) => q.surface ? [q.surface] : []))), withSheet);
|
|
652
834
|
const glowAt = mats.materials.length;
|
|
653
|
-
const materials = [
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
const nodes = [{ name: asset.name, children: [] }];
|
|
660
|
-
const index = new Map;
|
|
661
|
-
const samplers = [];
|
|
662
|
-
const channels = [];
|
|
663
|
-
const lights = [];
|
|
664
|
-
const attach = (parentId, id) => {
|
|
665
|
-
const parent = nodes[parentId];
|
|
666
|
-
if (!parent)
|
|
667
|
-
return;
|
|
668
|
-
parent["children"] = [...parent["children"] ?? [], id];
|
|
669
|
-
};
|
|
670
|
-
asset.parts.forEach((part, i) => {
|
|
671
|
-
const node = { name: part.name, translation: [...part.at] };
|
|
672
|
-
if (part.yaw)
|
|
673
|
-
node["rotation"] = [...quatFromAxisAngle2([0, 0, 1], part.yaw)];
|
|
674
|
-
if (part.emitter || part.socket) {
|
|
675
|
-
node["extras"] = {
|
|
676
|
-
ts23d: {
|
|
677
|
-
...part.emitter ? { emitter: part.emitter } : {},
|
|
678
|
-
...part.socket ? { socket: part.socket } : {}
|
|
679
|
-
}
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
if (part.mesh && part.mesh.indices.length > 0) {
|
|
835
|
+
const materials = [...mats.materials, ...glow.map((g, i) => glowMaterial(g, i, withSheet))];
|
|
836
|
+
const doc = newDoc(new BinWriter);
|
|
837
|
+
const roots = preps.map(({ asset, glowOf }, k) => writeHierarchy(doc, asset, k === 0 ? asset.name : `${asset.name}_LOD${asset.lod}`, {
|
|
838
|
+
withSheet,
|
|
839
|
+
animations: o.animations === true,
|
|
840
|
+
materialOf: (part, i) => {
|
|
683
841
|
const g = glowOf(part, i);
|
|
684
|
-
|
|
685
|
-
meshes.push({
|
|
686
|
-
name: part.name,
|
|
687
|
-
primitives: [writePrimitive(bin, part.mesh, material, o.sheet !== undefined)]
|
|
688
|
-
});
|
|
689
|
-
node["mesh"] = meshes.length - 1;
|
|
842
|
+
return g >= 0 ? glowAt + g : mats.index.get(part.surface ?? "opaque") ?? 0;
|
|
690
843
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
channels.push({ ...channel, sampler: samplers.length - 1 });
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
const animations = channels.length ? [restClip(bin), { name: "run", samplers, channels }] : [];
|
|
844
|
+
}));
|
|
845
|
+
for (const r of roots) {
|
|
846
|
+
const node = doc.nodes[r];
|
|
847
|
+
if (node)
|
|
848
|
+
node["rotation"] = Z_UP_TO_Y_UP;
|
|
849
|
+
}
|
|
850
|
+
const coverage = [];
|
|
851
|
+
const rootNode = doc.nodes[0];
|
|
852
|
+
if (roots.length > 1 && rootNode) {
|
|
853
|
+
const c = o.lodCoverage ?? top.lodCoverage ?? defaultCoverage2(lods);
|
|
854
|
+
checkCoverage2(c, top.name);
|
|
855
|
+
coverage.push(...coverageFor2(lods.map((l) => l.lod), c));
|
|
856
|
+
rootNode["extensions"] = { [MSFT_LOD2]: { ids: roots.slice(1) } };
|
|
857
|
+
rootNode["extras"] = { [SCREEN_COVERAGE2]: coverage };
|
|
858
|
+
}
|
|
859
|
+
const { bin, lights, samplers, channels } = doc;
|
|
860
|
+
const animations = channels.length ? [restClip(bin, roots), { name: "run", samplers, channels }] : [];
|
|
712
861
|
const geometry = bin.bytes();
|
|
713
862
|
const tex = o.sheet ? sheetGltf(o.sheet, bin.views, geometry.byteLength) : null;
|
|
714
863
|
const body = tex?.tail.byteLength ? concat(geometry, tex.tail) : geometry;
|
|
715
|
-
const meta = metadata(
|
|
864
|
+
const meta = metadata(top.name, withCredits(top, o.meta ?? top.meta));
|
|
716
865
|
const used = [
|
|
717
866
|
...mats.extensionsUsed,
|
|
718
867
|
...glow.some((g) => (g.strength ?? 4) !== 1) ? [EMISSIVE_STRENGTH] : [],
|
|
719
868
|
...lights.length ? [LIGHTS] : [],
|
|
869
|
+
...coverage.length ? [MSFT_LOD2] : [],
|
|
720
870
|
...meta.used
|
|
721
871
|
].sort();
|
|
722
872
|
const extensions = {
|
|
723
873
|
...lights.length ? { [LIGHTS]: { lights } } : {},
|
|
724
874
|
...meta.extensions ?? {}
|
|
725
875
|
};
|
|
726
|
-
const root = nodes[0];
|
|
727
|
-
if (root)
|
|
728
|
-
root["rotation"] = Z_UP_TO_Y_UP;
|
|
729
876
|
const gltf = {
|
|
730
877
|
asset: meta.asset,
|
|
731
878
|
extras: {
|
|
732
|
-
kind:
|
|
733
|
-
lod:
|
|
879
|
+
kind: top.kind,
|
|
880
|
+
lod: coverage.length ? lods.map((l) => l.lod) : top.lod,
|
|
734
881
|
units: "metres",
|
|
735
882
|
up: "Z (rotated to glTF Y-up at the root)"
|
|
736
883
|
},
|
|
737
884
|
...used.length ? { extensionsUsed: used } : {},
|
|
738
885
|
...Object.keys(extensions).length ? { extensions } : {},
|
|
739
886
|
scene: 0,
|
|
740
|
-
scenes: [{ name:
|
|
741
|
-
nodes,
|
|
742
|
-
meshes,
|
|
887
|
+
scenes: [{ name: top.name, nodes: [0] }],
|
|
888
|
+
nodes: doc.nodes,
|
|
889
|
+
meshes: doc.meshes,
|
|
743
890
|
materials,
|
|
744
891
|
...tex ? tex.json : {},
|
|
745
892
|
buffers: [{ byteLength: body.byteLength }],
|
|
@@ -747,9 +894,9 @@ function exportGlb2(input, o = {}) {
|
|
|
747
894
|
accessors: bin.accessors,
|
|
748
895
|
...animations.length ? { animations } : {}
|
|
749
896
|
};
|
|
750
|
-
return { glb: packGlb(gltf, body), report };
|
|
897
|
+
return { glb: packGlb(gltf, body), reports: preps.map((p) => p.report), coverage };
|
|
751
898
|
}
|
|
752
|
-
export { mergeToPivots2, summarize2, optimizeParts2, SHEET_MAPS2, sheetFileName2, sheetPngs2, toGlb2, exportGlb2 };
|
|
899
|
+
export { MSFT_LOD2, SCREEN_COVERAGE2, defaultCoverage2, checkCoverage2, coverageFor2, mergeToPivots2, summarize2, optimizeParts2, SHEET_MAPS2, sheetFileName2, sheetPngs2, toGlb2, exportGlb2, toLodGlb2, exportLodGlb2 };
|
|
753
900
|
|
|
754
|
-
//# debugId=
|
|
755
|
-
//# sourceMappingURL=chunk-
|
|
901
|
+
//# debugId=48DF0BBA03847F0964756E2164756E21
|
|
902
|
+
//# sourceMappingURL=chunk-dbq4qf52.js.map
|