@needle-tools/gltf-progressive 1.2.4-beta → 1.2.5-beta
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 +7 -0
- package/README.md +1 -0
- package/gltf-progressive.js +473 -444
- package/gltf-progressive.min.js +7 -7
- package/gltf-progressive.umd.cjs +7 -7
- package/lib/lods_manager.d.ts +15 -2
- package/lib/lods_manager.js +90 -66
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/lib/lods_manager.js
CHANGED
|
@@ -3,6 +3,7 @@ import { NEEDLE_progressive } from "./extension.js";
|
|
|
3
3
|
import { createLoaders } from "./loaders.js";
|
|
4
4
|
import { getParam, isMobileDevice } from "./utils.internal.js";
|
|
5
5
|
import { plugins } from "./plugins/plugin.js";
|
|
6
|
+
import { getRaycastMesh } from "./utils.js";
|
|
6
7
|
const debugProgressiveLoading = getParam("debugprogressive");
|
|
7
8
|
const suppressProgressiveLoading = getParam("noprogressive");
|
|
8
9
|
const $lodsManager = Symbol("Needle:LODSManager");
|
|
@@ -84,19 +85,34 @@ export class LODsManager {
|
|
|
84
85
|
targetTriangleDensity = 200_000;
|
|
85
86
|
/**
|
|
86
87
|
* The update interval in frames. If set to 0, the LODs will be updated every frame. If set to 2, the LODs will be updated every second frame, etc.
|
|
88
|
+
* @default "auto"
|
|
87
89
|
*/
|
|
88
90
|
updateInterval = "auto";
|
|
89
91
|
#updateInterval = 1;
|
|
90
92
|
/**
|
|
91
93
|
* If set to true, the LODsManager will not update the LODs.
|
|
94
|
+
* @default false
|
|
92
95
|
*/
|
|
93
96
|
pause = false;
|
|
97
|
+
/**
|
|
98
|
+
* When set to true the LODsManager will not update the LODs. This can be used to manually update the LODs using the `update` method.
|
|
99
|
+
* Otherwise the LODs will be updated automatically when the renderer renders the scene.
|
|
100
|
+
* @default false
|
|
101
|
+
*/
|
|
102
|
+
manual = false;
|
|
94
103
|
_lodchangedlisteners = [];
|
|
95
104
|
addEventListener(evt, listener) {
|
|
96
105
|
if (evt === "changed") {
|
|
97
106
|
this._lodchangedlisteners.push(listener);
|
|
98
107
|
}
|
|
99
108
|
}
|
|
109
|
+
removeEventListener(evt, listener) {
|
|
110
|
+
if (evt === "changed") {
|
|
111
|
+
const index = this._lodchangedlisteners.indexOf(listener);
|
|
112
|
+
if (index >= 0)
|
|
113
|
+
this._lodchangedlisteners.splice(index, 1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
100
116
|
// readonly plugins: NEEDLE_progressive_plugin[] = [];
|
|
101
117
|
constructor(renderer, context) {
|
|
102
118
|
this.renderer = renderer;
|
|
@@ -126,7 +142,7 @@ export class LODsManager {
|
|
|
126
142
|
// if it's rendering to a texture we don't want to update the LODs
|
|
127
143
|
// This might need to be loosened later - e.g. we might want to update LODs for a render texture - but then we need to store the last LOD level differently and we also might not want to perform all the plugin calls?
|
|
128
144
|
const renderTarget = self.renderer.getRenderTarget();
|
|
129
|
-
if (renderTarget == null) {
|
|
145
|
+
if (renderTarget == null || ("isXRRenderTarget" in renderTarget && renderTarget.isXRRenderTarget)) {
|
|
130
146
|
stack = 0;
|
|
131
147
|
self.#frame += 1;
|
|
132
148
|
self.#delta = self.#clock.getDelta();
|
|
@@ -137,11 +153,9 @@ export class LODsManager {
|
|
|
137
153
|
if (debugProgressiveLoading && self.#frame % 30 === 0)
|
|
138
154
|
console.log("FPS", Math.round(self.#fps), "Interval:", self.#updateInterval);
|
|
139
155
|
}
|
|
140
|
-
const frame = self.#frame;
|
|
141
156
|
const stack_level = stack++;
|
|
142
|
-
self.onBeforeRender(scene, camera, stack_level, frame);
|
|
143
157
|
self.#originalRender.call(this, scene, camera);
|
|
144
|
-
self.onAfterRender(scene, camera, stack_level
|
|
158
|
+
self.onAfterRender(scene, camera, stack_level);
|
|
145
159
|
};
|
|
146
160
|
}
|
|
147
161
|
disable() {
|
|
@@ -150,9 +164,10 @@ export class LODsManager {
|
|
|
150
164
|
this.renderer.render = this.#originalRender;
|
|
151
165
|
this.#originalRender = undefined;
|
|
152
166
|
}
|
|
153
|
-
|
|
167
|
+
update(scene, camera) {
|
|
168
|
+
this.internalUpdate(scene, camera);
|
|
154
169
|
}
|
|
155
|
-
onAfterRender(scene, camera, _stack
|
|
170
|
+
onAfterRender(scene, camera, _stack) {
|
|
156
171
|
if (this.pause)
|
|
157
172
|
return;
|
|
158
173
|
const renderList = this.renderer.renderLists.get(scene, 0);
|
|
@@ -201,77 +216,75 @@ export class LODsManager {
|
|
|
201
216
|
this.#updateInterval = this.updateInterval;
|
|
202
217
|
}
|
|
203
218
|
// Check if we should update LODs this frame
|
|
204
|
-
if (this.#updateInterval > 0 && frame % this.#updateInterval != 0) {
|
|
219
|
+
if (this.#updateInterval > 0 && this.#frame % this.#updateInterval != 0) {
|
|
205
220
|
return;
|
|
206
221
|
}
|
|
207
|
-
this.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
console.warn("Ignoring skybox or BLIT object", entry, entry.material.name, entry.material.type);
|
|
228
|
-
}
|
|
222
|
+
this.internalUpdate(scene, camera);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Update LODs in a scene
|
|
227
|
+
*/
|
|
228
|
+
internalUpdate(scene, camera) {
|
|
229
|
+
const renderList = this.renderer.renderLists.get(scene, 0);
|
|
230
|
+
const opaque = renderList.opaque;
|
|
231
|
+
this.projectionScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
|
232
|
+
this.cameraFrustrum.setFromProjectionMatrix(this.projectionScreenMatrix, this.renderer.coordinateSystem);
|
|
233
|
+
const desiredDensity = this.targetTriangleDensity;
|
|
234
|
+
for (const entry of opaque) {
|
|
235
|
+
if (entry.material && (entry.geometry?.type === "BoxGeometry" || entry.geometry?.type === "BufferGeometry")) {
|
|
236
|
+
// Ignore the skybox
|
|
237
|
+
if (entry.material.name === "SphericalGaussianBlur" || entry.material.name == "BackgroundCubeMaterial" || entry.material.name === "CubemapFromEquirect" || entry.material.name === "EquirectangularToCubeUV") {
|
|
238
|
+
if (debugProgressiveLoading) {
|
|
239
|
+
if (!entry.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"]) {
|
|
240
|
+
entry.material["NEEDLE_PROGRESSIVE:IGNORE-WARNING"] = true;
|
|
241
|
+
console.warn("Ignoring skybox or BLIT object", entry, entry.material.name, entry.material.type);
|
|
229
242
|
}
|
|
230
|
-
continue;
|
|
231
243
|
}
|
|
244
|
+
continue;
|
|
232
245
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
}
|
|
247
|
+
switch (entry.material.type) {
|
|
248
|
+
case "LineBasicMaterial":
|
|
249
|
+
case "LineDashedMaterial":
|
|
250
|
+
case "PointsMaterial":
|
|
251
|
+
case "ShadowMaterial":
|
|
252
|
+
case "MeshDistanceMaterial":
|
|
253
|
+
case "MeshDepthMaterial":
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (debugProgressiveLoading === "color") {
|
|
257
|
+
if (entry.material) {
|
|
258
|
+
if (!entry.object["progressive_debug_color"]) {
|
|
259
|
+
entry.object["progressive_debug_color"] = true;
|
|
260
|
+
const randomColor = Math.random() * 0xffffff;
|
|
261
|
+
const newMaterial = new MeshStandardMaterial({ color: randomColor });
|
|
262
|
+
entry.object.material = newMaterial;
|
|
250
263
|
}
|
|
251
264
|
}
|
|
252
|
-
const object = entry.object;
|
|
253
|
-
if (object instanceof Mesh || (object.isMesh)) {
|
|
254
|
-
this.updateLODs(scene, camera, object, desiredDensity, frame);
|
|
255
|
-
}
|
|
256
265
|
}
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
if (object instanceof Mesh || (object.isMesh)) {
|
|
261
|
-
this.updateLODs(scene, camera, object, desiredDensity, frame);
|
|
262
|
-
}
|
|
266
|
+
const object = entry.object;
|
|
267
|
+
if (object instanceof Mesh || (object.isMesh)) {
|
|
268
|
+
this.updateLODs(scene, camera, object, desiredDensity);
|
|
263
269
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
+
}
|
|
271
|
+
const transparent = renderList.transparent;
|
|
272
|
+
for (const entry of transparent) {
|
|
273
|
+
const object = entry.object;
|
|
274
|
+
if (object instanceof Mesh || (object.isMesh)) {
|
|
275
|
+
this.updateLODs(scene, camera, object, desiredDensity);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const transmissive = renderList.transmissive;
|
|
279
|
+
for (const entry of transmissive) {
|
|
280
|
+
const object = entry.object;
|
|
281
|
+
if (object instanceof Mesh || (object.isMesh)) {
|
|
282
|
+
this.updateLODs(scene, camera, object, desiredDensity);
|
|
270
283
|
}
|
|
271
284
|
}
|
|
272
285
|
}
|
|
273
286
|
/** Update the LOD levels for the renderer. */
|
|
274
|
-
updateLODs(scene, camera, object, desiredDensity
|
|
287
|
+
updateLODs(scene, camera, object, desiredDensity) {
|
|
275
288
|
if (!object.userData) {
|
|
276
289
|
object.userData = {};
|
|
277
290
|
}
|
|
@@ -426,8 +439,8 @@ export class LODsManager {
|
|
|
426
439
|
}
|
|
427
440
|
if (!this.cameraFrustrum?.intersectsObject(mesh)) {
|
|
428
441
|
// the object is not visible by the camera
|
|
429
|
-
result.mesh_lod =
|
|
430
|
-
result.texture_lod =
|
|
442
|
+
result.mesh_lod = 100;
|
|
443
|
+
result.texture_lod = 100;
|
|
431
444
|
return;
|
|
432
445
|
}
|
|
433
446
|
const canvasHeight = this.renderer.domElement.clientHeight || this.renderer.domElement.height;
|
|
@@ -437,6 +450,17 @@ export class LODsManager {
|
|
|
437
450
|
if (!skinnedMesh.boundingBox) {
|
|
438
451
|
skinnedMesh.computeBoundingBox();
|
|
439
452
|
}
|
|
453
|
+
// Fix: https://linear.app/needle/issue/NE-5264
|
|
454
|
+
else if (state.frames % 30 === 0) {
|
|
455
|
+
// use lowres geometry for bounding box calculation
|
|
456
|
+
const raycastmesh = getRaycastMesh(skinnedMesh);
|
|
457
|
+
const originalGeometry = skinnedMesh.geometry;
|
|
458
|
+
if (raycastmesh) {
|
|
459
|
+
skinnedMesh.geometry = raycastmesh;
|
|
460
|
+
}
|
|
461
|
+
skinnedMesh.computeBoundingBox();
|
|
462
|
+
skinnedMesh.geometry = originalGeometry;
|
|
463
|
+
}
|
|
440
464
|
boundingBox = skinnedMesh.boundingBox;
|
|
441
465
|
}
|
|
442
466
|
if (boundingBox && camera.isPerspectiveCamera) {
|
package/lib/version.js
CHANGED
package/package.json
CHANGED