• Unity内实现OBB包围盒算法


    前言

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

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

    效果

    实现

    基础:对象拥有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才得到正确的数值。原因我也还没想到。。。

    原文连接:https://juejin.cn/post/6844903857206591501

  • 相关阅读:
    跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByTagName
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName
    跟随标准与Webkit源码探究DOM -- 获取元素之getElementById
    原生DOM探究 -- NodeList v.s. HTMLCollection
    Jira 在流程节点中每个状态权限设置
    Eureka集群配置
    Linux下搭建 redis
    python框架django中结合vue进行前后端分离
  • 原文地址:https://www.cnblogs.com/atong/p/14092186.html
Copyright © 2020-2023  润新知