@needle-tools/gltf-progressive 1.2.12 → 1.2.14

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.
@@ -1,34 +1,34 @@
1
- {
2
- "name": "react-typescript",
3
- "version": "1.0.0",
4
- "main": "src/index.tsx",
5
- "dependencies": {
6
- "@needle-tools/gltf-progressive": "file:../..",
7
- "@react-three/drei": "^9.0.1",
8
- "@react-three/fiber": "^8.0.6",
9
- "react": "^18.0.0",
10
- "react-dom": "^18.0.0",
11
- "three": "0.162.0",
12
- "typescript": "4.7.4"
13
- },
14
- "devDependencies": {
15
- "@types/react": "18.0.15",
16
- "@types/react-dom": "17.0.0",
17
- "@types/three": "0.162.0",
18
- "@vitejs/plugin-basic-ssl": "^1.0.1",
19
- "@vitejs/plugin-react": "^1.3.0",
20
- "typescript": "4.1.3",
21
- "vite": "<= 4.3.9",
22
- "vite-plugin-compression": "^0.5.1"
23
- },
24
- "scripts": {
25
- "start": "vite --host",
26
- "build": "vite build"
27
- },
28
- "browserslist": [
29
- ">0.2%",
30
- "not dead",
31
- "not ie <= 11",
32
- "not op_mini all"
33
- ]
34
- }
1
+ {
2
+ "name": "react-typescript",
3
+ "version": "1.0.0",
4
+ "main": "src/index.tsx",
5
+ "dependencies": {
6
+ "@needle-tools/gltf-progressive": "file:../..",
7
+ "@react-three/drei": "^9.0.1",
8
+ "@react-three/fiber": "^8.0.6",
9
+ "react": "^18.0.0",
10
+ "react-dom": "^18.0.0",
11
+ "three": "0.162.0",
12
+ "typescript": "4.7.4"
13
+ },
14
+ "devDependencies": {
15
+ "@types/react": "18.0.15",
16
+ "@types/react-dom": "17.0.0",
17
+ "@types/three": "0.162.0",
18
+ "@vitejs/plugin-basic-ssl": "^1.0.1",
19
+ "@vitejs/plugin-react": "^1.3.0",
20
+ "typescript": "4.1.3",
21
+ "vite": "<= 4.3.9",
22
+ "vite-plugin-compression": "^0.5.1"
23
+ },
24
+ "scripts": {
25
+ "start": "vite --host",
26
+ "build": "vite build"
27
+ },
28
+ "browserslist": [
29
+ ">0.2%",
30
+ "not dead",
31
+ "not ie <= 11",
32
+ "not op_mini all"
33
+ ]
34
+ }
@@ -1,22 +1,22 @@
1
- {
2
- "compilerOptions": {
3
- "jsx": "react",
4
- "target": "ESNext",
5
- "useDefineForClassFields": true,
6
- "module": "ESNext",
7
- "lib": ["ESNext", "DOM"],
8
- "moduleResolution": "Node",
9
- "strict": true,
10
- "sourceMap": true,
11
- "resolveJsonModule": true,
12
- "esModuleInterop": true,
13
- "noEmit": true,
14
- "noUnusedLocals": false,
15
- "noUnusedParameters": true,
16
- "noImplicitReturns": true,
17
- "noImplicitAny": false,
18
- "experimentalDecorators": true,
19
- "skipLibCheck": true
20
- },
21
- "include": ["./src"]
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react",
4
+ "target": "ESNext",
5
+ "useDefineForClassFields": true,
6
+ "module": "ESNext",
7
+ "lib": ["ESNext", "DOM"],
8
+ "moduleResolution": "Node",
9
+ "strict": true,
10
+ "sourceMap": true,
11
+ "resolveJsonModule": true,
12
+ "esModuleInterop": true,
13
+ "noEmit": true,
14
+ "noUnusedLocals": false,
15
+ "noUnusedParameters": true,
16
+ "noImplicitReturns": true,
17
+ "noImplicitAny": false,
18
+ "experimentalDecorators": true,
19
+ "skipLibCheck": true
20
+ },
21
+ "include": ["./src"]
22
22
  }
@@ -1,39 +1,39 @@
1
- import * as path from 'path';
2
- import { defineConfig } from 'vite';
3
- import react from '@vitejs/plugin-react';
4
- import basicSsl from '@vitejs/plugin-basic-ssl'
5
- import viteCompression from 'vite-plugin-compression';
6
-
7
- export default defineConfig(async (command) => {
8
-
9
-
10
- return {
11
- base: "./",
12
- assetsInclude: ['*'],
13
-
14
- plugins: [
15
- react(),
16
- basicSsl(),
17
- viteCompression({ deleteOriginFile: true }),
18
- ],
19
-
20
- server: {
21
- https: true,
22
- proxy: { // workaround: specifying a proxy skips HTTP2 which is currently problematic in Vite since it causes session memory timeouts.
23
- 'https://localhost:3000': 'https://localhost:3000'
24
- },
25
- strictPort: true,
26
- port: 3001
27
- },
28
- build: {
29
- outDir: "./dist",
30
- emptyOutDir: true,
31
- },
32
- resolve: {
33
- alias: {
34
- 'react': () => path.resolve(__dirname, 'node_modules/react'),
35
- '@react-three/fiber': () => path.resolve(__dirname, 'node_modules/@react-three/fiber'),
36
- }
37
- }
38
- }
1
+ import * as path from 'path';
2
+ import { defineConfig } from 'vite';
3
+ import react from '@vitejs/plugin-react';
4
+ import basicSsl from '@vitejs/plugin-basic-ssl'
5
+ import viteCompression from 'vite-plugin-compression';
6
+
7
+ export default defineConfig(async (command) => {
8
+
9
+
10
+ return {
11
+ base: "./",
12
+ assetsInclude: ['*'],
13
+
14
+ plugins: [
15
+ react(),
16
+ basicSsl(),
17
+ viteCompression({ deleteOriginFile: true }),
18
+ ],
19
+
20
+ server: {
21
+ https: true,
22
+ proxy: { // workaround: specifying a proxy skips HTTP2 which is currently problematic in Vite since it causes session memory timeouts.
23
+ 'https://localhost:3000': 'https://localhost:3000'
24
+ },
25
+ strictPort: true,
26
+ port: 3001
27
+ },
28
+ build: {
29
+ outDir: "./dist",
30
+ emptyOutDir: true,
31
+ },
32
+ resolve: {
33
+ alias: {
34
+ 'react': () => path.resolve(__dirname, 'node_modules/react'),
35
+ '@react-three/fiber': () => path.resolve(__dirname, 'node_modules/@react-three/fiber'),
36
+ }
37
+ }
38
+ }
39
39
  });
@@ -1,51 +1,51 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="utf-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <title>Threejs Progressive Loading</title>
8
- <style>
9
- body {
10
- margin: 0;
11
- }
12
- </style>
13
- <script type="importmap">
14
- {
15
- "imports": {
16
- "three": "https://cdn.jsdelivr.net/npm/three@latest/build/three.module.js",
17
- "three/addons/": "https://cdn.jsdelivr.net/npm/three@latest/examples/jsm/",
18
- "three/examples/": "https://cdn.jsdelivr.net/npm/three@latest/examples/"
19
- }
20
- }
21
- </script>
22
- </head>
23
-
24
- <body>
25
- <script type="module" src="./main.js"></script>
26
- <button class="show-source">Show Source</button>
27
- </body>
28
-
29
-
30
- <style>
31
- .show-source {
32
- position: fixed;
33
- right: 1rem;
34
- bottom: 1rem;
35
- z-index: 100;
36
- border-radius: .5rem;
37
- border: none;
38
- padding: .3rem .5rem;
39
- }
40
- </style>
41
- <script>
42
- document.addEventListener("DOMContentLoaded", () => {
43
- document.querySelector('.show-source').addEventListener('click', () => {
44
- const scriptSource = document.querySelector('script[type="module"]').src;
45
- console.log(scriptSource);
46
- window.open(scriptSource);
47
- });
48
- });
49
- </script>
50
-
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <title>Threejs Progressive Loading</title>
8
+ <style>
9
+ body {
10
+ margin: 0;
11
+ }
12
+ </style>
13
+ <script type="importmap">
14
+ {
15
+ "imports": {
16
+ "three": "https://cdn.jsdelivr.net/npm/three@latest/build/three.module.js",
17
+ "three/addons/": "https://cdn.jsdelivr.net/npm/three@latest/examples/jsm/",
18
+ "three/examples/": "https://cdn.jsdelivr.net/npm/three@latest/examples/"
19
+ }
20
+ }
21
+ </script>
22
+ </head>
23
+
24
+ <body>
25
+ <script type="module" src="./main.js"></script>
26
+ <button class="show-source">Show Source</button>
27
+ </body>
28
+
29
+
30
+ <style>
31
+ .show-source {
32
+ position: fixed;
33
+ right: 1rem;
34
+ bottom: 1rem;
35
+ z-index: 100;
36
+ border-radius: .5rem;
37
+ border: none;
38
+ padding: .3rem .5rem;
39
+ }
40
+ </style>
41
+ <script>
42
+ document.addEventListener("DOMContentLoaded", () => {
43
+ document.querySelector('.show-source').addEventListener('click', () => {
44
+ const scriptSource = document.querySelector('script[type="module"]').src;
45
+ console.log(scriptSource);
46
+ window.open(scriptSource);
47
+ });
48
+ });
49
+ </script>
50
+
51
51
  </html>
@@ -1,181 +1,181 @@
1
- import * as THREE from 'three';
2
- import { EXRLoader } from 'three/addons/loaders/EXRLoader.js';
3
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
4
- import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
5
- import { useNeedleProgressive, getRaycastMesh, useRaycastMeshes } from "https://www.unpkg.com/@needle-tools/gltf-progressive@latest"
6
- import { Pane } from 'https://cdn.jsdelivr.net/npm/tweakpane@4.0.3/dist/tweakpane.min.js';
7
-
8
-
9
- const scene = new THREE.Scene();
10
- scene.background = new THREE.Color(0x555555);
11
- const renderer = new THREE.WebGLRenderer();
12
- renderer.setSize(window.innerWidth, window.innerHeight);
13
- document.body.appendChild(renderer.domElement);
14
-
15
- const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 200);
16
-
17
-
18
- window.addEventListener('resize', () => {
19
- renderer.setSize(window.innerWidth, window.innerHeight);
20
- camera.aspect = window.innerWidth / window.innerHeight;
21
- camera.updateProjectionMatrix();
22
- });
23
-
24
- const orbit = new OrbitControls(camera, renderer.domElement);
25
- orbit.target = new THREE.Vector3(0, .5, 0);
26
- camera.position.x = .5;
27
- camera.position.y = 1.3;
28
- camera.position.z = 2;
29
-
30
- const grid = new THREE.GridHelper(50, 50, 0x444444, 0x666666);
31
- scene.add(grid);
32
-
33
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
34
- directionalLight.position.set(-50, 20, 50);
35
- scene.add(directionalLight);
36
-
37
-
38
- // Animate the scene
39
- function animate() {
40
- requestAnimationFrame(animate);
41
- orbit.update();
42
- renderer.render(scene, camera);
43
- }
44
- animate();
45
-
46
- const environmentTextureUrl = "https://dl.polyhaven.org/file/ph-assets/HDRIs/exr/1k/studio_small_09_1k.exr";
47
- const pmremGenerator = new THREE.PMREMGenerator(renderer);
48
- pmremGenerator.compileEquirectangularShader();
49
- new EXRLoader().load(environmentTextureUrl, texture => {
50
- const envMap = pmremGenerator.fromEquirectangular(texture).texture;
51
- scene.environment = envMap;
52
- texture.dispose();
53
- pmremGenerator.dispose();
54
- });
55
-
56
-
57
-
58
-
59
- const modelUrls = [
60
- "https://engine.needle.tools/demos/gltf-progressive/assets/putti gruppe/model.glb",
61
- "https://engine.needle.tools/demos/gltf-progressive/assets/cyberpunk/model.glb",
62
- "https://engine.needle.tools/demos/gltf-progressive/assets/robot/model.glb",
63
- "https://engine.needle.tools/demos/gltf-progressive/assets/vase/model.glb",
64
- "https://engine.needle.tools/demos/gltf-progressive/assets/jupiter_und_ganymed/model.glb",
65
- "https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb",
66
- ]
67
- let currentUrl = "";
68
- /** @type {null | THREE.Scene} */
69
- let currentScene = null;
70
- let wireframe = false;
71
- /** @type {null | THREE.AnimationMixer} */
72
- let animationMixer = null;
73
-
74
- function loadScene() {
75
- let currentIndex = modelUrls.indexOf(currentUrl);
76
- currentIndex += 1;
77
- if (currentIndex >= modelUrls.length) {
78
- currentIndex = 0;
79
- }
80
- const url = modelUrls[currentIndex];
81
- currentUrl = url;
82
- wireframe = false;
83
- if (animationMixer) {
84
- animationMixer.stopAllAction();
85
- animationMixer = null;
86
- }
87
-
88
- // Integrate @needle-tools/gltf-progressive
89
- // Create a new GLTFLoader instance
90
- const gltfLoader = new GLTFLoader();
91
- /** Call this method to register the progressive loader */
92
- useNeedleProgressive(url, renderer, gltfLoader)
93
-
94
- // just call the load method as usual
95
- gltfLoader.load(url, gltf => {
96
- // we're basically just adding our glTF to the scene here
97
- // the rest of the code is just for the demo
98
- console.log(gltf)
99
- if (currentUrl != url) return;
100
- currentScene?.removeFromParent();
101
- currentScene = gltf.scene;
102
- scene.add(gltf.scene)
103
- gltf.scene.position.y += .01;
104
-
105
- // the church is huge - scaling it down so we don't have a big difference between the models
106
- if (url.includes("church")) {
107
- gltf.scene.scale.multiplyScalar(.1);
108
- }
109
- else if (url.includes("cyberpunk")) {
110
- gltf.scene.scale.multiplyScalar(15);
111
- }
112
-
113
- if (gltf.animations?.length) {
114
- console.log("Playing animation", gltf.animations)
115
- animationMixer = new THREE.AnimationMixer(gltf.scene);
116
- const action = animationMixer.clipAction(gltf.animations[0]);
117
- action.setLoop(THREE.LoopRepeat);
118
- action.play();
119
- }
120
- })
121
- }
122
- loadScene();
123
-
124
-
125
- const clock = new THREE.Clock();
126
- function loop() {
127
- const dt = clock.getDelta();
128
- if (animationMixer) {
129
- animationMixer.update(dt);
130
- }
131
- window.requestAnimationFrame(loop);
132
- }
133
- window.requestAnimationFrame(loop);
134
-
135
-
136
- useRaycastMeshes();
137
- const raycaster = new THREE.Raycaster();
138
- raycaster.params.Line.threshold = 0;
139
- window.addEventListener("click", evt => {
140
- const mousePos = {
141
- x: (evt.clientX / window.innerWidth) * 2 - 1,
142
- y: -(evt.clientY / window.innerHeight) * 2 + 1
143
- }
144
- raycaster.setFromCamera(mousePos, camera);
145
- const hits = raycaster.intersectObjects(scene.children, true);
146
- if (hits?.length) {
147
- const hit = hits[0];
148
- const obj = hit.object;
149
- console.log("HIT", obj.name, hit)
150
- const raycastMesh = getRaycastMesh(obj);
151
- if (raycastMesh) {
152
- const newMesh = new THREE.Mesh(raycastMesh, new THREE.MeshBasicMaterial({ color: 0xffddff, wireframe: true, transparent: true, opacity: .5, depthTest: false }));
153
- newMesh.matrix.copy(obj.matrixWorld);
154
- newMesh.matrixAutoUpdate = false;
155
- scene.add(newMesh);
156
- setTimeout(() => {
157
- newMesh.removeFromParent();
158
- }, 1000)
159
- }
160
- }
161
- })
162
-
163
-
164
-
165
-
166
-
167
- const pane = new Pane();
168
- pane.addButton({
169
- title: 'Change Scene',
170
- }).on('click', loadScene);
171
-
172
- pane.addButton({
173
- title: 'Toggle Wireframe',
174
- }).on('click', () => {
175
- wireframe = !wireframe;
176
- scene.traverse(child => {
177
- if (child instanceof THREE.Mesh) {
178
- child.material.wireframe = wireframe;
179
- }
180
- })
181
- });
1
+ import * as THREE from 'three';
2
+ import { EXRLoader } from 'three/addons/loaders/EXRLoader.js';
3
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
4
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
5
+ import { useNeedleProgressive, getRaycastMesh, useRaycastMeshes } from "https://www.unpkg.com/@needle-tools/gltf-progressive@latest"
6
+ import { Pane } from 'https://cdn.jsdelivr.net/npm/tweakpane@4.0.3/dist/tweakpane.min.js';
7
+
8
+
9
+ const scene = new THREE.Scene();
10
+ scene.background = new THREE.Color(0x555555);
11
+ const renderer = new THREE.WebGLRenderer();
12
+ renderer.setSize(window.innerWidth, window.innerHeight);
13
+ document.body.appendChild(renderer.domElement);
14
+
15
+ const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 200);
16
+
17
+
18
+ window.addEventListener('resize', () => {
19
+ renderer.setSize(window.innerWidth, window.innerHeight);
20
+ camera.aspect = window.innerWidth / window.innerHeight;
21
+ camera.updateProjectionMatrix();
22
+ });
23
+
24
+ const orbit = new OrbitControls(camera, renderer.domElement);
25
+ orbit.target = new THREE.Vector3(0, .5, 0);
26
+ camera.position.x = .5;
27
+ camera.position.y = 1.3;
28
+ camera.position.z = 2;
29
+
30
+ const grid = new THREE.GridHelper(50, 50, 0x444444, 0x666666);
31
+ scene.add(grid);
32
+
33
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
34
+ directionalLight.position.set(-50, 20, 50);
35
+ scene.add(directionalLight);
36
+
37
+
38
+ // Animate the scene
39
+ function animate() {
40
+ requestAnimationFrame(animate);
41
+ orbit.update();
42
+ renderer.render(scene, camera);
43
+ }
44
+ animate();
45
+
46
+ const environmentTextureUrl = "https://dl.polyhaven.org/file/ph-assets/HDRIs/exr/1k/studio_small_09_1k.exr";
47
+ const pmremGenerator = new THREE.PMREMGenerator(renderer);
48
+ pmremGenerator.compileEquirectangularShader();
49
+ new EXRLoader().load(environmentTextureUrl, texture => {
50
+ const envMap = pmremGenerator.fromEquirectangular(texture).texture;
51
+ scene.environment = envMap;
52
+ texture.dispose();
53
+ pmremGenerator.dispose();
54
+ });
55
+
56
+
57
+
58
+
59
+ const modelUrls = [
60
+ "https://engine.needle.tools/demos/gltf-progressive/assets/putti gruppe/model.glb",
61
+ "https://engine.needle.tools/demos/gltf-progressive/assets/cyberpunk/model.glb",
62
+ "https://engine.needle.tools/demos/gltf-progressive/assets/robot/model.glb",
63
+ "https://engine.needle.tools/demos/gltf-progressive/assets/vase/model.glb",
64
+ "https://engine.needle.tools/demos/gltf-progressive/assets/jupiter_und_ganymed/model.glb",
65
+ "https://engine.needle.tools/demos/gltf-progressive/assets/church/model.glb",
66
+ ]
67
+ let currentUrl = "";
68
+ /** @type {null | THREE.Scene} */
69
+ let currentScene = null;
70
+ let wireframe = false;
71
+ /** @type {null | THREE.AnimationMixer} */
72
+ let animationMixer = null;
73
+
74
+ function loadScene() {
75
+ let currentIndex = modelUrls.indexOf(currentUrl);
76
+ currentIndex += 1;
77
+ if (currentIndex >= modelUrls.length) {
78
+ currentIndex = 0;
79
+ }
80
+ const url = modelUrls[currentIndex];
81
+ currentUrl = url;
82
+ wireframe = false;
83
+ if (animationMixer) {
84
+ animationMixer.stopAllAction();
85
+ animationMixer = null;
86
+ }
87
+
88
+ // Integrate @needle-tools/gltf-progressive
89
+ // Create a new GLTFLoader instance
90
+ const gltfLoader = new GLTFLoader();
91
+ /** Call this method to register the progressive loader */
92
+ useNeedleProgressive(url, renderer, gltfLoader)
93
+
94
+ // just call the load method as usual
95
+ gltfLoader.load(url, gltf => {
96
+ // we're basically just adding our glTF to the scene here
97
+ // the rest of the code is just for the demo
98
+ console.log(gltf)
99
+ if (currentUrl != url) return;
100
+ currentScene?.removeFromParent();
101
+ currentScene = gltf.scene;
102
+ scene.add(gltf.scene)
103
+ gltf.scene.position.y += .01;
104
+
105
+ // the church is huge - scaling it down so we don't have a big difference between the models
106
+ if (url.includes("church")) {
107
+ gltf.scene.scale.multiplyScalar(.1);
108
+ }
109
+ else if (url.includes("cyberpunk")) {
110
+ gltf.scene.scale.multiplyScalar(15);
111
+ }
112
+
113
+ if (gltf.animations?.length) {
114
+ console.log("Playing animation", gltf.animations)
115
+ animationMixer = new THREE.AnimationMixer(gltf.scene);
116
+ const action = animationMixer.clipAction(gltf.animations[0]);
117
+ action.setLoop(THREE.LoopRepeat);
118
+ action.play();
119
+ }
120
+ })
121
+ }
122
+ loadScene();
123
+
124
+
125
+ const clock = new THREE.Clock();
126
+ function loop() {
127
+ const dt = clock.getDelta();
128
+ if (animationMixer) {
129
+ animationMixer.update(dt);
130
+ }
131
+ window.requestAnimationFrame(loop);
132
+ }
133
+ window.requestAnimationFrame(loop);
134
+
135
+
136
+ useRaycastMeshes();
137
+ const raycaster = new THREE.Raycaster();
138
+ raycaster.params.Line.threshold = 0;
139
+ window.addEventListener("click", evt => {
140
+ const mousePos = {
141
+ x: (evt.clientX / window.innerWidth) * 2 - 1,
142
+ y: -(evt.clientY / window.innerHeight) * 2 + 1
143
+ }
144
+ raycaster.setFromCamera(mousePos, camera);
145
+ const hits = raycaster.intersectObjects(scene.children, true);
146
+ if (hits?.length) {
147
+ const hit = hits[0];
148
+ const obj = hit.object;
149
+ console.log("HIT", obj.name, hit)
150
+ const raycastMesh = getRaycastMesh(obj);
151
+ if (raycastMesh) {
152
+ const newMesh = new THREE.Mesh(raycastMesh, new THREE.MeshBasicMaterial({ color: 0xffddff, wireframe: true, transparent: true, opacity: .5, depthTest: false }));
153
+ newMesh.matrix.copy(obj.matrixWorld);
154
+ newMesh.matrixAutoUpdate = false;
155
+ scene.add(newMesh);
156
+ setTimeout(() => {
157
+ newMesh.removeFromParent();
158
+ }, 1000)
159
+ }
160
+ }
161
+ })
162
+
163
+
164
+
165
+
166
+
167
+ const pane = new Pane();
168
+ pane.addButton({
169
+ title: 'Change Scene',
170
+ }).on('click', loadScene);
171
+
172
+ pane.addButton({
173
+ title: 'Toggle Wireframe',
174
+ }).on('click', () => {
175
+ wireframe = !wireframe;
176
+ scene.traverse(child => {
177
+ if (child instanceof THREE.Mesh) {
178
+ child.material.wireframe = wireframe;
179
+ }
180
+ })
181
+ });