如何获取three.js中某个位置半径内的其他3D对象

如何获取three.js中某个位置半径内的其他3D对象,three.js,raycasting,radial,Three.js,Raycasting,Radial,我在three.js中有一个3D场景,在这个场景中,我需要获得一个在源对象X范围内的对象数组。目前,我使用的示例是在for循环中使用光线投射,该循环迭代场景中存在的“可碰撞对象”数组。我觉得必须有更好的方法来处理这个问题,因为如果数组中的每个对象都必须从自身光线投射到数组中的每个其他对象,那么这种方法将以指数形式变得更加复杂。随着可碰撞对象阵列的增长,这将对性能产生巨大影响 //hold collidable objects var collidableObjects = []; var sc

我在three.js中有一个3D场景,在这个场景中,我需要获得一个在源对象X范围内的对象数组。目前,我使用的示例是在for循环中使用光线投射,该循环迭代场景中存在的“可碰撞对象”数组。我觉得必须有更好的方法来处理这个问题,因为如果数组中的每个对象都必须从自身光线投射到数组中的每个其他对象,那么这种方法将以指数形式变得更加复杂。随着可碰撞对象阵列的增长,这将对性能产生巨大影响

//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();

我想我要寻找的是一种更好的方法来获取场景中所有在源对象X半径范围内的对象。我甚至不需要使用光线投射,因为我对网格碰撞不感兴趣,而只是源对象X半径范围内的对象列表。由于场景的设置方式,我甚至不需要递归到这些对象的子对象中。所以我觉得一定有一些内部函数,或者简单地使用
THREE.Vector3
对象和数学,通过距离来细化它们。在这种情况下,运行数学要比光线投射便宜得多。如果three.js中已经有一个函数可以处理这个问题,我不想从头开始重新创建一个函数。我也意识到这可能是一个冗长的问题,很可能是一句话的答案,但是我想确保我在这里有所有的细节等等,以防以后有人想搜索它。

冲突检查是一个更普遍的问题,如果你在Three.js之外的上下文中考虑它,我想你会更成功。有许多方法可用于管理大量需要检查彼此碰撞的对象。以下是一些可能与您相关的优化:

第一个优化是每个对象都有一个布尔属性,指示自上次物理更新以来它是否移动。如果要比较的两个对象都未移动,则无需重新计算碰撞。如果您有大量处于稳定状态的对象(如您可以推来推去的板条箱),则这一点最为重要。在此基础上,您还可以构建许多其他优化;例如,如果两个对象没有移动,它们通常不会发生碰撞,因为如果它们发生碰撞,它们会后退(移动分开)

第二个优化是,通常只需要检查一定距离内的碰撞。例如,如果您知道所有对象都小于100个单位,则只需检查
(x1-x2)^2+(y1-y2)^2+(z1-z2)^2>100^2
。如果检查为true(表示两个对象之间的距离很大),则不需要计算详细的碰撞。实际上,这或多或少是
Raycaster
为您提供的
near
/
far
优化,但您并没有在代码中使用它,因为您总是调用
intersectObject
方法

第三个优化是在每次物理更新中分配一组新的
Raycaster
和相关对象。相反,您可以保留一个光线投射器池(甚至一个光线投射器)并只更新其属性。这将避免大量垃圾收集

最后,处理大量可碰撞对象的最常见的通用方法称为空间划分。其基本思想是将世界划分为给定数量的空间,并跟踪其中的空间对象。然后,当需要计算碰撞时,只需检查同一空间中的其他对象。最常用的方法是使用(8元树)。正如WestLangley提到的,Three.js在r59中有一个开头,还有一个()。是使用2D示例对空间划分概念的合理介绍


<>这些优化之外,如果你需要做任何特别复杂的事情,你可能想考虑使用一个外部物理库,它将为你管理这样的优化。目前与Three.js一起使用的最流行的是,和。

Three.js r.59有一个。@WestLangley哇,我甚至没有看到,但根据我在渲染器中看到的,这个例子可能有一些功能,可能会证明很有用:)谢谢,我会看一看,这是一篇措辞精辟的帖子。非常感谢你。你讲了很多我没有考虑过的问题。我曾经考虑过分区对象,但是没有办法处理分区“边界”上的对象。似乎八叉树实现正是我处理优化所需要的。尽管有函数/变量名,但在本例中,我实际上不需要检查碰撞,而是需要检查距离。这个系统在我正在开发的MMO服务器中被用作“视线”、攻击检测等的预过滤器。我继续并将此标记为我的答案,因为实现八叉树肯定比我最初认为的有更好的性能提升:)我甚至不知道他们在三个中添加了一个八叉树。js:P再次感谢!
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 );

};

}(),