@needle-tools/gltf-build-pipeline 1.4.1-beta.13 → 1.4.1-beta.15

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 CHANGED
@@ -4,6 +4,10 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.4.1-beta.15] - 2023-04-02
8
+ - fix: issue where discarding all LODs might result in broken mesh due to simplify having modified the original mesh
9
+ - fix: don't produce LODs if GLB/glTF was produced with old generator
10
+
7
11
  ## [1.4.1-beta.13] - 2023-03-26
8
12
  - change: passthrough `NEEDLE_editor` & `NEEDLE_gltf_dependencies` extensions
9
13
 
@@ -20,5 +20,6 @@ export interface IExtensionWriter {
20
20
  assignTo?(obj: object): any;
21
21
  write(context: WriterContext, prop: IExtensibleProperty): void;
22
22
  }
23
+ export declare let currentGenerator: string;
23
24
  export declare function createOpaqueExtension(name: string, types: PropertyType | PropertyType[], opts?: Options): IOpaqueExtension;
24
25
  export {};
@@ -4,6 +4,7 @@ const ALL_PROPERTY_TYPES = [];
4
4
  for (const key in PropertyType) {
5
5
  ALL_PROPERTY_TYPES.push(PropertyType[key]);
6
6
  }
7
+ export let currentGenerator = "";
7
8
  // an opaque extension can be used to pass data through the gltf transform process
8
9
  // it should also be able to re-write/fix json pointers after the transformation which might have shuffled them around
9
10
  export function createOpaqueExtension(name, types, opts) {
@@ -18,6 +19,7 @@ export function createOpaqueExtension(name, types, opts) {
18
19
  // private roots: Array<OpaqueProperty> = [];
19
20
  jsonPointerHandler;
20
21
  read(context) {
22
+ currentGenerator = context.jsonDoc.json.asset?.generator;
21
23
  if (debugLog)
22
24
  console.log("READ " + EXTENSION_NAME);
23
25
  this.jsonPointerHandler = new JsonPointerHandler(this.document, EXTENSION_NAME);
@@ -1,7 +1,7 @@
1
1
  import { BufferUtils, Document, NodeIO, PropertyType } from '@gltf-transform/core';
2
2
  import { SIMPLIFY_DEFAULTS, WELD_DEFAULTS, listTextureSlots, sparse } from '@gltf-transform/functions';
3
3
  import { NEEDLE_PROGRESSIVE_EXTENSION_NAME, NEEDLE_progressive } from "../extensions/NEEDLE_progressive/index.js";
4
- import { createOpaqueExtension, NEEDLE_compression_texture, NEEDLE_mesh_compression, NEEDLE_progressive_mesh_settings, NEEDLE_progressive_texture_settings, registerExtensions as registerDefaultExtensions } from '../extensions/index.js';
4
+ import { createOpaqueExtension, currentGenerator, NEEDLE_compression_texture, NEEDLE_mesh_compression, NEEDLE_progressive_mesh_settings, NEEDLE_progressive_texture_settings, registerExtensions as registerDefaultExtensions } from '../extensions/index.js';
5
5
  import path from 'path';
6
6
  import { existsSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs';
7
7
  import { addMetaToCache, addToCache, getHash, getKey, tryGetFromCache, tryGetMetaFromCache } from '../cache/index.js';
@@ -299,6 +299,12 @@ export function make_progressive_meshes(filePath, _options, opts) {
299
299
  // const fileNameWithoutExtension = path.basename(filePath, path.extname(filePath));
300
300
  const outputDirectory = directory + "/";
301
301
  return createTransform("PROGRESSIVE_MESHES", async (doc, _context) => {
302
+ // this is to ensure we're not creating progressive meshes for engine versions that don't support loading them yet
303
+ // the generator should include the version or the app that produced the GLB too (needle engine repo: 2c00d0e304e205cf9d4ac0499faabb92a706a5c4)
304
+ if (currentGenerator == "Needle Engine") {
305
+ console.log("WARN: Skip creating mesh LODs - Unsupported generator found... Please update your editor integration");
306
+ return;
307
+ }
302
308
  if (isMeshLOD(filePath)) {
303
309
  console.log("Progressive Mesh Transform: skip lod at " + filePath);
304
310
  return Promise.resolve();
@@ -331,8 +337,13 @@ export function make_progressive_meshes(filePath, _options, opts) {
331
337
  }
332
338
  /** Map of visited GUID -> extension */
333
339
  const visited = new Map();
334
- const meshes = doc.getRoot().listMeshes();
340
+ const root = doc.getRoot();
341
+ const meshes = root.listMeshes();
335
342
  for (const mesh of meshes) {
343
+ await processMesh(mesh);
344
+ }
345
+ console.log(`[${NAME}]: Finished generating progressive meshes for \"${filename}\"`);
346
+ async function processMesh(mesh) {
336
347
  /** The size and vertex count of the original mesh */
337
348
  const originalMeshInformation = getMeshInformation(mesh);
338
349
  const { totalVertexCount: originalTotalVertexCount, maxVertexCount: originalMaxVertexCount } = originalMeshInformation;
@@ -340,7 +351,7 @@ export function make_progressive_meshes(filePath, _options, opts) {
340
351
  if (!settings) {
341
352
  if (originalMaxVertexCount < 32) {
342
353
  logger.debug(`[${NAME}] Skipping, no settings found and no primitive with more than 32 vertices. mesh[${index}] has ${originalTotalVertexCount} vertices (max: ${originalMaxVertexCount})`);
343
- continue;
354
+ return;
344
355
  }
345
356
  else {
346
357
  settings = {
@@ -352,12 +363,12 @@ export function make_progressive_meshes(filePath, _options, opts) {
352
363
  }
353
364
  else if (settings.generateLods === false) {
354
365
  logger.debug(`[${NAME}] progressive mesh disabled for mesh at index ${index++}`);
355
- continue;
366
+ return;
356
367
  }
357
368
  const progressiveExt = doc.createExtension(NEEDLE_progressive);
358
369
  if (!progressiveExt || !progressiveExt.createMesh) {
359
370
  logger.debug(`[${NAME}] Skipping because progressive extension is not available. ${index++}`);
360
- continue;
371
+ return;
361
372
  }
362
373
  // check if we have already produced LODs for this mesh
363
374
  let needsToGenerateLODs = true;
@@ -449,7 +460,11 @@ export function make_progressive_meshes(filePath, _options, opts) {
449
460
  let maxDensity = 0;
450
461
  let primitiveIndex = 0;
451
462
  const lodLevelInFile = generatedLODInfos.length;
463
+ const clonedData = new Array();
452
464
  for (const prim of mesh.listPrimitives()) {
465
+ const data = clonePrimitiveData(prim);
466
+ clonedData.push(data);
467
+ console.log(`[${NAME}] Simplify mesh[${index}] primitive[${primitiveIndex}] with ${data.indices.length / 3} triangles`);
453
468
  const lastLod = LODS[lodLevelInFile];
454
469
  // TODO: this should be run after simplification but then we need to change the runtime to use the LOD 0 density
455
470
  const density = calculateMeshDensity(prim);
@@ -476,7 +491,14 @@ export function make_progressive_meshes(filePath, _options, opts) {
476
491
  catch (err) {
477
492
  logger.error(`ERR: [${NAME}] Failed to remove LOD files for \"${mesh.getName()}\"`);
478
493
  }
479
- continue;
494
+ // reset data (simplify might have changed the mesh data that we cloned before)
495
+ const primitives = mesh.listPrimitives();
496
+ if (clonedData.length == primitives.length) {
497
+ for (let i = 0; i < primitives.length; i++) {
498
+ setPrimitiveData(primitives[i], clonedData[i]);
499
+ }
500
+ }
501
+ return;
480
502
  }
481
503
  if (generatedLODInfos.length > 0) {
482
504
  const model = progressiveExt.createMesh({
@@ -501,9 +523,31 @@ export function make_progressive_meshes(filePath, _options, opts) {
501
523
  }
502
524
  }
503
525
  }
504
- console.log(`[${NAME}]: Finished generating progressive meshes for \"${filename}\"`);
505
526
  });
506
527
  }
528
+ function clonePrimitiveData(prim) {
529
+ const indices = new Uint32Array(prim.getIndices().getArray());
530
+ const attributes = {};
531
+ for (const attr of prim.listSemantics()) {
532
+ const accessor = prim.getAttribute(attr);
533
+ if (accessor) {
534
+ attributes[attr] = new Float32Array(accessor.getArray());
535
+ }
536
+ }
537
+ return { indices, attributes };
538
+ }
539
+ function setPrimitiveData(prim, data) {
540
+ const indices = prim.getIndices();
541
+ if (indices) {
542
+ indices.setArray(data.indices);
543
+ }
544
+ for (const attr of prim.listSemantics()) {
545
+ const accessor = prim.getAttribute(attr);
546
+ if (accessor) {
547
+ accessor.setArray(data.attributes[attr]);
548
+ }
549
+ }
550
+ }
507
551
  /**
508
552
  * @param basePath the base path to save the lod files
509
553
  * @param level: 0 = original, 1 = first lod, 2 = second lod, ...
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-build-pipeline",
3
- "version": "1.4.1-beta.13",
3
+ "version": "1.4.1-beta.15",
4
4
  "description": "Pipeline and tools for optimizing gltf files using gltf-transform and compression settings within glTF extensions",
5
5
  "main": "index.mjs",
6
6
  "type": "module",