碰撞检测之OBB-OBB的SweepTest

来源:互联网 发布:公司取名软件注册码 编辑:程序博客网 时间:2024/05/18 06:22

提要

当物体在运动的时候,普通的每帧进行碰撞检测已经无法满足要求,比如子弹的运动


两帧的位置已经直接将中间的板子穿过了,所以 t 时刻和 t +1 时刻的检测都是失效的。这时候需要用到的就是sweep检测了。今天要处理的就是AABB的Sweep检测。



2D情况

如下图,当前位置是蓝色Box所在位置,目的位置是绿色框所在位置。



2D情况只用处理x,y方向的,利用SAP理论,分别在各个轴向计算可以移动的距离。代码如下

 public static Vector2 SweepTest(OBB from, OBB other, Vector2 movement){        float deltaX = movement.x;        float deltaY = movement.y;        if (from.max.y > other.min.y && from.min.y < other.max.y)        {            float d1;            if (deltaX > 0.0D && from.max.x <= other.min.x)            {                d1 = other.min.x - from.max.x;                if (d1 < deltaX)                {                    deltaX = d1;                }            }            else if (deltaX < 0.0D && from.min.x >= other.max.x)            {                d1 = other.max.x - from.min.x;                if (d1 > deltaX)                {                    deltaX = d1;                }            }        }        if (from.max.x > other.min.x && from.min.x < other.max.x)        {            float d1;            if (deltaY > 0f && from.max.y <= other.min.y)            {                d1 = other.min.y - from.max.y;                if (d1 < deltaY)                {                    deltaY = d1;                }            }            else if (deltaY < 0f && from.min.y >= other.max.y)            {                d1 = other.max.y - from.min.y;                if (d1 > deltaY)                {                    deltaY = d1;                }            }        }        return Vector2(deltaX, deltaY);}

输入是两个OBB,from是要运动的OBB,movement是要进行的位移,返回的是最终的位移。

简单说一下X方向的判断,

首先

if (from.max.y > other.min.y && from.min.y < other.max.y)

要判断的是两个OBB在Y方向的投影是否有重叠,如果没有就直接返回movement 的x分量,因为在X方向不可能发生碰撞。

接下来判断的是如果from在other的左边,看是否有足够的空间给它运动,没有的话直接贴到other的边边上。from在other的右边的情况做同样的检测。


3D情况

只要简单的扩展到3D情况就可以了。

    public static Vector3 SweepTest(Bounds from, Bounds other, Vector3 movement)    {        float deltaX = movement.x;        float deltaY = movement.y;        float deltaZ = movement.z;        if (from.max.y > other.min.y && from.min.y < other.max.y && from.max.z > other.min.z && from.min.z < other.max.z)        {            float d1;            if (deltaX > 0.0D && from.max.x <= other.min.x)            {                d1 = other.min.x - from.max.x;                if (d1 < deltaX)                {                    deltaX = d1;                }            }            else if (deltaX < 0.0D && from.min.x >= other.max.x)            {                d1 = other.max.x - from.min.x;                if (d1 > deltaX)                {                    deltaX = d1;                }            }        }        if (from.max.x > other.min.x && from.min.x < other.max.x && from.max.z > other.min.z && from.min.z < other.max.z)        {            float d1;            if (deltaY > 0f && from.max.y <= other.min.y)            {                d1 = other.min.y - from.max.y;                if (d1 < deltaY)                {                    deltaY = d1;                }            }            else if (deltaY < 0f && from.min.y >= other.max.y)            {                d1 = other.max.y - from.min.y;                if (d1 > deltaY)                {                    deltaY = d1;                }            }        }        if (from.max.x > other.min.x && from.min.x < other.max.x && from.max.y > other.min.y && from.min.y < other.max.y)        {            float d1;            if (deltaZ > 0.0D && from.max.z <= other.min.z)            {                d1 = other.min.z - from.max.z;                if (d1 < deltaZ)                {                    deltaZ = d1;                }            }            else if (deltaZ < 0.0D && from.min.z >= other.max.z)            {                d1 = other.max.z - from.min.z;                if (d1 > deltaZ)                {                    deltaZ = d1;                }            }        }        return new Vector3(deltaX, deltaY, deltaZ);    }


测试代码

using UnityEngine;using System.Collections;using NPhysX;public class BoxBoxSweepTester : MonoBehaviour {    public Vector3 direction;    public float speed;    public GameObject box;    public GameObject box1;    Box _box;    Box _box1;    // Use this for initialization    void Start()    {        _box = new Box();        _box1 = new Box();        direction = Vector3.one;    }// Update is called once per framevoid Update () {        Vector3 moveVector = speed * direction;        Vector3 realMove = NSweepTests.SweepTest(box.GetComponent<BoxCollider>().bounds, box1.GetComponent<BoxCollider>().bounds, moveVector);        box.transform.position += realMove;    }}


测试结果


参考

Swept AABB Collision Detection and Response - http://www.gamedev.net/page/resources/_/technical/game-programming/swept-aabb-collision-detection-and-response-r3084



0 0
原创粉丝点击