zoukankan      html  css  js  c++  java
  • 胶囊体边界点的计算及获取

    (注意 取的是中心点位置来计算边界点,而非投影点位置。可以自行修改为投影点)

    之前想做一些体积碰撞的效果但是遇到点问题,胶囊边界点检测这个涉及到球体的交点检测以及圆柱的交点检测

    觉得可以放上来,相交检测的代码逻辑来源于网络。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class CapsuleTest : MonoBehaviour
    {
        public enum DirectionEnum { X, Y, Z }
        public Vector3 center;
        public float height = 1f;
        public float radius = 1f;
        public DirectionEnum direction = DirectionEnum.Y;
        public Transform testOutsidePoint;
    
    
        Vector3 Test(Vector3 outsidePoint)
        {
            var localMassPoint = center;
            var localOutsidePoint = transform.worldToLocalMatrix.MultiplyPoint3x4(outsidePoint);
    
            var centerPoint = localMassPoint + center;
    
            var up = Vector3.up;
            var right = Vector3.right;
            var forward = Vector3.forward;
    
            switch (direction)
            {
                case DirectionEnum.X:
                    up = Vector3.right;
                    right = Vector3.forward;
                    forward = Vector3.up;
                    break;
                case DirectionEnum.Z:
                    up = Vector3.forward;
                    right = Vector3.up;
                    forward = Vector3.right;
                    break;
            }
    
            var remainHeight = Mathf.Max(height - radius * 2f, 0) + 0.01f;
            var remainHeightHalf = remainHeight * 0.5f;
            var pillarOrigin = centerPoint + up * -remainHeightHalf;
            var pillarEnd = centerPoint + up * remainHeightHalf;
    
            var insectPoint = Vector3.zero;
            var isHitCylinder = CylinderVSline(localOutsidePoint, (centerPoint - localOutsidePoint).normalized, pillarOrigin, pillarEnd, radius, out insectPoint);
    
            if (isHitCylinder)
            {
                return transform.localToWorldMatrix.MultiplyPoint3x4(insectPoint);
            }
            else
            {
                var spherePoint1 = centerPoint + up * remainHeightHalf;
                var spherePoint2 = centerPoint + (-up) * remainHeightHalf;
                var finalSpherePoint = spherePoint1;
    
                if (Vector3.Distance(localOutsidePoint, spherePoint2) < Vector3.Distance(localOutsidePoint, spherePoint1))
                {
                    finalSpherePoint = spherePoint2;
                }
    
                BetweenLineAndSphere(finalSpherePoint, radius, centerPoint, localOutsidePoint, out spherePoint1, out spherePoint2);
    
                if (Vector3.Distance(spherePoint1, centerPoint) > Vector3.Distance(spherePoint2, centerPoint))
                    return transform.localToWorldMatrix.MultiplyPoint3x4(spherePoint1);
                else
                    return transform.localToWorldMatrix.MultiplyPoint3x4(spherePoint2);
            }
        }
    
        void OnDrawGizmos()
        {
            var cacheColor = Gizmos.color;
            var cacheMatrix = Gizmos.matrix;
    
            if (testOutsidePoint != null)
            {
                var edgePoint = Test(testOutsidePoint.position);
                Gizmos.DrawWireSphere(edgePoint, 0.2f);
            }
    
            Gizmos.color = Color.Lerp(Color.green, Color.gray, 0.5f);
            Gizmos.matrix = transform.localToWorldMatrix;
    
            var remainHeight = Mathf.Max(height - radius * 2f, 0);
            var remainHeightHalf = remainHeight * 0.5f;
    
            var up = Vector3.up;
            var right = Vector3.right;
            var forward = Vector3.forward;
    
            switch (direction)
            {
                case DirectionEnum.X:
                    up = Vector3.right;
                    right = Vector3.forward;
                    forward = Vector3.up;
                    break;
                case DirectionEnum.Z:
                    up = Vector3.forward;
                    right = Vector3.up;
                    forward = Vector3.right;
                    break;
            }
    
            var lastPoint1 = (Vector3?)null;
            var lastPoint2 = (Vector3?)null;
            for (var i = 0f; i <= 180f; i += 9f)
            {
                var point1 = up * -remainHeightHalf + Quaternion.AngleAxis(i, right) * forward * radius;
                var point2 = up * -remainHeightHalf + Quaternion.AngleAxis(i, -forward) * right * radius;
    
                Gizmos.DrawLine(center + lastPoint1.GetValueOrDefault(point1), center + point1);
                Gizmos.DrawLine(center + lastPoint2.GetValueOrDefault(point2), center + point2);
    
                lastPoint1 = point1;
                lastPoint2 = point2;
            }
    
            lastPoint1 = (Vector3?)null;
            for (var i = 0f; i <= 360f; i += 9f)
            {
                var point1 = up * -remainHeightHalf + Quaternion.AngleAxis(i, up) * forward * radius;
    
                Gizmos.DrawLine(center + lastPoint1.GetValueOrDefault(point1), center + point1);
    
                lastPoint1 = point1;
            }
    
            Gizmos.DrawLine(center + forward * radius + up * -remainHeightHalf, center + forward * radius + up * remainHeightHalf);
            Gizmos.DrawLine(center + -forward * radius + up * -remainHeightHalf, center + -forward * radius + up * remainHeightHalf);
    
            Gizmos.DrawLine(center + right * radius + up * -remainHeightHalf, center + right * radius + up * remainHeightHalf);
            Gizmos.DrawLine(center + -right * radius + up * -remainHeightHalf, center + -right * radius + up * remainHeightHalf);
    
            lastPoint1 = (Vector3?)null;
            lastPoint2 = (Vector3?)null;
            for (var i = 0f; i <= 180f; i += 9f)
            {
                var point1 = up * remainHeightHalf + Quaternion.AngleAxis(i, -right) * forward * radius;
                var point2 = up * remainHeightHalf + Quaternion.AngleAxis(i, forward) * right * radius;
    
                Gizmos.DrawLine(center + lastPoint1.GetValueOrDefault(point1), center + point1);
                Gizmos.DrawLine(center + lastPoint2.GetValueOrDefault(point2), center + point2);
    
                lastPoint1 = point1;
                lastPoint2 = point2;
            }
    
            lastPoint1 = (Vector3?)null;
            for (var i = 0f; i <= 360f; i += 9f)
            {
                var point1 = up * remainHeightHalf + Quaternion.AngleAxis(i, up) * forward * radius;
    
                Gizmos.DrawLine(center + lastPoint1.GetValueOrDefault(point1), center + point1);
    
                lastPoint1 = point1;
            }
    
            Gizmos.color = cacheColor;
            Gizmos.matrix = cacheMatrix;
        }
    
        bool BetweenLineAndSphere(
            Vector3 circleCenter, float circleRadius,
            Vector3 point1, Vector3 point2,
            out Vector3 intersection1, out Vector3 intersection2)
        {
            float t;
    
            var dx = point2.x - point1.x;
            var dy = point2.y - point1.y;
            var dz = point2.z - point1.z;
    
            var a = dx * dx + dy * dy + dz * dz;
            var b = 2 * (dx * (point1.x - circleCenter.x) + dy * (point1.y - circleCenter.y) + dz * (point1.z - circleCenter.z));
            var c = (point1.x - circleCenter.x) * (point1.x - circleCenter.x)
                + (point1.y - circleCenter.y) * (point1.y - circleCenter.y)
                + (point1.z - circleCenter.z) * (point1.z - circleCenter.z) - circleRadius * circleRadius;
    
            var determinate = b * b - 4 * a * c;
    
            // Two solutions.
            t = (float)((-b + Mathf.Sqrt(determinate)) / (2 * a));
            intersection1 = new Vector3(point1.x + t * dx, point1.y + t * dy, point1.z + t * dz);
            t = (float)((-b - Mathf.Sqrt(determinate)) / (2 * a));
            intersection2 = new Vector3(point1.x + t * dx, point1.y + t * dy, point1.z + t * dz);
    
            if (intersection1.normalized == Vector3.zero && intersection2.normalized == Vector3.zero)
                return false;
            else
                return true;
        }
    
        bool CylinderVSline(Vector3 start, Vector3 dir, Vector3 aVec, Vector3 bVec, float radius, out Vector3 intersectPoint)
        {
            intersectPoint = Vector3.zero;
    
            // Solution : http://www.gamedev.net/community/forums/topic.asp?topic_id=467789
    
            var ab = bVec - aVec;
            var ao = start - aVec;
            var aoxAb = Vector3.Cross(ao, ab);
            var vxAb = Vector3.Cross(dir, ab);
            var ab2 = Vector3.Dot(ab, ab);
            var a = Vector3.Dot(vxAb, vxAb);
            var b = 2 * Vector3.Dot(vxAb, aoxAb);
            var c = Vector3.Dot(aoxAb, aoxAb) - (radius * radius * ab2);
            var d = b * b - 4 * a * c;
            if (d < 0) return false;
            float time = (-b - Mathf.Sqrt(d)) / (2 * a);
            if (time < 0) return false;
    
            intersectPoint = start + dir * time;
    
            var projectionPoint = aVec + Vector3.Project(intersectPoint - aVec, ab.normalized);
            var distance1 = Mathf.Max(Vector3.Distance(projectionPoint, aVec), Vector3.Distance(projectionPoint, bVec));
            var distance2 = Vector3.Distance(aVec, bVec);
    
            if (distance1 >= distance2)
                return false;
    
            return true;
        }
    }
    View Code
  • 相关阅读:
    SQL Server 快速大数据排序方法
    RGB颜色名称与色值对应表
    Visual Studio 2017 Android 调试无法连接到虚拟机
    sqlite 使用 cte 及 递归的实现示例
    C# 判断文件编码
    SQL点点滴滴_SQL分页查询
    SQL点点滴滴_判断字段或者字符中是否包含有特殊字符
    SQL点点滴滴_公用表表达式(CTE)递归的生成帮助数据
    【Oracle】Update方法
    SQL点点滴滴_DELETE小计
  • 原文地址:https://www.cnblogs.com/hont/p/9470781.html
Copyright © 2011-2022 走看看