【问题标题】:Handling collision in THREE.js处理 THREE.js 中的冲突
【发布时间】:2025-12-14 22:35:01
【问题描述】:

大家好,我一直在利用很棒的库 three.js 进行我的一个小项目

现在我一直在使用https://github.com/stemkoski/stemkoski.github.com/blob/master/Three.js/Collision-Detection.html 的示例来处理碰撞检测,当一个对象与另一个使用voxel's 的对象重叠时更是如此。

为了引用我的问题,我使用了http://threejs.org/examples/#canvas_interactive_voxelpainter 示例。

无论如何要继续,当我将voxel 渲染到屏幕上时,立方体上方的任何东西都将允许我渲染另一个voxel 一定半径内的任何东西below volex 不会让我渲染:

这里显示了立方体:

现在这是我使用stemkoski提供的示例整理的简洁小函数:

        checkOverlapObject: function(voxel) // THIS IS USED TO SEE IF WE ARE OVER LAPPING ANY OBJECTS
        {
            var originPoint = voxel.position.clone();
            var collidableObjs = this.rooms;
            for (var vertexIndex = 0; vertexIndex < voxel.geometry.vertices.length; vertexIndex++)
            {       
                var localVertex = voxel.geometry.vertices[vertexIndex].clone();
                console.log(localVertex);
                var globalVertex = localVertex.applyMatrix4( voxel.matrix );
                console.log(globalVertex);

                var directionVector = globalVertex.sub( voxel.position );
                console.log(directionVector);

                console.log(originPoint);
                console.log(directionVector.clone().normalize());
                if(collidableObjs.length > 0)
                {
                    var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
                    var collisionResults = ray.intersectObjects( collidableObjs );
                    if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) 
                    {
                        console.log(collisionResults);
                        console.log(collisionResults[0].distance);
                        console.log( directionVector.length() );
                        return false
                    }
                }
            }
            return true;
        },

现在这里发生的情况是,在实际添加渲染的volex 之前,用户可以预览他们是否有权添加volex 所以我们传递了一个volex,由:

 var voxel = new THREE.Mesh( this.room.cubeGeometry, this.room.cubeTmpHoverMaterial );
 voxel.geometry.computeBoundingBox();
 voxel.position.copy( intersect.point ).add( intersect.face.normal );
 voxel.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );
 voxel.material.color.setHex(this.colorTmpHover);

进入我们的checkOverlapObject 函数,查看对象是否与已渲染到screen/grid 上的对象重叠

现在按照我创建的little neat 函数,我已将console.log 放置在输出参数中,以下是其中的一些输出:

T…E.Vector3 {x: 25, y: 25, z: 25} <!-- our localVertex
T…E.Vector3 {x: 25, y: 25, z: 25} <!-- our globalVertex
T…E.Vector3 {x: 0, y: 0, z: -350} <!-- our directionVector
T…E.Vector3 {x: 25, y: 25, z: 375} <!-- our originPoint
T…E.Vector3 {x: 0, y: 0, z: -1} <!-- our directionVector.clone().normalize()
[Object, Object] <!-- our collisionResults
225 <!-- our collisionResults[0].distance
350 <!-- our directionVector.length()

此数据基于第一张图片。

请理解我还有其他volex 占用2 blocks on the grid 或更多。所以这样做的原因是,我有一个位置的中心位置,但如果它占用2 blocks on the grid,我需要考虑对象的其余部分,以检查它是否与already rendered volex重叠我不在乎他们是否互相触摸。

关于可能是什么问题的任何建议或想法?

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    如上所述,我终于找到了解决方案。我为对象collision/overlap 创建了一个自定义函数。

    首先,上面的collision代码有什么问题,如上所示,它处理的是raycaster,以我们objectdirection开头-从它的orgin直接射一条线来看看如果有任何事情与ray 接触。现在,如果object 的任何部分接触到另一个object,这很好,但还不足以告诉我们何时拥有overlap/collision

    正如我们的rays所展示的那样:

    所以这是我的解决方案。

    当我们的飞机上有一个物体时,我们知道它的一切,我们的坐标x,y,z - 在这个例子中我不是在处理y,所以忽略它。

    我们关心的是我们的对象width = x 和我们的对象depth/length = z。所以本质上,当我们检查一个对象是否是overlapping 另一个对象时,我们只需要处理我们的to be added object 中的每个min x/z and max x/z 和我们已经的rendered obj

    我们如何做到这一点,循环通过我们要添加的对象starting min z positionfor 循环。这个起始min z 位置包含我们的position z + min z of object。这为我们提供了zplane 上的确切位置。

    然后我们继续我们的width 或我们要添加的对象starting min x positionfor 循环。不要忘记我们的x 为我们提供了plane 上的确切位置

    现在原因很简单。我们想从要添加的对象的position 0,0 开始。将我们的length/z - increment 一直递增到我们的width/x 并在执行此过程时,我们的plane 上的每个对象都已经渲染并检查是否有任何精确点与我们的匹配。

    这是实际的方法:

            checkOverlapObject: function(voxel) // THIS IS USED TO SEE IF WE ARE OVER LAPPING ANY OBJECTS
            {
    
                var collidableObjs = this.rooms; 
                //lets get our voxel min and max vars
                var voxelMX = voxel.geometry.boundingBox.max.x;
                var voxelMZ = voxel.geometry.boundingBox.max.z;
                var voxelmX = voxel.geometry.boundingBox.min.x;
                var voxelmZ = voxel.geometry.boundingBox.min.z;
                    // we need to get our voxel position ad to do some math to see if voxel min and max do not go beyound our boundries for our plane
                var voxelPX = voxel.position.x;
                var voxelPZ = voxel.position.z;
    
                var totalPositionVoxelminZ = (voxelPZ + voxelmZ);
                var totalPositionVoxelminX = (voxelPX + voxelmX);
                var totalPositionVoxelMAXZ = (voxelPZ + voxelMZ);
                var totalPositionVoxelMAXX = (voxelPX + voxelMX);
    
                // start loop for object to add Z cordinate
                for(var length = totalPositionVoxelminZ; length < totalPositionVoxelMAXZ; length++)
                {
                    // start loop for object to add X cordinate
                    for(var width = totalPositionVoxelminX; width < totalPositionVoxelMAXX; width++)
                    {
                        for(var i = 0; i < collidableObjs.length;i++)
                        {
                            //lets get our voxel min and max vars
                            var thisvoxelMX = this.rooms[i].geometry.boundingBox.max.x;
                            var thisvoxelMZ = this.rooms[i].geometry.boundingBox.max.z;
                            var thisvoxelmX = this.rooms[i].geometry.boundingBox.min.x;
                            var thisvoxelmZ = this.rooms[i].geometry.boundingBox.min.z;
                                // we need to get our voxel position ad to do some math to see if voxel min and max do not go beyound our boundries for our plane
                            var thisvoxelPX = this.rooms[i].position.x;
                            var thisvoxelPZ = this.rooms[i].position.z;
    
                            var thistotalPositionVoxelminZ = (thisvoxelPZ + thisvoxelmZ);
                            var thistotalPositionVoxelminX = (thisvoxelPX + thisvoxelmX);
                            var thistotalPositionVoxelMAXZ = (thisvoxelPZ + thisvoxelMZ);
                            var thistotalPositionVoxelMAXX = (thisvoxelPX + thisvoxelMX);
    
                            for(var insideZ = thistotalPositionVoxelminZ; insideZ < thistotalPositionVoxelMAXZ; insideZ++)
                            {
                                for(var insideX = thistotalPositionVoxelminX; insideX < thistotalPositionVoxelMAXX; insideX++)
                                {
                                    if(insideZ == length && insideX == width)
                                    {
                                        return false;   
                                    }
                                }
                            }
                        }
                    }
    
                }
    
                return true;
            }
    

    这是我们的结果:

    这确实提供了一个确切的答案,即您的对象是否正在触摸它不应该触摸的东西,因为它会逐点处理。

    我希望这会有所帮助!请随时使用。

    还请注意,如果您不小心使用它,这确实会影响 overhead/memory 的使用。在处理数百个对象的情况下,我正在研究一种更好地优化它的方法。因此,如果您对修改或添加到我现有的代码以更好地完成此任务并在传递数百个对象的情况下提供更好的性能有任何建议,请随时提供详细信息!

    【讨论】: