@needle-tools/gltf-progressive 3.6.0-alpha.3 → 3.6.0-canary.5401de9

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.
@@ -0,0 +1,70 @@
1
+ import { loadRuntime } from "../shared/runtime.js";
2
+ import {
3
+ addLoadedScene,
4
+ createOrbitControls,
5
+ createExampleState,
6
+ getModelUrl,
7
+ markError,
8
+ markReady,
9
+ resizeRenderer,
10
+ setupScene,
11
+ setupRoomEnvironment,
12
+ updateStatus,
13
+ } from "../shared/example-utils.js";
14
+
15
+ const state = createExampleState("webgpu");
16
+
17
+ try {
18
+ const runtime = await loadRuntime();
19
+ const THREE = runtime.THREE;
20
+ const WebGPURenderer = runtime.THREE.WebGPURenderer || runtime.THREE_WEBGPU.WebGPURenderer;
21
+ if (!WebGPURenderer) throw new Error("WebGPURenderer is not available in this Three.js runtime.");
22
+ if (!navigator.gpu) throw new Error("WebGPU is not available in this browser.");
23
+
24
+ const canvas = document.getElementById("view");
25
+ const renderer = new WebGPURenderer({ canvas, antialias: true });
26
+ await renderer.init?.();
27
+
28
+ const { scene, camera } = setupScene(THREE, window.innerWidth, window.innerHeight);
29
+ resizeRenderer(renderer, camera, window.innerWidth, window.innerHeight, window.devicePixelRatio);
30
+ setupRoomEnvironment(THREE, runtime.RoomEnvironment, renderer, scene, {
31
+ PMREMGenerator: runtime.THREE_WEBGPU.PMREMGenerator,
32
+ });
33
+ const controls = createOrbitControls(runtime.OrbitControls, camera, canvas);
34
+
35
+ const loader = new runtime.GLTFLoader();
36
+ runtime.useNeedleProgressive(loader, renderer);
37
+
38
+ const root = await new Promise((resolve, reject) => {
39
+ loader.load(getModelUrl(), gltf => resolve(addLoadedScene(THREE, scene, gltf, { camera, controls })), undefined, reject);
40
+ });
41
+
42
+ window.addEventListener("resize", () => {
43
+ resizeRenderer(renderer, camera, window.innerWidth, window.innerHeight, window.devicePixelRatio);
44
+ });
45
+
46
+ function render() {
47
+ state.frames += 1;
48
+ root.rotation.y += 0.01;
49
+ controls.update();
50
+ renderer.render(scene, camera);
51
+ requestAnimationFrame(render);
52
+ }
53
+
54
+ const backend = getBackendType(renderer);
55
+ if (backend !== "webgpu") throw new Error(`Expected WebGPU backend, got ${backend}.`);
56
+ markReady(state, backend);
57
+ render();
58
+ }
59
+ catch (error) {
60
+ updateStatus("webgpu unavailable");
61
+ markError(state, error);
62
+ }
63
+
64
+ function getBackendType(renderer) {
65
+ const backend = renderer.backend;
66
+ if (backend?.isWebGPUBackend === true) return "webgpu";
67
+ if (backend?.isWebGLBackend === true) return "webgl";
68
+ if (renderer.isWebGPURenderer === true) return "webgpu";
69
+ return backend?.constructor?.name || renderer.constructor?.name || "unknown";
70
+ }
@@ -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 Worker 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,91 @@
1
+ import { loadRuntime } from "../shared/runtime.js";
2
+ import {
3
+ applyCameraState,
4
+ createExampleState,
5
+ createOrbitControls,
6
+ markError,
7
+ markReady,
8
+ serializeCamera,
9
+ updateStatus,
10
+ } from "../shared/example-utils.js";
11
+
12
+ const state = createExampleState("worker-rendering");
13
+
14
+ try {
15
+ if (!globalThis.OffscreenCanvas) throw new Error("OffscreenCanvas is not available in this browser.");
16
+
17
+ const runtime = await loadRuntime();
18
+ const THREE = runtime.THREE;
19
+ const canvas = document.getElementById("view");
20
+ const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 200);
21
+ camera.position.set(0.5, 1.3, 2);
22
+ const controls = createOrbitControls(runtime.OrbitControls, camera, canvas);
23
+ const offscreenCanvas = canvas.transferControlToOffscreen();
24
+ const worker = new Worker("./worker.js", { type: "module" });
25
+
26
+ worker.addEventListener("message", event => {
27
+ const message = event.data || {};
28
+ if (message.type === "ready") {
29
+ if (message.camera) applyCameraState(camera, message.camera);
30
+ if (message.fit?.target) {
31
+ controls.target.fromArray(message.fit.target);
32
+ controls.minDistance = message.fit.minDistance;
33
+ controls.maxDistance = message.fit.maxDistance;
34
+ controls.update();
35
+ }
36
+ sendCamera();
37
+ markReady(state, message.renderer || "worker-webgl");
38
+ }
39
+ else if (message.type === "frame") {
40
+ state.frames = message.frames;
41
+ }
42
+ else if (message.type === "error") {
43
+ markError(state, message.message || "Worker rendering failed.");
44
+ }
45
+ });
46
+ worker.addEventListener("error", event => {
47
+ markError(state, event.message || event.error || event);
48
+ });
49
+
50
+ function postResize() {
51
+ camera.aspect = window.innerWidth / window.innerHeight;
52
+ camera.updateProjectionMatrix();
53
+ worker.postMessage({
54
+ type: "resize",
55
+ width: window.innerWidth,
56
+ height: window.innerHeight,
57
+ pixelRatio: window.devicePixelRatio || 1,
58
+ camera: serializeCamera(camera),
59
+ });
60
+ }
61
+
62
+ function sendCamera() {
63
+ worker.postMessage({
64
+ type: "camera",
65
+ camera: serializeCamera(camera),
66
+ });
67
+ }
68
+
69
+ controls.addEventListener("change", sendCamera);
70
+
71
+ function updateControls() {
72
+ controls.update();
73
+ requestAnimationFrame(updateControls);
74
+ }
75
+ updateControls();
76
+
77
+ worker.postMessage({
78
+ type: "init",
79
+ canvas: offscreenCanvas,
80
+ width: window.innerWidth,
81
+ height: window.innerHeight,
82
+ pixelRatio: window.devicePixelRatio || 1,
83
+ camera: serializeCamera(camera),
84
+ search: location.search,
85
+ }, [offscreenCanvas]);
86
+ window.addEventListener("resize", postResize);
87
+ updateStatus("worker-webgl");
88
+ }
89
+ catch (error) {
90
+ markError(state, error);
91
+ }
@@ -0,0 +1,77 @@
1
+ import { loadRuntime } from "../shared/runtime.js";
2
+ import {
3
+ addLoadedScene,
4
+ applyCameraState,
5
+ getModelUrl,
6
+ resizeRenderer,
7
+ serializeCamera,
8
+ setupScene,
9
+ setupRoomEnvironment,
10
+ } from "../shared/example-utils.js";
11
+
12
+ let renderer;
13
+ let camera;
14
+ let root;
15
+ let frames = 0;
16
+ let width = 1;
17
+ let height = 1;
18
+ let pixelRatio = 1;
19
+
20
+ self.addEventListener("message", event => {
21
+ const message = event.data || {};
22
+ if (message.type === "init") {
23
+ init(message).catch(error => {
24
+ self.postMessage({ type: "error", message: error?.stack || error?.message || String(error) });
25
+ });
26
+ }
27
+ else if (message.type === "resize") {
28
+ width = message.width || width;
29
+ height = message.height || height;
30
+ pixelRatio = message.pixelRatio || pixelRatio;
31
+ if (renderer && camera) resizeRenderer(renderer, camera, width, height, pixelRatio);
32
+ if (camera && message.camera) applyCameraState(camera, message.camera);
33
+ }
34
+ else if (message.type === "camera") {
35
+ if (camera && message.camera) applyCameraState(camera, message.camera);
36
+ }
37
+ });
38
+
39
+ async function init(message) {
40
+ width = message.width || width;
41
+ height = message.height || height;
42
+ pixelRatio = message.pixelRatio || pixelRatio;
43
+
44
+ const params = new URLSearchParams(message.search || "");
45
+ const runtime = await loadRuntime({ params });
46
+ const THREE = runtime.THREE;
47
+
48
+ renderer = new THREE.WebGLRenderer({ canvas: message.canvas, antialias: true });
49
+ const setup = setupScene(THREE, width, height);
50
+ const scene = setup.scene;
51
+ camera = setup.camera;
52
+ resizeRenderer(renderer, camera, width, height, pixelRatio);
53
+ if (message.camera) applyCameraState(camera, message.camera);
54
+ setupRoomEnvironment(THREE, runtime.RoomEnvironment, renderer, scene);
55
+
56
+ const loader = new runtime.GLTFLoader();
57
+ runtime.useNeedleProgressive(loader, renderer);
58
+ let fit = null;
59
+ root = await new Promise((resolve, reject) => {
60
+ loader.load(getModelUrl(params), gltf => resolve(addLoadedScene(THREE, scene, gltf, {
61
+ camera,
62
+ onFit: result => fit = result,
63
+ })), undefined, reject);
64
+ });
65
+
66
+ self.postMessage({ type: "ready", renderer: "worker-webgl", camera: serializeCamera(camera), fit });
67
+
68
+ const requestFrame = self.requestAnimationFrame || (callback => setTimeout(() => callback(performance.now()), 16));
69
+ function render() {
70
+ frames += 1;
71
+ root.rotation.y += 0.01;
72
+ renderer.render(scene, camera);
73
+ if (frames % 10 === 0) self.postMessage({ type: "frame", frames });
74
+ requestFrame(render);
75
+ }
76
+ render();
77
+ }