@needle-tools/gltf-progressive 3.6.0-alpha.2 → 3.6.0-beta.1
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 +42 -8
- package/examples/modelviewer-multiple.html +4 -4
- package/examples/modelviewer.html +4 -4
- package/examples/offscreen/index.html +15 -0
- package/examples/offscreen/main.js +98 -0
- package/examples/react-three-fiber/index.html +2 -2
- package/examples/react-three-fiber/package-lock.json +482 -484
- package/examples/react-three-fiber/package.json +4 -4
- package/examples/react-three-fiber/src/App.tsx +76 -21
- package/examples/react-three-fiber/src/styles.css +2 -4
- package/examples/react-three-fiber/vite.config.js +2 -2
- package/examples/shared/example-utils.js +297 -0
- package/examples/shared/example.css +44 -0
- package/examples/shared/runtime.js +34 -0
- package/examples/threejs/index.html +6 -10
- package/examples/threejs/main.js +5 -23
- package/examples/webgpu/index.html +15 -0
- package/examples/webgpu/main.js +105 -0
- package/examples/worker-rendering/index.html +15 -0
- package/examples/worker-rendering/main.js +109 -0
- package/examples/worker-rendering/worker.js +166 -0
- package/gltf-progressive.js +670 -559
- package/gltf-progressive.min.js +9 -9
- package/gltf-progressive.umd.cjs +9 -9
- package/lib/extension.d.ts +6 -0
- package/lib/extension.js +85 -16
- package/lib/loaders.d.ts +1 -8
- package/lib/loaders.js +15 -2
- package/lib/lods.debug.js +1 -1
- package/lib/lods.manager.d.ts +3 -0
- package/lib/lods.manager.js +62 -18
- package/lib/utils.d.ts +1 -1
- package/lib/utils.internal.d.ts +27 -0
- package/lib/utils.internal.js +68 -25
- package/lib/version.js +1 -1
- package/lib/worker/loader.mainthread.js +6 -4
- package/package.json +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ 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
|
+
## [3.6.0-beta.1] - 2026-06-09
|
|
8
|
+
- Fix: texture LOD selection regressed for meshes that only have texture LODs (no mesh LODs); screen coverage is now computed unconditionally so texture LODs update with camera distance again.
|
|
9
|
+
|
|
10
|
+
## [3.6.0-alpha.3] - 2026-05-27
|
|
11
|
+
- Fix: stale progressive mesh and texture LOD requests no longer overwrite newer explicit targets, while still allowing useful intermediate LODs to apply during rapid target changes.
|
|
12
|
+
- Fix: progressive worker/debug imports no longer assume `window` exists, and texture LOD selection now uses the renderer pixel ratio so main-thread and worker/offscreen renderers can make matching LOD decisions.
|
|
13
|
+
|
|
7
14
|
## [3.6.0-alpha.2] - 2026-05-26
|
|
8
15
|
- Add: mesh LOD selection can now be reused by renderers that manage their own batching, keeping progressive instanced meshes on independent LOD levels.
|
|
9
16
|
- Add: `assignMeshLOD` can delegate applying a loaded geometry, so batched renderers can update one instance without changing every mesh that shares the source geometry.
|
package/README.md
CHANGED
|
@@ -26,8 +26,13 @@ useNeedleProgressive(gltf_loader, webgl_renderer)
|
|
|
26
26
|
|
|
27
27
|
Examples are in the `/examples` directory. Live versions can be found in the links below.
|
|
28
28
|
|
|
29
|
+
To view the examples locally with the current checkout's runtime, run `npm run examples:serve` and open the printed examples index URL.
|
|
30
|
+
|
|
29
31
|
- [Loading comparisons](https://stackblitz.com/edit/gltf-progressive-comparison?file=package.json,index.html)
|
|
30
32
|
- [Vanilla three.js](https://engine.needle.tools/demos/gltf-progressive/threejs/) - multiple models and animations
|
|
33
|
+
- `examples/webgpu` - WebGPU renderer
|
|
34
|
+
- `examples/offscreen` - main-thread OffscreenCanvas rendering
|
|
35
|
+
- `examples/worker-rendering` - OffscreenCanvas rendering in a Worker
|
|
31
36
|
- [React Three Fiber](https://engine.needle.tools/demos/gltf-progressive/r3f/)
|
|
32
37
|
- \<model-viewer\>
|
|
33
38
|
- [single \<model-viewer> element](https://engine.needle.tools/demos/gltf-progressive/modelviewer)
|
|
@@ -74,10 +79,10 @@ gltfLoader.load(url, gltf => {
|
|
|
74
79
|
<script type="importmap">
|
|
75
80
|
{
|
|
76
81
|
"imports": {
|
|
77
|
-
"three": "https://cdn.jsdelivr.net/npm/three@
|
|
78
|
-
"three/addons/": "https://cdn.jsdelivr.net/npm/three@
|
|
79
|
-
"three/examples/": "https://cdn.jsdelivr.net/npm/three@
|
|
80
|
-
"@needle-tools/gltf-progressive": "https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"
|
|
82
|
+
"three": "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js",
|
|
83
|
+
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/jsm/",
|
|
84
|
+
"three/examples/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/",
|
|
85
|
+
"@needle-tools/gltf-progressive": "https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
</script>
|
|
@@ -110,13 +115,13 @@ Full model-viewer example at: `examples/modelviewer.html`
|
|
|
110
115
|
<script type="importmap">
|
|
111
116
|
{
|
|
112
117
|
"imports": {
|
|
113
|
-
"three": "https://unpkg.com/three/build/three.module.js",
|
|
114
|
-
"three/": "https://unpkg.com/three/"
|
|
118
|
+
"three": "https://unpkg.com/three@0.184.0/build/three.module.js",
|
|
119
|
+
"three/": "https://unpkg.com/three@0.184.0/"
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
122
|
</script>
|
|
118
123
|
<!-- Include gltf-progressive -->
|
|
119
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"></script>
|
|
124
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"></script>
|
|
120
125
|
<!-- Include model-viewer -->
|
|
121
126
|
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
|
|
122
127
|
</head>
|
|
@@ -144,6 +149,36 @@ Create a new class extending `NEEDLE_progressive_plugin` and add your plugin by
|
|
|
144
149
|
### Wait for LODs being loaded
|
|
145
150
|
Call `lodsManager.awaitLoading(<opts?>)` to receive a promise that will resolve when all object LODs that start loading during the next frame have finished to update. Use the optional options parameter to e.g. wait for more frames.
|
|
146
151
|
|
|
152
|
+
### Worker loading and device pixel ratio
|
|
153
|
+
Progressive mesh and texture LOD files can be loaded in a worker by enabling the `gltf-progressive-worker` URL parameter.
|
|
154
|
+
|
|
155
|
+
```txt
|
|
156
|
+
https://example.test/viewer?gltf-progressive-worker
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
LOD selection uses the renderer pixel ratio. For matching results across main-thread, worker, or offscreen rendering, configure the renderer with the same device pixel ratio before calling `useNeedleProgressive` or `LODsManager.get`.
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const renderer = new WebGLRenderer({ canvas });
|
|
163
|
+
renderer.setPixelRatio(devicePixelRatio);
|
|
164
|
+
|
|
165
|
+
useNeedleProgressive(gltfLoader, renderer);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
In a worker or offscreen renderer, pass the display DPR from the main thread and apply it to the renderer there as well.
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
// main thread
|
|
172
|
+
worker.postMessage({ type: "init", devicePixelRatio: window.devicePixelRatio });
|
|
173
|
+
|
|
174
|
+
// worker / offscreen renderer
|
|
175
|
+
const renderer = new WebGLRenderer({ canvas: offscreenCanvas });
|
|
176
|
+
renderer.setPixelRatio(message.devicePixelRatio);
|
|
177
|
+
useNeedleProgressive(gltfLoader, renderer);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
If the renderer does not expose a pixel ratio, gltf-progressive falls back to `globalThis.devicePixelRatio` and then `1`.
|
|
181
|
+
|
|
147
182
|
### Global LOD level override
|
|
148
183
|
|
|
149
184
|
### LOD Manager settings
|
|
@@ -180,4 +215,3 @@ Read more about the [NEEDLE_progressive extension](./NEEDLE_progressive/README.m
|
|
|
180
215
|
[Twitter](https://twitter.com/NeedleTools) •
|
|
181
216
|
[Discord](https://discord.needle.tools) •
|
|
182
217
|
[Forum](https://forum.needle.tools)
|
|
183
|
-
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
<script type="importmap">
|
|
14
14
|
{
|
|
15
15
|
"imports": {
|
|
16
|
-
"three": "https://unpkg.com/three/build/three.module.js",
|
|
17
|
-
"three/": "https://unpkg.com/three/"
|
|
16
|
+
"three": "https://unpkg.com/three@0.184.0/build/three.module.js",
|
|
17
|
+
"three/": "https://unpkg.com/three@0.184.0/"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
</script>
|
|
21
21
|
<script type="module"
|
|
22
|
-
src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"></script>
|
|
22
|
+
src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"></script>
|
|
23
23
|
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
|
|
24
24
|
</head>
|
|
25
25
|
|
|
@@ -123,4 +123,4 @@
|
|
|
123
123
|
}
|
|
124
124
|
</style>
|
|
125
125
|
|
|
126
|
-
</html>
|
|
126
|
+
</html>
|
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
<script type="importmap">
|
|
8
8
|
{
|
|
9
9
|
"imports": {
|
|
10
|
-
"three": "https://unpkg.com/three/build/three.module.js",
|
|
11
|
-
"three/": "https://unpkg.com/three/"
|
|
10
|
+
"three": "https://unpkg.com/three@0.184.0/build/three.module.js",
|
|
11
|
+
"three/": "https://unpkg.com/three@0.184.0/"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
</script>
|
|
15
15
|
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
|
|
16
16
|
<script type="module"
|
|
17
|
-
src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive/gltf-progressive.min.js"></script>
|
|
17
|
+
src="https://cdn.jsdelivr.net/npm/@needle-tools/gltf-progressive@3.6.0-canary.5401de9/gltf-progressive.min.js"></script>
|
|
18
18
|
</head>
|
|
19
19
|
|
|
20
20
|
<model-viewer src="https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb" ar shadow-intensity="1"
|
|
@@ -31,4 +31,4 @@
|
|
|
31
31
|
}
|
|
32
32
|
</style>
|
|
33
33
|
|
|
34
|
-
</html>
|
|
34
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<link rel="icon" href="data:,">
|
|
7
|
+
<link rel="stylesheet" href="../shared/example.css">
|
|
8
|
+
<title>glTF Progressive Offscreen Rendering</title>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<canvas id="view"></canvas>
|
|
12
|
+
<div id="status" class="example-status">loading</div>
|
|
13
|
+
<script type="module" src="./main.js"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { loadRuntime } from "../shared/runtime.js";
|
|
2
|
+
import {
|
|
3
|
+
addLoadedScene,
|
|
4
|
+
createOrbitControls,
|
|
5
|
+
createExampleState,
|
|
6
|
+
createSceneChangeButton,
|
|
7
|
+
getInitialSceneIndex,
|
|
8
|
+
getModelUrl,
|
|
9
|
+
markError,
|
|
10
|
+
markReady,
|
|
11
|
+
markSceneLoaded,
|
|
12
|
+
markSceneLoading,
|
|
13
|
+
normalizeSceneIndex,
|
|
14
|
+
resizeRenderer,
|
|
15
|
+
setupScene,
|
|
16
|
+
setupRoomEnvironment,
|
|
17
|
+
trackLODChanges,
|
|
18
|
+
} from "../shared/example-utils.js";
|
|
19
|
+
|
|
20
|
+
const state = createExampleState("offscreen");
|
|
21
|
+
const params = new URLSearchParams(location.search);
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
if (!globalThis.OffscreenCanvas) throw new Error("OffscreenCanvas is not available in this browser.");
|
|
25
|
+
|
|
26
|
+
const runtime = await loadRuntime();
|
|
27
|
+
const THREE = runtime.THREE;
|
|
28
|
+
const visibleCanvas = document.getElementById("view");
|
|
29
|
+
const visibleContext = visibleCanvas.getContext("bitmaprenderer");
|
|
30
|
+
if (!visibleContext) throw new Error("bitmaprenderer is not available in this browser.");
|
|
31
|
+
|
|
32
|
+
let width = window.innerWidth;
|
|
33
|
+
let height = window.innerHeight;
|
|
34
|
+
let pixelRatio = window.devicePixelRatio || 1;
|
|
35
|
+
const offscreenCanvas = new OffscreenCanvas(Math.max(1, width * pixelRatio), Math.max(1, height * pixelRatio));
|
|
36
|
+
const renderer = new THREE.WebGLRenderer({ canvas: offscreenCanvas, antialias: true });
|
|
37
|
+
const { scene, camera } = setupScene(THREE, width, height);
|
|
38
|
+
setupRoomEnvironment(THREE, runtime.RoomEnvironment, renderer, scene);
|
|
39
|
+
const controls = createOrbitControls(runtime.OrbitControls, camera, visibleCanvas);
|
|
40
|
+
let root = null;
|
|
41
|
+
let sceneIndex = getInitialSceneIndex(params);
|
|
42
|
+
let loadToken = 0;
|
|
43
|
+
|
|
44
|
+
function resize() {
|
|
45
|
+
width = window.innerWidth;
|
|
46
|
+
height = window.innerHeight;
|
|
47
|
+
pixelRatio = window.devicePixelRatio || 1;
|
|
48
|
+
visibleCanvas.width = Math.max(1, Math.floor(width * pixelRatio));
|
|
49
|
+
visibleCanvas.height = Math.max(1, Math.floor(height * pixelRatio));
|
|
50
|
+
resizeRenderer(renderer, camera, width, height, pixelRatio);
|
|
51
|
+
}
|
|
52
|
+
resize();
|
|
53
|
+
|
|
54
|
+
const firstLoader = new runtime.GLTFLoader();
|
|
55
|
+
const lodsManager = runtime.useNeedleProgressive(firstLoader, renderer);
|
|
56
|
+
trackLODChanges(lodsManager, state);
|
|
57
|
+
|
|
58
|
+
async function loadScene(nextIndex) {
|
|
59
|
+
const token = ++loadToken;
|
|
60
|
+
sceneIndex = normalizeSceneIndex(nextIndex);
|
|
61
|
+
const url = getModelUrl(params, sceneIndex);
|
|
62
|
+
markSceneLoading(state, sceneIndex, url);
|
|
63
|
+
|
|
64
|
+
const loader = token === 1 ? firstLoader : new runtime.GLTFLoader();
|
|
65
|
+
if (token !== 1) runtime.useNeedleProgressive(loader, renderer);
|
|
66
|
+
|
|
67
|
+
const nextRoot = await new Promise((resolve, reject) => {
|
|
68
|
+
loader.load(url, gltf => resolve(addLoadedScene(THREE, scene, gltf, { camera, controls })), undefined, reject);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (token !== loadToken) {
|
|
72
|
+
nextRoot.removeFromParent();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
root?.removeFromParent();
|
|
77
|
+
root = nextRoot;
|
|
78
|
+
markSceneLoaded(state, runtime, root);
|
|
79
|
+
markReady(state, "offscreen-webgl");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
window.addEventListener("resize", resize);
|
|
83
|
+
createSceneChangeButton(() => loadScene(sceneIndex + 1).catch(error => markError(state, error)));
|
|
84
|
+
|
|
85
|
+
function render() {
|
|
86
|
+
state.frames += 1;
|
|
87
|
+
controls.update();
|
|
88
|
+
renderer.render(scene, camera);
|
|
89
|
+
visibleContext.transferFromImageBitmap(offscreenCanvas.transferToImageBitmap());
|
|
90
|
+
requestAnimationFrame(render);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
await loadScene(sceneIndex);
|
|
94
|
+
render();
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
markError(state, error);
|
|
98
|
+
}
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
<meta property="og:image" content="" />
|
|
15
15
|
|
|
16
16
|
<meta name="robots" content="index,follow">
|
|
17
|
-
<link rel="stylesheet" href="./src/
|
|
17
|
+
<link rel="stylesheet" href="./src/styles.css">
|
|
18
18
|
</head>
|
|
19
19
|
|
|
20
20
|
<body>
|
|
21
21
|
<script type="module" src="./src/index.tsx"></script>
|
|
22
22
|
<div id="root" style="width:100vw; height:100vh;"></div>
|
|
23
23
|
</body>
|
|
24
|
-
</html>
|
|
24
|
+
</html>
|