|
15 | 15 | <body>
|
16 | 16 | <div id="info">
|
17 | 17 | <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> batch lod bvh - <a href="https://github.com/agargaro/batched-mesh-extensions" target="_blank" rel="noopener">@three.ez/batched-mesh-extensions</a><br/>
|
18 |
| - BatchedMesh with 10 geometries and 500k instances. Each geometry has 4 LODs generated with meshoptimizer. <br> |
| 18 | + BatchedMesh with 10 geometries and 500k instances. Each geometry has 5 LODs (4 generated with meshoptimizer). <br> |
19 | 19 | Frustum culling and raycasting are accelerated by using BVHs (TLAS & BLAS). <br>
|
20 | 20 | See <a href="https://github.com/agargaro/batched-mesh-extensions" target="_blank" rel="noopener">main project repository</a> for more information and examples on BatchedMesh extensions.
|
21 | 21 | </div>
|
|
56 | 56 | THREE.Mesh.prototype.raycast = acceleratedRaycast;
|
57 | 57 | THREE.BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;
|
58 | 58 |
|
59 |
| - const instancesCount = 500000; |
60 | 59 | let stats;
|
61 | 60 | let camera, scene, renderer;
|
| 61 | + |
| 62 | + const instancesCount = 500000; |
62 | 63 | let batchedMesh;
|
63 | 64 | let lastHoveredInstance = null;
|
64 | 65 | const lastHoveredColor = new THREE.Color();
|
|
116 | 117 | new THREE.TorusKnotGeometry( 1, 0.4, 256, 32, 5, 3 )
|
117 | 118 | ];
|
118 | 119 |
|
119 |
| - // generate 4 LODs (Levels of Detail) for each geometry |
| 120 | + // generate 4 LODs (levels of detail) for each geometry |
120 | 121 | const geometriesLODArray = await simplifyGeometriesByErrorLOD( geometries, 4, performanceRangeLOD );
|
121 | 122 |
|
122 | 123 | // create BatchedMesh
|
|
165 | 166 |
|
166 | 167 | // set up gui
|
167 | 168 | const config = {
|
| 169 | + freeze: false, |
168 | 170 | useBVH: true,
|
169 | 171 | useLOD: true
|
170 | 172 | };
|
171 | 173 |
|
172 | 174 | const bvh = batchedMesh.bvh;
|
173 | 175 | const lods = batchedMesh._geometryInfo.map( x => x.LOD );
|
| 176 | + const onBeforeRender = batchedMesh.onBeforeRender; |
174 | 177 |
|
175 | 178 | const gui = new GUI();
|
| 179 | + |
176 | 180 | gui.add( batchedMesh, 'instanceCount' ).disable();
|
| 181 | + |
| 182 | + gui.add( config, 'freeze' ).onChange( v => { |
| 183 | + |
| 184 | + batchedMesh.onBeforeRender = v ? () => {} : onBeforeRender; |
| 185 | + |
| 186 | + } ); |
177 | 187 |
|
178 | 188 | const frustumCullingFolder = gui.addFolder( 'Frustum culling & raycasting' );
|
179 | 189 | frustumCullingFolder.add( config, 'useBVH' ).onChange( v => {
|
|
182 | 192 |
|
183 | 193 | } );
|
184 | 194 |
|
185 |
| - const GeometriesFolder = gui.addFolder( 'Geometries' ); |
186 |
| - GeometriesFolder.add( config, 'useLOD' ).onChange( v => { |
| 195 | + const geometriesFolder = gui.addFolder( 'Geometries' ); |
| 196 | + geometriesFolder.add( config, 'useLOD' ).onChange( v => { |
187 | 197 |
|
188 | 198 | const geometryInfo = batchedMesh._geometryInfo;
|
189 | 199 | for ( let i = 0; i < geometryInfo.length; i ++ ) {
|
|
194 | 204 |
|
195 | 205 | } );
|
196 | 206 |
|
197 |
| - document.addEventListener( 'mousemove', onMouseMove ); |
| 207 | + document.addEventListener( 'pointermove', onPointerMove ); |
198 | 208 | window.addEventListener( 'resize', onWindowResize );
|
199 | 209 | onWindowResize();
|
200 | 210 |
|
|
203 | 213 | }
|
204 | 214 |
|
205 | 215 |
|
206 |
| - function onMouseMove( event ) { |
| 216 | + function onPointerMove( event ) { |
207 | 217 |
|
208 | 218 | event.preventDefault();
|
209 | 219 |
|
|
229 | 239 | raycaster.setFromCamera( mouse, camera );
|
230 | 240 | const intersection = raycaster.intersectObject( batchedMesh );
|
231 | 241 |
|
232 |
| - if ( intersection.length > 0 ) { |
233 |
| - |
234 |
| - const batchId = intersection[ 0 ].batchId; |
235 |
| - |
236 |
| - if ( lastHoveredInstance === batchId ) return; |
| 242 | + const batchId = intersection.length > 0 ? intersection[ 0 ].batchId : null; |
| 243 | + |
| 244 | + if ( lastHoveredInstance === batchId ) return; |
237 | 245 |
|
238 |
| - if ( lastHoveredInstance ) { |
| 246 | + if ( lastHoveredInstance ) { |
239 | 247 |
|
240 |
| - batchedMesh.setColorAt( lastHoveredInstance, lastHoveredColor ); |
| 248 | + batchedMesh.setColorAt( lastHoveredInstance, lastHoveredColor ); |
241 | 249 |
|
242 |
| - } |
| 250 | + } |
243 | 251 |
|
244 |
| - lastHoveredInstance = batchId; |
245 |
| - batchedMesh.getColorAt( lastHoveredInstance, lastHoveredColor ); |
246 |
| - batchedMesh.setColorAt( lastHoveredInstance, yellow ); |
| 252 | + if ( batchId ) { |
247 | 253 |
|
248 |
| - } else if ( lastHoveredInstance ) { |
| 254 | + batchedMesh.getColorAt( batchId, lastHoveredColor ); |
| 255 | + batchedMesh.setColorAt( batchId, yellow ); |
249 | 256 |
|
250 |
| - batchedMesh.setColorAt( lastHoveredInstance, lastHoveredColor ); |
251 |
| - lastHoveredInstance = null; |
252 |
| - |
253 | 257 | }
|
254 | 258 |
|
| 259 | + lastHoveredInstance = batchId; |
| 260 | + |
255 | 261 | }
|
256 | 262 |
|
257 | 263 | function animate() {
|
|
0 commit comments