|
19 | 19 | <script type="text/javascript" src="js/Octree.js"></script>
|
20 | 20 | <script>
|
21 | 21 |
|
22 |
| - var camera, |
23 |
| - scene, |
| 22 | + var camera, |
| 23 | + scene, |
24 | 24 | renderer,
|
25 | 25 | octree,
|
26 |
| - geometry, |
27 |
| - material, |
| 26 | + geometry, |
| 27 | + material, |
28 | 28 | mesh,
|
29 | 29 | meshes = [],
|
30 | 30 | meshesSearch = [],
|
|
34 | 34 | radiusMaxHalf = radiusMax * 0.5,
|
35 | 35 | radiusSearch = 400,
|
36 | 36 | searchMesh,
|
37 |
| - baseR = 255, baseG = 0, baseB = 255, |
38 |
| - foundR = 0, foundG = 255, foundB = 0, |
| 37 | + base = new THREE.Color( 0xff00ff ), |
| 38 | + found = new THREE.Color( 0x00ff00 ), |
39 | 39 | adding = true,
|
40 | 40 | rayCaster = new THREE.Raycaster(),
|
41 | 41 | origin = new THREE.Vector3(),
|
|
45 | 45 | animate();
|
46 | 46 |
|
47 | 47 | function init() {
|
48 |
| - |
| 48 | + |
49 | 49 | // standard three scene, camera, renderer
|
50 | 50 |
|
51 | 51 | scene = new THREE.Scene();
|
|
58 | 58 | renderer.setPixelRatio( window.devicePixelRatio );
|
59 | 59 | renderer.setSize( window.innerWidth, window.innerHeight );
|
60 | 60 | document.body.appendChild( renderer.domElement );
|
61 |
| - |
| 61 | + |
62 | 62 | // create octree
|
63 |
| - |
| 63 | + |
64 | 64 | octree = new THREE.Octree( {
|
65 | 65 | // when undeferred = true, objects are inserted immediately
|
66 | 66 | // instead of being deferred until next octree.update() call
|
|
76 | 76 | // pass the scene to visualize the octree
|
77 | 77 | scene: scene
|
78 | 78 | } );
|
79 |
| - |
| 79 | + |
80 | 80 | // create object to show search radius and add to scene
|
81 |
| - |
| 81 | + |
82 | 82 | searchMesh = new THREE.Mesh(
|
83 | 83 | new THREE.SphereGeometry( radiusSearch ),
|
84 | 84 | new THREE.MeshBasicMaterial( { color: 0x00FF00, transparent: true, opacity: 0.4 } )
|
85 | 85 | );
|
86 | 86 | scene.add( searchMesh );
|
87 |
| - |
| 87 | + |
88 | 88 | // info
|
89 |
| - |
| 89 | + |
90 | 90 | var info = document.createElement( 'div' );
|
91 | 91 | info.style.position = 'absolute';
|
92 | 92 | info.style.top = '0';
|
|
103 | 103 |
|
104 | 104 | // note: three.js includes requestAnimationFrame shim
|
105 | 105 | requestAnimationFrame( animate );
|
106 |
| - |
| 106 | + |
107 | 107 | // modify octree structure by adding/removing objects
|
108 |
| - |
| 108 | + |
109 | 109 | modifyOctree();
|
110 |
| - |
| 110 | + |
111 | 111 | // search octree at random location
|
112 |
| - |
| 112 | + |
113 | 113 | searchOctree();
|
114 |
| - |
| 114 | + |
115 | 115 | // render results
|
116 |
| - |
| 116 | + |
117 | 117 | render();
|
118 |
| - |
| 118 | + |
119 | 119 | // update octree to add deferred objects
|
120 |
| - |
| 120 | + |
121 | 121 | octree.update();
|
122 | 122 |
|
123 | 123 | }
|
124 |
| - |
| 124 | + |
| 125 | + var geometry = new THREE.BoxGeometry( 50, 50, 50 ); |
| 126 | + |
125 | 127 | function modifyOctree() {
|
126 |
| - |
| 128 | + |
127 | 129 | // if is adding objects to octree
|
128 |
| - |
| 130 | + |
129 | 131 | if ( adding === true ) {
|
130 |
| - |
| 132 | + |
131 | 133 | // create new object
|
132 |
| - |
133 |
| - geometry = new THREE.BoxGeometry( 50, 50, 50 ); |
134 |
| - material = new THREE.MeshBasicMaterial(); |
135 |
| - material.color.setRGB( baseR, baseG, baseB ); |
136 |
| - |
137 |
| - mesh = new THREE.Mesh( geometry, material ); |
138 |
| - |
| 134 | + |
| 135 | + mesh = new THREE.Line( geometry, new THREE.MeshBasicMaterial( { color: new THREE.Color( base ) } ) ); |
| 136 | + |
139 | 137 | // give new object a random position in radius
|
140 |
| - |
| 138 | + |
141 | 139 | mesh.position.set(
|
142 | 140 | Math.random() * radiusMax - radiusMaxHalf,
|
143 | 141 | Math.random() * radiusMax - radiusMaxHalf,
|
144 | 142 | Math.random() * radiusMax - radiusMaxHalf
|
145 | 143 | );
|
146 |
| - |
| 144 | + |
147 | 145 | // add new object to octree and scene
|
148 |
| - |
| 146 | + |
149 | 147 | octree.add( mesh );
|
150 | 148 | scene.add( mesh );
|
151 |
| - |
| 149 | + |
152 | 150 | // store object for later
|
153 |
| - |
| 151 | + |
154 | 152 | meshes.push( mesh );
|
155 |
| - |
| 153 | + |
156 | 154 | // if at max, stop adding
|
157 |
| - |
| 155 | + |
158 | 156 | if ( meshes.length === meshCountMax ) {
|
159 |
| - |
| 157 | + |
160 | 158 | adding = false;
|
161 |
| - |
| 159 | + |
162 | 160 | }
|
163 |
| - |
| 161 | + |
164 | 162 | }
|
165 | 163 | // else remove objects from octree
|
166 | 164 | else {
|
167 |
| - |
| 165 | + |
168 | 166 | // get object
|
169 |
| - |
| 167 | + |
170 | 168 | mesh = meshes.shift();
|
171 |
| - |
| 169 | + |
172 | 170 | // remove from scene and octree
|
173 |
| - |
| 171 | + |
174 | 172 | scene.remove( mesh );
|
175 | 173 | octree.remove( mesh );
|
176 |
| - |
| 174 | + |
177 | 175 | // if no more objects, start adding
|
178 |
| - |
| 176 | + |
179 | 177 | if ( meshes.length === 0 ) {
|
180 |
| - |
| 178 | + |
181 | 179 | adding = true;
|
182 |
| - |
| 180 | + |
183 | 181 | }
|
184 |
| - |
| 182 | + |
185 | 183 | }
|
186 |
| - |
| 184 | + |
187 | 185 | /*
|
188 |
| - |
| 186 | +
|
189 | 187 | // octree details to console
|
190 |
| - |
| 188 | +
|
191 | 189 | console.log( ' OCTREE: ', octree );
|
192 | 190 | console.log( ' ... depth ', octree.depth, ' vs depth end?', octree.depth_end() );
|
193 | 191 | console.log( ' ... num nodes: ', octree.node_count_end() );
|
194 | 192 | console.log( ' ... total objects: ', octree.object_count_end(), ' vs tree objects length: ', octree.objects.length );
|
195 |
| - |
| 193 | +
|
196 | 194 | // print full octree structure to console
|
197 |
| - |
| 195 | +
|
198 | 196 | octree.to_console();
|
199 |
| - |
| 197 | +
|
200 | 198 | */
|
201 |
| - |
| 199 | + |
202 | 200 | }
|
203 |
| - |
| 201 | + |
204 | 202 | function searchOctree() {
|
205 |
| - |
| 203 | + |
206 | 204 | var i, il;
|
207 |
| - |
| 205 | + |
208 | 206 | // revert previous search objects to base color
|
209 |
| - |
| 207 | + |
210 | 208 | for ( i = 0, il = meshesSearch.length; i < il; i++ ) {
|
211 |
| - |
212 |
| - meshesSearch[ i ].object.material.color.setRGB( baseR, baseG, baseB ); |
213 |
| - |
| 209 | + |
| 210 | + meshesSearch[ i ].object.material.color.copy( base ); |
| 211 | + |
214 | 212 | }
|
215 |
| - |
| 213 | + |
216 | 214 | // new search position
|
217 | 215 | searchMesh.position.set(
|
218 | 216 | Math.random() * radiusMax - radiusMaxHalf,
|
219 | 217 | Math.random() * radiusMax - radiusMaxHalf,
|
220 | 218 | Math.random() * radiusMax - radiusMaxHalf
|
221 | 219 | );
|
222 |
| - |
| 220 | + |
223 | 221 | // record start time
|
224 |
| - |
| 222 | + |
225 | 223 | var timeStart = Date.now();
|
226 |
| - |
| 224 | + |
227 | 225 | // search octree from search mesh position with search radius
|
228 | 226 | // optional third parameter: boolean, if should sort results by object when using faces in octree
|
229 | 227 | // optional fourth parameter: vector3, direction of search when using ray (assumes radius is distance/far of ray)
|
230 |
| - |
| 228 | + |
231 | 229 | origin.copy( searchMesh.position );
|
232 | 230 | direction.set( Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1 ).normalize();
|
233 | 231 | rayCaster.set( origin, direction );
|
234 | 232 | meshesSearch = octree.search( rayCaster.ray.origin, radiusSearch, true, rayCaster.ray.direction );
|
235 | 233 | var intersections = rayCaster.intersectOctreeObjects( meshesSearch );
|
236 |
| - |
| 234 | + |
237 | 235 | // record end time
|
238 |
| - |
| 236 | + |
239 | 237 | var timeEnd = Date.now();
|
240 |
| - |
| 238 | + |
241 | 239 | // set color of all meshes found in search
|
242 |
| - |
| 240 | + |
243 | 241 | for ( i = 0, il = meshesSearch.length; i < il; i++ ) {
|
244 |
| - |
245 |
| - meshesSearch[ i ].object.material.color.setRGB( foundR, foundG, foundB ); |
246 |
| - |
| 242 | + |
| 243 | + meshesSearch[ i ].object.material.color.copy( found ); |
| 244 | + |
247 | 245 | }
|
248 |
| - |
| 246 | + |
249 | 247 | /*
|
250 |
| - |
| 248 | +
|
251 | 249 | // results to console
|
252 |
| - |
| 250 | +
|
253 | 251 | console.log( 'OCTREE: ', octree );
|
254 | 252 | console.log( '... searched ', meshes.length, ' and found ', meshesSearch.length, ' with intersections ', intersections.length, ' and took ', ( timeEnd - timeStart ), ' ms ' );
|
255 |
| - |
| 253 | +
|
256 | 254 | */
|
257 |
| - |
| 255 | + |
258 | 256 | }
|
259 |
| - |
| 257 | + |
260 | 258 | function render() {
|
261 |
| - |
| 259 | + |
262 | 260 | var timer = - Date.now() / 5000;
|
263 | 261 |
|
264 | 262 | camera.position.x = Math.cos( timer ) * 10000;
|
265 | 263 | camera.position.z = Math.sin( timer ) * 10000;
|
266 | 264 | camera.lookAt( scene.position );
|
267 |
| - |
| 265 | + |
268 | 266 | renderer.render( scene, camera );
|
269 | 267 |
|
270 | 268 | }
|
|
0 commit comments