Unity内实现OBB包围盒算法

栏目: 后端 · 发布时间: 5年前

内容简介:作为碰撞盒的检测,OBB是一个常用的办法。网上有很多文章是介绍原理的,具体可以查一下。 以下给出OBB的Unity实现版本。亲测可跑。参考 :基础:对象拥有BoxCollider控件(用作包围盒)和MeshRenderer控件(模型)

作为碰撞盒的检测,OBB是一个常用的办法。网上有很多文章是介绍原理的,具体可以查一下。 以下给出OBB的Unity实现版本。亲测可跑。

参考 : www.tuicool.com/articles/IN…

效果

Unity内实现OBB包围盒算法

实现

基础:对象拥有BoxCollider控件(用作包围盒)和MeshRenderer控件(模型)

步骤:1.更新BoxCollider 2.更新AABB

更新BoxCollider。这个只需要在编辑器中更新一下即可,不需要运行时不断更新。

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的实现

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.先更新包围盒,所有计算(宽高这些)都是基于包围盒的数据。

2.该算法是做到模型忽略Y轴进行检测,需要的话可以自己补充一下。思路:多一个轴向计算。

3.计算Sin值和参考文章不一样,这里是使用-Sin才得到正确的数值。原因我也还没想到。。知道的话麻烦告诉我一下哈哈哈


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

硅谷热

硅谷热

埃弗雷特.M.罗杰斯 / 范国鹰 等 / 1985.8 / 经济科学出版社 / 1.9

《硅谷热》总共分三部分。第一部分为“硅谷的崛起”,以苹果电脑的传奇故事为主线,讲述了硅谷的发展历史。第二部分为“高技术文明”,从风险投资、创业故事、人物传奇等各个方面描绘了硅谷的生态状况。第三部分为“硅谷的明天”,讲述了硅谷模式在全球的扩散、硅谷面临的全球竞争和深远影响。 书中,硅谷这场传奇的主要角色:人物、公司、技术、产品等都综合在其中,一锅子端给了嗷嗷待哺的人们:PC革命、半导体传奇、软......一起来看看 《硅谷热》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具