首页 > 解决方案 > 如何使用 Threejs 实现两个对象之间的捕捉效果和碰撞检测?

问题描述

我们能够检测到碰撞,但无法实现捕捉/磁性效果,例如将对象的边缘相互对齐并防止重叠 ,我们在此处需要 3D 对象的帮助,我们正在使用 Vec3 作为活动对象的位置。

使用以下方法,碰撞检测在所有情况下都可以完美地工作,并且磁效应在某种程度上起作用 - 并不完美。当对象沿 x 或 z 轴移动时效果很好,但是当对象的移动沿对角线方向(同时沿 x 和 z 轴移动)时,问题就出现了。

虽然对以下方法不满意,但这就是为什么我正在寻找新方法来实现磁性和碰撞检测功能。Threejs中不需要有解,任何通用的解或坐标算法都可以转换成Threejs。

        let collide = this.detectCollisionCubes(activeObject, collidingObject, vec3);
  
        let magneticEffect = new MagneticEffect(activeObject, vec3, collidingObject);
        vec3 = magneticEffect.setNewPosition(); 
        activeObject.position.copy(vec3); 
             

        detectCollisionCubes = function(a, d, vec3){
            // a is active object's positon
            // d is colliding object                        
   
            let aHeight = Math.abs(a.getHeight());
            let aWidth = Math.abs(a.getWidth());
            let aDepth = Math.abs(a.getDepth());

            let b1 = vec3.y - aHeight / 2;
            let t1 = vec3.y + aHeight / 2;

            let r1 = vec3.x + aWidth / 2;
            let l1 = vec3.x - aWidth / 2;

            let f1 = vec3.z - aDepth / 2;
            let B1 = vec3.z + aDepth / 2;

            let dHeight = Math.abs(d.getHeight());
            let dWidth = Math.abs(d.getWidth());
            let dDepth = Math.abs(d.getDepth());
            
            let b2 = d.position.y - dHeight / 2;
            let t2 = d.position.y + dHeight / 2;

            let r2 = d.position.x + dWidth / 2;
            let l2 = d.position.x - dWidth / 2;

            let f2 = d.position.z - dDepth / 2;
            let B2 = d.position.z + dDepth / 2;
            
            if (t1 < b2 || r1 < l2 || b1 > t2 || l1 > r2 || f1 > B2 || B1 < f2) {
              return false;
            }

            return true;
        }

试图通过创建磁效应

    this.currentObject = currentObject;
    this.collisionObject = collisionObject;
    this.collisionType = null;
    this.objectType = null;
    this.currentPosition = currentPosition; 

    this.currentObjectHeight = Math.abs(currentObject.getHeight());
    this.currentObjectWidth = Math.abs(currentObject.getWidth());

    this.collisionObjectHeight = Math.abs(collisionObject.getHeight());
    this.collisionObjectWidth = Math.abs(collisionObject.getWidth());
    this.collisionObjectDepth = Math.abs(collisionObject.getDepth());

    this.objectTop = currentObject.position.y + (this.currentObjectHeight/2);
    this.objectBottom = currentObject.position.y - (this.currentObjectHeight/2);

    this.collideTop = collisionObject.position.y + (this.collisionObjectHeight/2);
    this.collideBottom = collisionObject.position.y - (this.collisionObjectHeight/2);

    this.zAxisDifference = Math.abs(Math.abs(currentPosition.z) - Math.abs(collisionObject.position.z));
    this.xAxisDifference = Math.abs(Math.abs(currentPosition.x) - Math.abs(collisionObject.position.x));
     
     // Extra code here   
     
    if (
        this.objectTop < this.collideBottom
    ) { 
        this.collisionType = collisionTypes.verticalBottom;
    } else if (
        this.objectBottom > this.collideTop
    ) { 
        this.collisionType = collisionTypes.verticalTop;
    } else if (
        this.currentPosition.x > this.collisionObject.position.x &&
        this.zAxisDifference < 2
    ) {
        this.collisionType = collisionTypes.horizentalXLeft;
    } else if (
        this.currentPosition.x < this.collisionObject.position.x &&
        this.zAxisDifference < 2
    ) {
        this.collisionType = collisionTypes.horizentalXRight;
    } else if (
        this.currentPosition.z > this.collisionObject.position.z &&
        this.xAxisDifference < 2
    ) {
        this.collisionType = collisionTypes.horizentalZLeft;
    } else if (
        this.currentPosition.z < this.collisionObject.position.z &&
        this.xAxisDifference < 2
    ) {
        this.collisionType = collisionTypes.horizentalZRight;
    }

 MagneticEffect.prototype.setNewPosition = function () {
    
    if (this.collisionType === collisionTypes.verticalBottom) {
        this.currentPosition.y = this.collideBottom + 0.5;
    } else if (this.collisionType === collisionTypes.verticalTop) {
        this.currentPosition.y = this.collideTop - 0.5;
    } else if (this.collisionType === collisionTypes.horizentalXRight) {
        this.currentPosition.x = this.collisionObject.position.x - this.collisionObjectWidth - 0.5;
    } else if (this.collisionType === collisionTypes.horizentalXLeft) {
        this.currentPosition.x = this.collisionObject.position.x + this.collisionObjectWidth + 0.5;
    } else if (this.collisionType === collisionTypes.horizentalZRight) {
        this.currentPosition.z = this.collisionObject.position.z - this.collisionObjectWidth - 0.5;
    } else if (this.collisionType === collisionTypes.horizentalZLeft) {
        this.currentPosition.z = this.collisionObject.position.z + this.collisionObjectWidth + 0.5;
    }

    return this.currentPosition;
};

标签: three.jscollision-detectionsnapping

解决方案


推荐阅读