zoukankan      html  css  js  c++  java
  • 碰撞检測之OBB-OBB的SweepTest

    提要

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


    两帧的位置已经直接将中间的板子穿过了,所以 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 frame
    	void 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



  • 相关阅读:
    江西理工大学南昌校区cool code竞赛
    喵哈哈村的魔法考试 Round #3 (Div.2) ABCDE
    项目管理概要记录
    JS开发引用HTML DOM的location和document对象
    Linux下触摸屏驱动程序分析
    敦泰FT6X06单层自容调屏
    FT5X06 如何应用在10寸电容屏(linux-3.5电容屏驱动简析&移植10寸电容屏驱动到Android4.2) (by liukun321咕唧咕唧)
    基于FT5x06嵌入式Linux电容触摸屏驱动
    Linux/Android多点触摸协议
    高通 8x12 添加 TP和按键
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8612854.html
Copyright © 2011-2022 走看看