- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 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();
You can see the JSfiddle of this here.
如果将指示的变量更改为更大的数字(例如 200),那么您将看到处理时间开始失控。我觉得必须有一种更简单的方法来减少这样做的数组I looked at the documentation for the Raycaster of three.js我注意到 near
和 far
属性都表示“该值指示可以根据距离丢弃哪些对象”。所以我推测有一些内部函数用于在转换所有光线之前根据距离细化结果。
I did a little digging on this and came up with a single function inside of 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.Vector3
对象和数学来按距离细化它们的东西。在这种情况下,运行数学运算的成本必须比光线转换便宜得多。如果在 Three.js 中已经有一个函数可以处理这个问题,我不想从头开始重新创建一个。我还意识到这可能是一个非常冗长的问题,很可能是单行答案,但我想确保我在这里拥有所有细节和其他内容,以防其他人以后想要这样做搜索它。
最佳答案
碰撞检查是一个更普遍的问题,我认为如果您在 Three.js 之外的上下文中考虑它,您会取得更大的成功。有多种方法可以管理大量需要检查彼此碰撞的对象。以下是一些可能与您相关的优化:
第一个优化是让每个对象都有一个 bool 属性,指示自上次物理更新以来它是否移动。如果您要比较的两个对象都没有移动,则无需重新计算碰撞。如果您有大量处于稳定状态的对象(例如您可以推来推去的 crate ),则这非常重要。在此基础上还可以进行许多其他优化;例如,通常如果两个物体没有移动,它们就不会碰撞,因为如果它们碰撞,它们就会后坐(分开)。
第二个优化是通常只需要检查一定距离内的碰撞。例如,如果您知道所有对象都小于 100 个单位,那么您只需检查 (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2 > 100^2
。如果检查为真(表明两个对象之间的距离很大),那么您不需要计算详细的碰撞。事实上,这或多或少是 Raycaster 为您提供的近
/远
优化,但您没有在代码中使用它,因为您总是调用 intersectObject
方法。
第三个优化是您在每次物理更新中分配一堆新的 Raycaster
和相关对象。相反,您可以保留一个 Raycaster 池(甚至单个 Raycaster)并只更新它们的属性。这将避免大量垃圾收集。
最后,处理大量可碰撞对象的最常见通用方法称为空间分区。这个想法基本上是将你的世界划分为给定数量的空间并跟踪哪些空间物体位于其中。然后,当您需要计算碰撞时,您只需要检查同一空间中的其他物体。最常见的方法是使用 Octree (八叉树)。正如 WestLangley 提到的,Three.js 有一个 Octree implementation从 r59 开始,以及 example (source)。 Here使用 2D 示例对空间分区的概念进行了合理的介绍。
除了这些优化之外,如果您需要执行任何特别复杂的操作,您可能需要考虑使用外部物理库,它将为您管理此类优化。目前与 Three.js 一起使用的最流行的是 Physijs , Cannon.js ,和Ammo.js .
关于three.js - 如何在 Three.js 中获取某个位置半径内的其他 3D 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17666404/
我是一名优秀的程序员,十分优秀!