一些图形学中的数学应用

包围体是一个简单的几何空间,里面包含着复杂形状的物体。为物体添加包围体的目的是快速的进行碰撞检测或者进行精确的碰撞检测之前进行过滤(即当包围体碰撞,才进行精确碰撞检测和处理)。包围体类型包括球体、轴对齐包围盒(AABB)、有向包围盒(OBB)、8-DOP以及凸壳。如图1所示。

clip_image001

                                                                       图1 依次是球体、AABB、OBB

可以看到图1是3D包围体,在2D包围体如图2所示:

clip_image003

                                                                    图2 依次是球体、AABB、OBB

 

OBB

方向包围盒(Oriented bounding box),简称OBB。方向包围盒类似于AABB,但是具有方向性、可以旋转,AABB不能旋转。如图3所示。

clip_image005

                                                                  图3 矩形和矩形投影检测的四条轴

要计算两个OBB是否碰撞,只需要计算他们在图3上的4个坐标轴上的投影是否都发生重叠,如果是,则两多边形有接触。这也可以扩展到任意多边形,如图4所示。

                                                    clip_image007

                                                            图4 矩形和三角形投影检测的五条轴

投影轴来自于多边形自身边的垂线。

判定方式:两个多边形在所有轴上的投影都发生重叠,则判定为碰撞;否则,没有发生碰撞

OBB存在多种的表达方式,这里使用最常用的一种:一个中心点、2个矩形的边长、两个旋转轴(该轴垂直于多边形自身的边,用于投影计算)。代码如下所示:

(function (window) {

    var OBB = function (centerPoint, width, height, rotation) {

        this.centerPoint = centerPoint;
        this.extents = [width / 2, height / 2];
        this.axes = [new Vector2(Math.cos(rotation), Math.sin(rotation)), new Vector2(-1 * Math.sin(rotation), Math.cos(rotation))];

        this._width = width;
        this._height = height;
        this._rotation = rotation;
    }

    window.OBB = OBB;
})(window);

其所依赖的Vector2这个类如下所示:

(function (window) {
    Vector2 = function (x, y) {
        this.x = x || 0;
        this.y = y || 0;
    };

    Vector2.prototype = {
        sub: function (v) {
            return new Vector2(this.x - v.x, this.y - v.y)
        },
        dot: function (v) {
            return this.x * v.x + this.y * v.y;
        }
    };
    window.Vector2 = Vector2;
} (window))

然后基于这个数据结构,进行OBB之间的相交测试。为OBB扩展一个方法,即或者在任意轴上的投影半径:

OBB.prototype = {
    getProjectionRadius: function (axis) {
        returnthis.extents[0] * Math.abs(axis.dot(this.axes[0])) + this.extents[1] * Math.abs(axis.dot(this.axes[1]));
    }
}

这里你可能需要读者了解Vector2.dot的几何意义:若b为单位矢量,则a与b的点积即为a在方向b的投影

有了这些,就可以进行相交检测。由上面的判定方式,可以得出,两个矩形之间的碰撞检测需要判断四次(每个投影轴一次)。完整检测代码如下所示:

(function (window) {

    var CollisionDetector = {

        detectorOBBvsOBB: function (OBB1, OBB2) {
            var nv = OBB1.centerPoint.sub(OBB2.centerPoint);
            var axisA1 = OBB1.axes[0];
            if (OBB1.getProjectionRadius(axisA1) + OBB2.getProjectionRadius(axisA1) <= Math.abs(nv.dot(axisA1))) return false;
            var axisA2 = OBB1.axes[1];
            if (OBB1.getProjectionRadius(axisA2) + OBB2.getProjectionRadius(axisA2) <= Math.abs(nv.dot(axisA2))) return false;
            var axisB1 = OBB2.axes[0];
            if (OBB1.getProjectionRadius(axisB1) + OBB2.getProjectionRadius(axisB1) <= Math.abs(nv.dot(axisB1))) return false;
            var axisB2 = OBB2.axes[1];
            if (OBB1.getProjectionRadius(axisB2) + OBB2.getProjectionRadius(axisB2) <= Math.abs(nv.dot(axisB2))) return false;
            return true;

        }
    }

    window.CollisionDetector = CollisionDetector;
})(window)

这里拿两个OBB的中心点连线在坐标轴上的投影长度和两个矩形投影半径之和进行对比,如果半径之后都小于或者等于中心连线之后才判定为碰撞,否则判定为分离状态。

 

怎样判断平面上一个矩形和一个圆形是否有重叠?

c为矩形中心,h为矩形半長,p为圆心,r为半径。

计算方法是先找到矩形上离圆形最短距离u,然后再比较u是否小于圆形的半径r

1. 首先利用绝对值把 p - c 转移到第一象限,下图显示不同象限的圆心也能映射至第一象限,这不影响相交测试的结果:

 

 

2. 然后,把 v 减去 h,负数的分量设置为0,就得到圆心与矩形最短距离的矢量 u。下图展示了4种情况,红色的u是结果。

 3. 最后要比较 和 r 的长度,若距离少于 r,则两者相交。可以只求 的长度平方是否小于 的平方。

 

转自知乎https://www.zhihu.com/question/24251545

方向包圍盒碰撞檢測

https://www.cnblogs.com/iamzhanglei/archive/2012/06/07/2539751.html

射线与平面的相交检测(Ray-Plane intersection test)

https://www.cnblogs.com/graphics/archive/2009/10/17/1585281.html

 

判断点是否在三角形内

https://www.cnblogs.com/graphics/archive/2010/08/05/1793393.html

 

射线和三角形的相交检测(ray triangle intersection test)

https://www.cnblogs.com/graphics/archive/2010/08/09/1795348.html

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值