@needle-tools/gltf-build-pipeline 1.4.7 → 1.4.9

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,14 @@ 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.9] - 2023-04-23
8
+ - add: NEEDLE_progressive now have `hash` field for LODs which is generated using the content of the LOD and it's settings that produced it.
9
+ - fix: NEEDLE_progressive catches error when copying mesh with extensions where the copy operation fails
10
+
11
+ ## [1.4.8] - 2023-04-22
12
+ - fix: update sharp package to `^0.32.6`
13
+ - change: NEEDLE_progressive meshes max LOD error increased
14
+
7
15
  ## [1.4.7] - 2023-04-16
8
16
  - add: `asset.extras.needle` now contains information about used build pipeline
9
17
 
@@ -39,6 +39,10 @@ export declare function tryGetMetaFromCache(key: string, ignoreVersion?: boolean
39
39
  * @returns The key as a string.
40
40
  */
41
41
  export declare function getKey(property: ExtensibleProperty): string;
42
+ export declare function getKeyWithHash(property: ExtensibleProperty): {
43
+ key: string;
44
+ hash: number;
45
+ };
42
46
  /**
43
47
  * Get the hash for a property or an object.
44
48
  * @param property The property to get the hash for.
@@ -139,6 +139,15 @@ export function getKey(property) {
139
139
  const key = `${prefix}-${hash}`;
140
140
  return key;
141
141
  }
142
+ export function getKeyWithHash(property) {
143
+ let prefix = "prop";
144
+ if (property instanceof Texture) {
145
+ prefix = "image";
146
+ }
147
+ let hash = getHash(property);
148
+ const key = `${prefix}-${hash}`;
149
+ return { key, hash };
150
+ }
142
151
  /**
143
152
  * Get the hash for a property or an object.
144
153
  * @param property The property to get the hash for.
@@ -7,14 +7,19 @@ export type ProgressiveLoadingInfo = {
7
7
  lods?: Array<LodInfo>;
8
8
  };
9
9
  type LodInfo = {
10
+ /** Relative path to the LOD file */
10
11
  path: string;
12
+ /** Hash of the LOD file. It has been generated using the file content and settings */
13
+ hash: string;
11
14
  };
12
15
  export type ProgressiveTextureModel = ProgressiveLoadingInfo & {
13
16
  lods?: Array<LodInfo & {}>;
14
17
  };
15
18
  export type ProgressiveMeshModel = ProgressiveLoadingInfo & {
19
+ /** LOD0 vertex density. TODO: remove this since we now have a LODs array. This is just for supporting older engine versions */
16
20
  density: number;
17
21
  lods?: Array<LodInfo & {
22
+ /** Mesh vertex density */
18
23
  density: number;
19
24
  vertexCount: number;
20
25
  indexCount: number;
@@ -4,7 +4,7 @@ import { NEEDLE_PROGRESSIVE_EXTENSION_NAME, NEEDLE_progressive } from "../extens
4
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, { basename } from 'path';
6
6
  import { existsSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs';
7
- import { addMetaToCache, addToCache, getHash, getKey, tryGetFromCache, tryGetMetaFromCache } from '../cache/index.js';
7
+ import { addMetaToCache, addToCache, getHash, getKeyWithHash, tryGetFromCache, tryGetMetaFromCache } from '../cache/index.js';
8
8
  import sharp from "sharp";
9
9
  import { foreachGLTF, generateGuid } from '../utils/index.js';
10
10
  import { needle_asset, writeNeedleAsset } from './needle_asset.js';
@@ -159,12 +159,14 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
159
159
  if (!outPath) {
160
160
  continue;
161
161
  }
162
+ const { key, hash } = getKeyWithHash(texture);
162
163
  const relName = path.relative(directory, outPath);
163
164
  // TODO: this path should be added to the NEEDLE dependencies extension
164
165
  const model = {
165
166
  guid: textureGuid,
166
167
  lods: [
167
168
  {
169
+ hash: hash.toString(),
168
170
  path: relName,
169
171
  }
170
172
  ],
@@ -172,7 +174,6 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
172
174
  // for backwards compatibility - this should be removed in the future
173
175
  model["uri"] = relName;
174
176
  texture.setExtension(NEEDLE_PROGRESSIVE_EXTENSION_NAME, progressiveExt.createTexture(model));
175
- const key = getKey(texture);
176
177
  if (opts.useCache) {
177
178
  const cached = tryGetFromCache(key);
178
179
  if (cached) {
@@ -342,7 +343,7 @@ export function make_progressive_meshes(filePath, _options, opts) {
342
343
  const t = l / MAX_LODS;
343
344
  const latest = LODS[LODS.length - 1];
344
345
  const ratio = latest.ratio * .5;
345
- const error = .05;
346
+ const error = Math.min(.013 * (l + 1), 0.05);
346
347
  LODS.push({
347
348
  ratio: ratio,
348
349
  error,
@@ -526,6 +527,7 @@ export function make_progressive_meshes(filePath, _options, opts) {
526
527
  lods: generatedLODInfos.map(l => {
527
528
  return {
528
529
  path: l.path,
530
+ hash: l.content_hash.toString(),
529
531
  density: l.density,
530
532
  vertexCount: l.lodMeshInfo?.totalVertexCount,
531
533
  indexCount: l.lodMeshInfo?.totalIndexCount,
@@ -587,21 +589,21 @@ async function createMeshLod(doc, basePath, level, mesh, meshInfo, guid, lodLeve
587
589
  const outPath = basePath + fileName;
588
590
  const primitives = mesh.listPrimitives();
589
591
  let cacheKey = undefined;
592
+ // generate hash for mesh
593
+ let hash = mesh["needle:mesh-hash"];
594
+ if (hash === undefined) {
595
+ hash = getHash(mesh);
596
+ mesh["needle:mesh-hash"] = hash;
597
+ }
598
+ hash += getHash(lodLevel);
590
599
  if (opts.useCache !== false) {
591
- // generate hash for mesh
592
- let hash = mesh["needle:mesh-hash"];
593
- if (hash === undefined) {
594
- hash = getHash(mesh);
595
- mesh["needle:mesh-hash"] = hash;
596
- }
597
- hash += getHash(lodLevel);
598
600
  cacheKey = `mesh_lod_${level}_${hash}`;
599
601
  const cachedValue = tryGetFromCache(cacheKey);
600
602
  const meta = tryGetMetaFromCache(cacheKey);
601
603
  if (cachedValue && meta) {
602
604
  console.log(`[${NAME}] LOD ${level} loaded ${(cachedValue.length / 1024).toFixed()} KB from cache for \"${mesh.getName()}\"`);
603
605
  writeFileSync(outPath, cachedValue);
604
- return { level, path: fileName, success: true, cacheKey: cacheKey, lodMeshInfo: meta.meshInfo, density: meta.density };
606
+ return { level, path: fileName, success: true, cacheKey: cacheKey, content_hash: hash, lodMeshInfo: meta.meshInfo, density: meta.density };
605
607
  }
606
608
  }
607
609
  const newDoc = new Document();
@@ -667,9 +669,14 @@ async function createMeshLod(doc, basePath, level, mesh, meshInfo, guid, lodLeve
667
669
  for (const ext of extensions) {
668
670
  const PropertyClass = ext.constructor;
669
671
  const newProp = new PropertyClass(newDoc.getGraph());
670
- const copy = newProp.copy(ext);
671
- const name = ext.extensionName;
672
- newPrim.setExtension(name, copy);
672
+ try {
673
+ const copy = newProp.copy(ext);
674
+ const name = ext.extensionName;
675
+ newPrim.setExtension(name, copy);
676
+ }
677
+ catch (err) {
678
+ console.error(`WARN: [${NAME}] Failed to copy extension ${ext.extensionName} for mesh LOD ${level} → ${err}`);
679
+ }
673
680
  }
674
681
  }
675
682
  let primitiveIndex = 0;
@@ -687,7 +694,7 @@ async function createMeshLod(doc, basePath, level, mesh, meshInfo, guid, lodLeve
687
694
  const newMeshInformation = getMeshInformation(newMesh);
688
695
  if (newMeshInformation.totalVertexCount < 4) {
689
696
  console.error(`[${NAME}] mesh LOD ${level} is has less than 4 vertices → skipping`);
690
- return { level, path: fileName, success: false, cacheKey: cacheKey, lodMeshInfo: null, density: null, };
697
+ return { level, path: fileName, success: false, cacheKey: cacheKey, content_hash: hash, lodMeshInfo: null, density: null, };
691
698
  }
692
699
  let density = 0;
693
700
  for (const prim of newMesh.listPrimitives()) {
@@ -723,7 +730,7 @@ async function createMeshLod(doc, basePath, level, mesh, meshInfo, guid, lodLeve
723
730
  addToCache(cacheKey, bytes);
724
731
  addMetaToCache(cacheKey, { meshInfo: newMeshInformation, density: density });
725
732
  }
726
- return { level, path: fileName, success: true, lodMeshInfo: newMeshInformation, cacheKey: cacheKey, density: density };
733
+ return { level, path: fileName, success: true, lodMeshInfo: newMeshInformation, cacheKey: cacheKey, content_hash: hash, density: density };
727
734
  }
728
735
  async function simplifyMesh(doc, mesh, prim, index, lodinfo) {
729
736
  const weldOptions = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-build-pipeline",
3
- "version": "1.4.7",
3
+ "version": "1.4.9",
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",
@@ -30,7 +30,7 @@
30
30
  "ndarray-pixels": "^2.0.1",
31
31
  "p-limit": "3.1.0",
32
32
  "semver": "^7.3.7",
33
- "sharp": "^0.31.3",
33
+ "sharp": "^0.32.6",
34
34
  "tmp": "^0.2.1",
35
35
  "uuid": "^9.0.1"
36
36
  },