我在three.js中有一个3D场景,我需要获取一组距离源对象X范围内的对象数组。目前,我使用的示例在场景中利用射线投射(raycasting)和for循环迭代“可碰撞物体”数组。如果每个数组中的对象都必须从自身到数组中的其他对象进行射线投射,则此方法的复杂度呈指数级增长,因此我认为一定有更好的方法来处理这个问题。随着可碰撞物体数组的增长,这会对性能产生巨大的影响。
我想找到一种更好的方法,以获取场景中与源对象距离为X的所有对象。我甚至不需要使用射线投射,因为我对网格碰撞不感兴趣,只需列出源对象周围距离在X范围内的对象列表。由于场景设置的原因,我甚至不需要递归进入这些对象的子元素。因此,我认为three.js中必须有某个内部函数或类可以仅使用
//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();
如果您将指定的变量更改为较大的数字,比如 200,则会发现处理时间开始失控。我觉得必须有一种更简单的方式来减少数组的大小,所以我查看了 three.js 的 Raycaster 文档,并注意到 near
和 far
属性都说“此值表示可以根据距离丢弃哪些对象”,因此我推断出在投射所有光线之前,应该使用某些内部函数根据距离细化结果。
我对此进行了一些调查,并在 Ray.js
中找到了一个单独的函数。
distanceToPoint: function () {
var v1 = new THREE.Vector3();
return function ( point ) {
var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
// point behind the ray
if ( directionDistance < 0 ) {
return this.origin.distanceTo( point );
}
v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
return v1.distanceTo( point );
};
}(),
我想找到一种更好的方法,以获取场景中与源对象距离为X的所有对象。我甚至不需要使用射线投射,因为我对网格碰撞不感兴趣,只需列出源对象周围距离在X范围内的对象列表。由于场景设置的原因,我甚至不需要递归进入这些对象的子元素。因此,我认为three.js中必须有某个内部函数或类可以仅使用
THREE.Vector3
对象和数学来通过距离来细化它们。在这种情况下,比起射线投射,这将是更便宜的计算量。如果three.js中已经有一个处理此问题的函数,我就不想从头开始重新创建一个。我也意识到,这可能是一个非常冗长的问题,但我想确保在后来搜索此类内容的其他人能够看到所有细节和附加信息。