I have a three-dimensional scene in three .js in which I need to get an array of objects that are within the X range of the original object. At the moment, the example I'm using uses raycasting inside a for loop, which iterates through an array of "collidable objects" that exist in the scene. I feel that there should be a better way to handle this, because this approach is exponentially more complex if every object in the array needs raycast from itself to every other object in the array. This has a significant impact on performance, as the array of collision capable objects grows.
//hold collidable objects var collidableObjects = []; var scene = new THREE.Scene(); var cubeGeo = new THREE.CubeGeometry( 10 , 10 , 10 ); var materialA = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); var materialB = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); var cubeA = new THREE.Mesh( cubeGeo , materialA ); collidableObjects.push( cubeA ); scene.add( cubeA ); //Change this variable to a larger number to see the processing time explode var range = 100; for( var x = 0 ; x < range ; x += 20 ) { for( var z = 0; z < range ; z += 20 ) { if( x === 0 && z === 0 ) continue; var cube = new THREE.Mesh( cubeGeo , materialB ); scene.add( cube ); cube.position.x = x; cube.position.z = z; collidableObjects.push( cube ); var cube = cube.clone(); scene.add( cube ); cube.position.x = x * -1; cube.position.z = z; collidableObjects.push( cube ); var cube = cube.clone(); scene.add( cube ); cube.position.x = x; cube.position.z = z * -1; collidableObjects.push( cube ); var cube = cube.clone(); scene.add( cube ); cube.position.x = x * -1; cube.position.z = z * -1; collidableObjects.push( cube ); } } var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); camera.position.y = 200; camera.lookAt( scene.position ); function render() { //requestAnimationFrame(render); renderer.render(scene, camera); console.log( getObjectsWithinRange( cubeA , 30 ) ); } function getObjectsWithinRange( source , range ) { var startTime = new Date().getTime(); var inRange = []; for( var i = 0; i < collidableObjects.length ; ++i ) { var ray = new THREE.Raycaster( source.position , collidableObjects[i].position , 0 , range ); if( ( obj = ray.intersectObject( collidableObjects[i] ) ) && obj.length ) { inRange.push( obj[0] ); } } var endTime = new Date().getTime(); console.log( 'Processing Time: ' , endTime - startTime ); return inRange; } render();
Here you can see the JSfiddle.
If you change the specified variable to a larger number, say 200, you will see that the processing time starts to get out of control. I feel that there should be an easier way to reduce the number of such actions so that I look at the documentation for Raycaster from three.js and I notice that both near and far attributes say: "This value indicates which objects can be dropped based on distance" . therefore, I assume there is some internal function that is used to refine the results down based on distance before throwing all the rays.
I worked a bit on this and came up with one function inside Ray.js
distanceToPoint: function () { var v1 = new THREE.Vector3(); return function ( point ) { var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
I assume that I am looking for the best way to get all the objects in the scene that are within the radius X of the radius of the original object. I donβt even need to use Raycasting, because I am not interested in a grid collision, but just a list of objects in the radius X of the radius of the original object. I donβt even need to go back to the children of these objects because of how the scene is created. So I feel that there needs to be some kind of internal function or something that just uses THREE.Vector3 objects and math to refine them by distance. In this case, it should be much cheaper math than Raycasting. If there is already a function that processes this somewhere in the three.js file, I don't want to recreate it from scratch. I also understand that this can be a very long question about what can be a very definite answer, but I wanted to make sure that I have all the details and something else, if someone else is looking for it, he is looking for it later.