做爲碰撞盒的檢測,OBB是一個經常使用的辦法。網上有不少文章是介紹原理的,具體能夠查一下。 如下給出OBB的Unity實現版本。親測可跑。算法
參考 :www.tuicool.com/articles/IN…bash
基礎:對象擁有BoxCollider控件(用做包圍盒)和MeshRenderer控件(模型)編輯器
步驟:1.更新BoxCollider 2.更新AABBide
更新BoxCollider。這個只須要在編輯器中更新一下便可,不須要運行時不斷更新。ui
using UnityEngine;
public class UpdateBoxColliderHelp
{
private Transform m_Transform;
private MeshRenderer m_MeshRenderer;
private BoxCollider m_BoxCollider;
public UpdateBoxColliderHelp(Transform transform)
{
m_Transform = transform;
m_MeshRenderer = m_Transform.GetComponent<MeshRenderer>();
m_BoxCollider = m_Transform.GetComponent<BoxCollider>();
UpdateBoxCollider();
}
public void UpdateBoxCollider()
{
if (m_MeshRenderer == null || m_BoxCollider == null)
{
Debug.Log(string.Format("對象{0}沒有指定控件,跳過。", m_Transform.name));
return;
}
Vector3 position = m_Transform.position;
Vector3 scale = m_Transform.localScale;
Quaternion rotation = m_Transform.rotation;
m_Transform.position = Vector3.zero;
m_Transform.localScale = Vector3.one;
m_Transform.rotation = new Quaternion(0,0,0,1);
m_BoxCollider.size = m_MeshRenderer.bounds.size;
m_BoxCollider.center = m_MeshRenderer.bounds.center;
m_Transform.position = position;
m_Transform.localScale = scale;
m_Transform.rotation = rotation;
Debug.Log(string.Format("對象{0}的BoxCollider更新完畢。", m_Transform.name));
}
}
複製代碼
OBB的實現spa
using System;
using UnityEngine;
public class OBBRect
{
public Transform m_Transform;
public BoxCollider m_BoxCollider;
private double m_Rotation;
public Vector2 m_Extents;
public Vector2[] m_Axiss;
public OBBRect(Transform transform)
{
m_Transform = transform;
m_BoxCollider = m_Transform.GetComponent<BoxCollider>();
m_Axiss = new Vector2[2];
SetExtents();
}
private void SetExtents()
{
Quaternion rotation = m_Transform.rotation;
m_Transform.rotation = new Quaternion(0, 0, 0, 1);
Vector3 center = m_BoxCollider.center;
Vector3 size = m_BoxCollider.size / 2;
Vector3 Point1 = new Vector3(center.x + size.x, center.y, center.z - size.z);
Vector3 Point2 = new Vector3(center.x - size.x, center.y, center.z + size.z);
Point1 = m_Transform.localToWorldMatrix.MultiplyPoint3x4(Point1);
Point2 = m_Transform.localToWorldMatrix.MultiplyPoint3x4(Point2);
m_Extents = new Vector2(Mathf.Abs(Point1.x - Point2.x)/2,Mathf.Abs(Point2.z - Point1.z)/2);
m_Transform.rotation = rotation;
}
public float dot(Vector2 a, Vector2 b)
{
return Mathf.Abs(a.x * b.x + a.y * b.y);
}
public float getProjectionRadius(Vector2 axis)
{
return (m_Extents.x * dot(m_Axiss[0], axis) + m_Extents.y * dot(m_Axiss[1], axis));
}
public void Update()
{
m_Rotation = m_Transform.eulerAngles.y * Math.PI / 180;
m_Axiss[0] = new Vector2( (float) Math.Cos(m_Rotation), -(float) Math.Sin(m_Rotation));
m_Axiss[1] = new Vector2(-m_Axiss[0].y, m_Axiss[0].x);
}
public bool intersects(OBBRect other)
{
Update();
other.Update();
Vector2 distanceVector = new Vector2(m_Transform.position.x - other.m_Transform.position.x, m_Transform.position.z - other.m_Transform.position.z);
Vector2[] checkObbVector2s =
{
m_Axiss[0],
m_Axiss[1],
other.m_Axiss[0],
other.m_Axiss[1],
};
for (int index = 0; index < checkObbVector2s.Length; index++)
{
Vector2 curVector2 = checkObbVector2s[index];
if ((getProjectionRadius(curVector2) + other.getProjectionRadius(curVector2)) <= dot(distanceVector, curVector2))
{
return false;
}
}
return true;
}
}
複製代碼
1.先更新包圍盒,全部計算(寬高這些)都是基於包圍盒的數據。code
2.該算法是作到模型忽略Y軸進行檢測,須要的話能夠本身補充一下。思路:多一個軸向計算。orm
3.計算Sin值和參考文章不同,這裏是使用-Sin才獲得正確的數值。緣由我也還沒想到。。知道的話麻煩告訴我一下哈哈哈cdn