• 【原】3D游戏中的算法MMO游戏全视角3D相机,全地形中视觉障碍物自动缩进调整


    大家好,欢迎大家多多交流,转载请注明出处,谢谢。

    我来博客园的第一篇博客,想写的东西很多,基于目前工作手里的内容,先上一篇算法的。

    上周做了个3D自由相机功能,需要对地形和墙壁进行自动缩进动画,效果经过多款游戏对比,决定编写《万王之王》的相机效果。

    我发现很多同学,基础知识都不错,但是自己写的话,却不知道怎么去实现具体算法和方案,其实这种情况不用着急,养成好的需求分析习惯会帮助你提前解决很多难题。但是需求分析再好,对于算法来说,基础知识的掌握更加重要。

    所以下面几个步骤是解决问题的流程。

    第一步:首先就是自身基础了,关于3d向量的掌握,必须达到一定层次,否则很难处理好这种复杂环境下的算法策略,如果算法不好的,接着看,或许能让你有所提高。

    第二步:其次就是对于相机功能的需求分析,需求分析是通过游戏还有和游戏策划沟通的结果,需求分析的准确与否决定了我们最终的结果,否则需求分析的错误或者不明确会带来代码策略的错误,影响工期。

    第三步:很多同学到这里可能以为要开始动手写代码了,不着急,这里建议大家先整理游戏中相关流程,确定自己方案可行性,然后编写伪代码或者方案流程。伪代码能提前实验逻辑的可行性和纰漏,总览全局,避免实际编写代码过程中的盲目或者片面引起的时间成本。

    第四步:接下来可以开始编写你的代码了。

    相机涉及数学知识:

     涉及的数学知识不多,作为游戏开发人员,这些知识点事必备技能,如果有不熟悉或者不知道的,一定要及时补充知识。

      1:主要是对3d空间的理解,空间点,空间向量,空间角度的概念。

      2:熟悉3D向量相关计算,余弦公式,角度计算,三角函数,向量投影计算和物理意义

      3:熟悉笛卡尔坐标系,熟悉点乘积和叉乘积计算和物理意思,知道右手定则,平面法线等知识。 

    相机需求:

    1:3D自由相机通用功能,滑动屏幕可以随意调整方向和缩进显示距离。

    2:在1基础上对相机进行遮挡碰撞处理,相机和角色中间有阻挡时相机自动越过障碍物(渐进运动方式),并且保持相机视域内不在物体内部(穿墙情况)。

    3:相机离开遮挡的时候回复原来自由相机设置距离,并且动态回复到合适位置。

    4:对任意形状的阻挡(墙面,地面,任意角度斜坡)进行处理后不穿强。

    5:发生视觉遮挡时,缩进的速度与滑动屏幕的速度成正比(这样体验会好,慢慢转动相机,遇到视觉阻挡时,正常缩进动画,当快速滑动屏幕时,就需要快速缩进相机,以防止视线穿墙)

    方案:

       1:射线检测,因为需要考虑各种地形的角度,所以射线检测方案修改成,视椎体射线检测方案,请看函数NearClipPlanePoints。(相机视口的4个点分别向目标点打射线进行检测,碰撞点取距离角色最近的)

       2:相机提前预检测,提前计算下一帧相机碰撞,再相机被遮挡实际发生前,进行预测。

       3:相机终点调整,使用最优碰撞点进行调整,调整算法考虑到相机视口宽度,使相视口机完全避免边界与碰撞点穿插。

       4:相机终点确认后,对相机进行平滑过渡动画的方式往目标点移动。

       5:平滑过渡速率和触摸拖动角度变化速率成正比,防止滑动太大穿墙,也增加体验。

    实现参考图:

    如下图,椎体为四条碰撞检测射线:

    穿墙后,相机进行调整以后的截图:

    实现效果:参考 万王之王,一样的效果。

    代码实现:代码中关键步骤已经有注释,核心函数是CameraMovement。

      1 using UnityEngine;
      2 using System.Collections;
      3 using System.Collections.Generic;
      4 using Invector;
      5 using System;
      6 public class vThirdPersonCamera : MonoBehaviour
      7 {
      8     public enum CameraState
      9     {
     10         Drag,
     11         Auto,
     12         AutoFixY,
     13     }
     14     public static vThirdPersonCamera Create()
     15     {
     16         var go = new GameObject("vThirdPersonCamera");
     17         vThirdPersonCamera comp = go.AddComponent<vThirdPersonCamera>();
     18         GameObject.DontDestroyOnLoad(go);
     19         return comp;
     20     }
     21     #region inspector properties
     22     [Tooltip("Lerp speed between Camera States")]
     23     public float smoothCameraRotation = 12f;
     24     public float smoothCameraRotationAuto = 1;
     25     private float m_currentCameraRotation;
     26     [Tooltip("What layer will be culled")]
     27     public LayerMask cullingLayer = 1 << 0;//碰撞检测用的layer,请根据自己游戏进行设置。
     28     public float rightOffset = 0f;
     29     public float defaultDistance = 12.5f;
     30     public float height = 2f; 
     31     private float defaultHeight = 2f;
     32     public float smoothFollow = 5f;
     33     public float cameraAutoRotationSensitivity = 3f;
     34     public float xMouseSensitivity = 0.2f;//3f;
     35     public float yMouseSensitivity = 0.2f;//3f;
     36     public float yMinLimit = -70;
     37     public float yMaxLimit = 80f;
     38     public const float MinDistance = 0f;
     39     public const float MaxDistance = 35;
     40     public float currentDistance = 0;
     41     public float zoomSensitivity = 0.05f;
     42     public Transform cameraTransform;
     43     //public Transform otherTargetTransform;//相机动画锁定目标Trans
     44     #endregion
     45     #region hide properties
     46     [HideInInspector]
     47     public float offSetPlayerPivot;
     48     //[HideInInspector]
     49     [HideInInspector]
     50     public Vector2 movementSpeed;
     51     private Vector3 currentPlayerPos;
     52     private Vector3 currentPlayerDirection;
     53     private Vector3 currentPlayerDirectionRight;
     54     private Transform targetLookAt;    //目标观察点
     55     private Transform nextTargetLookAt;//目标观察点
     56     private Vector3 currentTargetPos;
     57     private Vector3 lookPoint;
     58     private Vector3 nextLookPoint;
     59     private Vector3 current_cPos;
     60     private Vector3 desired_cPos;
     61     private Vector3 nextTargetCameraPos = Vector3.zero;
     62     private Vector3 nextCameraPos = Vector3.zero;
     63     private Camera _camera;
     64     private float distance = 0f;
     65     private float mouseY = 0f;
     66     private float mouseX = 0f;
     67     private float currentHeight;
     68     private float cullingDistance;
     69     //private float checkHeightRadius = 0.4f;
     70     private float clipPlaneMargin = 0f;
     71     private float forward = -1f;
     72     private float xMinLimit = -360f;
     73     private float xMaxLimit = 360f;
     74     private RaycastHit hitInfo;
     75     private float distanceTime = 0f;
     76     private float curSmoothFollow = 5f;
     77     private CameraState mState = CameraState.Drag;
     78     private float clipOffset = 1f;//相机视口区域射线检测区扩大
     79     public CameraState State
     80     {
     81         get
     82         {
     83             return mState;
     84         }
     85         set
     86         {
     87             if (value == mState)
     88                 return;
     89             mState = value;
     90             UpdateState();
     91         }
     92     }
     93     #endregion
     94     #region 相机基础功能函数区--------------------------------------------------------------------------------
     95     private void UpdateState()
     96     {
     97         switch (mState)
     98         {
     99             case CameraState.Auto:
    100                 m_currentCameraRotation = smoothCameraRotationAuto;
    101                 break;
    102             case CameraState.AutoFixY:
    103                 break;
    104             default:
    105                 m_currentCameraRotation = smoothCameraRotation;
    106                 break;
    107         }
    108     }
    109     public float GetMouseX()
    110     {
    111         return mouseX;
    112     }
    113     public float GetMouseY()
    114     {
    115         return mouseY;
    116     }
    117     public void SetRotateY(float targetX)
    118     {
    119         mouseX = targetX;
    120     }
    121     public void Release()
    122     {
    123         if (targetLookAt != null)
    124         {
    125             GameObject.Destroy(targetLookAt);
    126             targetLookAt = null;
    127         }
    128         if (nextTargetLookAt != null)
    129         {
    130             GameObject.Destroy(nextTargetLookAt);
    131             nextTargetLookAt = null;
    132         }
    133     }
    134     public void Init()
    135     {
    136         cullingLayer = 1 << (int)PublicConst.E_Layer.Layer_Road;
    137         currentTargetPos = new Vector3(currentPlayerPos.x, currentPlayerPos.y + offSetPlayerPivot, currentPlayerPos.z);
    138         if (targetLookAt == null)
    139         {
    140             targetLookAt = new GameObject("targetLookAt").transform;
    141             GameObject.DontDestroyOnLoad(targetLookAt);
    142         }
    143         if (nextTargetLookAt == null)
    144         {
    145             nextTargetLookAt = new GameObject("nextTargetLookAt").transform;
    146             GameObject.DontDestroyOnLoad(nextTargetLookAt);
    147         }
    148         targetLookAt.position = currentTargetPos;
    149         targetLookAt.rotation = Quaternion.Euler(mouseY, mouseX, 0);
    150         nextTargetLookAt.position = currentTargetPos;
    151         nextTargetLookAt.rotation = Quaternion.Euler(mouseY, mouseX, 0);
    152         defaultDistance = Mathf.Clamp(defaultDistance, MinDistance, MaxDistance);
    153         if (State == CameraState.AutoFixY)
    154         {
    155             currentDistance = distance = camera2DDistance;
    156         }
    157         else
    158         {
    159             currentDistance = distance = defaultDistance;
    160         }
    161         currentHeight = height;
    162         UpdateState();
    163     }
    164     public void SetCamera(Camera cam, Transform cameraRootTrans, int xRot, int yRot)
    165     {
    166         mouseY = xRot;
    167         mouseX = yRot;
    168         _camera = cam;
    169         cameraTransform = cameraRootTrans;
    170         Init();
    171     }
    172     /// <summary>
    173     /// 相机看向角色的高度值,目的是看向人脸
    174     /// 1:不同高度的角色,需要配置这个值
    175     /// 2:在坐骑上 高度 = 坐骑坐垫高度 + 角色高度*0.5
    176     /// </summary>
    177     /// <param name="_height">高度 (单位 米)</param>
    178     public void SetHeight(float pHeight)
    179     {
    180         if(pHeight <= 0)
    181         {
    182             LiteCommon.BLog.E("相机中角色高度设置错误! 值<=0!");
    183             height = defaultHeight;
    184             return;
    185         }
    186         height = pHeight;
    187     }
    188     /// <summary>
    189     /// 相机在lateUpdate中的持续更新
    190     /// </summary>
    191     public void UpdatePosition()
    192     {
    193         CameraMovement();
    194     }
    195     /// <summary>
    196     /// 持续缩进相机距离(触控滑动交互)
    197     /// </summary>
    198     /// <param name="delta"></param>
    199     public void UpdateZoomFactor(float delta)
    200     {
    201         currentDistance -= delta * zoomSensitivity;
    202         currentDistance = Mathf.Clamp(currentDistance, MinDistance, MaxDistance);
    203     }
    204     /// <summary>
    205     /// 持续旋转相机角度(触控滑动交互)
    206     /// </summary>
    207     /// <param name="delta"></param>
    208     public void UpdateRotate(Vector2 delta)
    209     {
    210         RotateCamera(delta.x, delta.y);
    211     }
    212     /// <summary>
    213     /// 设置相机到固定位置
    214     /// </summary>
    215     /// <param name="_fixedAngleX">水平角度</param>
    216     /// <param name="_fixedAngleY">垂直角度</param>
    217     /// <param name="distance">相机对目标位置距离</param>
    218     public void SetCameraPos(float _fixedAngleX, float _fixedAngleY, float distance)
    219     {
    220         mouseX = _fixedAngleX;
    221         mouseY = _fixedAngleY;
    222         currentDistance = distance;
    223     }
    224     /// <summary>
    225     /// 更新角色位置
    226     /// </summary>
    227     /// <param name="pos"></param>
    228     public void UpdateRolePosition(Vector3 pos)
    229     {
    230         currentPlayerPos = pos;
    231         if (isLookingToOtherTarget)
    232         {
    233             if (!isAutoLookingTargetSmooth && otherlookTarget != null)
    234             {
    235                 //Debug.Log("---->UpdateRolePosition otherlookTarget!");
    236                 currentTargetPos = otherlookTarget.position;
    237             }
    238         }
    239         else
    240         {
    241             currentTargetPos = currentPlayerPos;
    242         }
    243     }
    244     /// <summary>
    245     /// 跟新相机目标对象的方向
    246     /// </summary>
    247     /// <param name="directionForward"></param>
    248     public void UpdateRoleDirection(Vector3 directionForward)
    249     {
    250         currentPlayerDirection = directionForward;
    251         currentPlayerDirectionRight = Vector3.Cross(directionForward, Vector3.up);
    252     }
    253     /// <summary>
    254     /// Camera Update 实时刷新相机方位,并且避免碰撞
    255     /// </summary>    
    256     void CameraMovement()
    257     {
    258         if (_camera == null)
    259             return;
    260         //next position and direction
    261         //distance = Mathf.Lerp(distance, currentDistance, smoothFollow * Time.deltaTime);
    262         //cullingDistance = Mathf.Lerp(cullingDistance, distance, Time.deltaTime);
    263         var camDir = (forward * targetLookAt.forward);
    264         camDir.Normalize();
    265         var targetPos = new Vector3(currentTargetPos.x, currentTargetPos.y + offSetPlayerPivot, currentTargetPos.z);
    266         currentTargetPos = targetPos;
    267         //look direction
    268         lookPoint = desired_cPos + targetLookAt.forward * 2f;
    269         lookPoint += (targetLookAt.right * Vector3.Dot(camDir * (distance), targetLookAt.right));
    270         //set current real looking height p;osition
    271         currentHeight = height;
    272         desired_cPos = targetPos + new Vector3(0, height, 0);
    273         current_cPos = currentTargetPos + new Vector3(0, currentHeight, 0);
    274         //next look Target
    275         nextTargetLookAt.position = desired_cPos;
    276         Quaternion newNextRot = Quaternion.Euler(mouseY, mouseX, 0);
    277         nextTargetLookAt.rotation = newNextRot;
    278         //next camera direction
    279         var nextCamDir = (forward * nextTargetLookAt.forward);
    280         nextCamDir.Normalize();
    281         //next look direction
    282         nextLookPoint = desired_cPos + nextTargetLookAt.forward * 2f;
    283         nextLookPoint += (nextTargetLookAt.right * Vector3.Dot(nextCamDir * (currentDistance), nextTargetLookAt.right));
    284         nextCameraPos = desired_cPos + (nextCamDir * currentDistance);
    285         //calculate next ClipPlanePoints
    286         ClipPlanePoints nextPlanePoints = _camera.NearClipPlanePoints(nextCameraPos, clipPlaneMargin, clipOffset);
    287         //if hit not success, then next target camera pos --> current camera pos
    288         //else calculate next target camera pos
    289         if (CullingRayCast(desired_cPos, nextPlanePoints, out hitInfo, currentDistance, cullingLayer, Color.cyan))
    290         {
    291             ///处理相机缩进和穿墙
    292             Vector3 nextPlayerToHitVec = desired_cPos - hitInfo.point;
    293             //下一幀和当前帧的弧度,弧度大小可以用来衡量变化快慢,这个快慢将会用来调节缩进速率
    294             float angleRad = Mathf.PI / 2 - Mathf.Acos(Vector3.Dot((-nextPlayerToHitVec).normalized, hitInfo.normal));
    295             //换算相机侧翼宽度为相机到目标位置方向上的距离,用来避免相机侧翼太近导致的穿墙。
    296             //clipOffset * 0.9f 参数 0.9 使
    297             float length = Mathf.Abs((nextPlanePoints.width- clipOffset * 0.9f) / Mathf.Tan(angleRad));
    298             float hitLenth = nextPlayerToHitVec.magnitude;
    299             if (length > hitLenth)
    300             {
    301                 length = hitLenth;
    302             }
    303             ClipPlanePoints planePoints = _camera.NearClipPlanePoints(cameraTransform.position, clipPlaneMargin, 1f);
    304             //根据下一个相机位置的弧度,决定相机缩进动画的速率
    305             if (CullingViewRayCast(desired_cPos, planePoints, out hitInfo, distance + 0.2f, cullingLayer, Color.cyan))
    306             {
    307                 curSmoothFollow = smoothFollow * Mathf.Abs(angleRad) * 40f / Mathf.PI;
    308             }
    309             else
    310             {
    311                 curSmoothFollow = smoothFollow;
    312             }
    313             //调整相机位置,避免相机边缘发生穿墙
    314             Vector3 targetCameraVector = nextPlayerToHitVec - nextPlayerToHitVec.normalized * length;
    315             cullingDistance = targetCameraVector.magnitude;
    316             cullingDistance = Mathf.Clamp(cullingDistance, 0f, currentDistance);
    317             distance = Mathf.Lerp(distance, cullingDistance, curSmoothFollow * Time.deltaTime);
    318             distance = Mathf.Clamp(distance, MinDistance, MaxDistance);
    319             distanceTime += curSmoothFollow * Time.deltaTime;
    320             Vector3 camDirComp = Vector3.Lerp(camDir, nextCamDir, distanceTime);
    321             cameraTransform.position = desired_cPos + (camDirComp * distance);
    322             cameraTransform.rotation = Quaternion.LookRotation((desired_cPos) - cameraTransform.position);
    323         }
    324         else
    325         {
    326             distanceTime = 0;
    327             distance = Mathf.Lerp(distance, currentDistance, smoothFollow * Time.deltaTime);
    328             targetLookAt.position = desired_cPos;
    329             targetLookAt.rotation = Quaternion.Euler(mouseY, mouseX, 0);
    330             Vector3 desiredCameraPos = desired_cPos + (forward * targetLookAt.forward * distance);
    331             ClipPlanePoints planePoints = _camera.NearClipPlanePoints(desiredCameraPos, clipPlaneMargin, 1);
    332             if (!CullingViewRayCast(desired_cPos, planePoints, out hitInfo, distance + 0.2f, cullingLayer, Color.cyan))
    333             {
    334                 cameraTransform.position = desiredCameraPos;
    335                 cameraTransform.rotation = Quaternion.LookRotation((desired_cPos) - cameraTransform.position);
    336             }
    337         }
    338         Debug.DrawLine(desired_cPos, nextPlanePoints.LowerLeft, Color.red);
    339         Debug.DrawLine(desired_cPos, nextPlanePoints.LowerRight, Color.red);
    340         Debug.DrawLine(desired_cPos, nextPlanePoints.UpperRight, Color.red);
    341         Debug.DrawLine(desired_cPos, nextPlanePoints.UpperLeft, Color.red);
    342         Debug.DrawLine(nextTargetLookAt.position, nextTargetLookAt.position + nextTargetLookAt.forward, Color.blue);
    343         Debug.DrawLine(targetLookAt.position, targetLookAt.position + targetLookAt.forward, Color.green);
    344         movementSpeed = Vector2.zero;
    345     }
    346     /// <summary>
    347     /// 视口投射射线检测
    348     /// </summary>
    349     /// <param name="from">起点</param>
    350     /// <param name="_to">目标点</param>
    351     /// <param name="hitInfo">RaycastHit</param>
    352     /// <param name="distance">距离</param>
    353     /// <param name="cullingLayer">裁剪层</param>
    354     /// <param name="color">调试颜色</param>
    355     /// <returns></returns>
    356     bool CullingViewRayCast(Vector3 from, ClipPlanePoints _to, out RaycastHit hitInfo, float distance, LayerMask cullingLayer, Color color)
    357     {
    358         bool value = false;
    359         if (Physics.Raycast(from, _to.LowerRight - from, out hitInfo, distance, cullingLayer))
    360         {
    361             value = true;
    362         }
    363         else if (Physics.Raycast(from, _to.LowerLeft - from, out hitInfo, distance, cullingLayer))
    364         {
    365             value = true;
    366         }
    367         else if (Physics.Raycast(from, _to.UpperRight - from, out hitInfo, distance, cullingLayer))
    368         {
    369             value = true;
    370         }
    371         else if (Physics.Raycast(from, _to.UpperLeft - from, out hitInfo, distance, cullingLayer))
    372         {
    373             value = true;
    374         }
    375         return value;
    376     }
    377     /// <summary>
    378     ///获取最远点检测点离想几点最远位置进行检测
    379     ///判断相机在视口边缘坐标的最远点
    380     /// </summary>
    381     /// <param name="_to"></param>
    382     /// <param name="from"></param> 
    383     /// <param name="hitInfo"></param>
    384     /// <param name="distance"></param>
    385     /// <param name="cullingLayer"></param>
    386     /// <returns></returns>
    387     bool CullingRayCast(Vector3 from, ClipPlanePoints _to, out RaycastHit hitInfo, float distance, LayerMask cullingLayer, Color color)
    388     {
    389         bool value = false;
    390         RaycastHit curHitInfo;
    391         if (Physics.Raycast(from, _to.LowerRight - from, out hitInfo, distance, cullingLayer))
    392         {
    393             value = true;
    394         }
    395         if (Physics.Raycast(from, _to.LowerLeft - from, out curHitInfo, distance, cullingLayer))
    396         {
    397             if (value)
    398             {
    399                 if (hitInfo.distance > curHitInfo.distance)
    400                     hitInfo = curHitInfo;
    401             }
    402             else
    403             {
    404                 hitInfo = curHitInfo;
    405             }
    406             value = true;
    407         }
    408         if (Physics.Raycast(from, _to.UpperRight - from, out curHitInfo, distance, cullingLayer))
    409         {
    410             if (value)
    411             {
    412                 if (hitInfo.distance > curHitInfo.distance)
    413                     hitInfo = curHitInfo;
    414             }
    415             else
    416             {
    417                 hitInfo = curHitInfo;
    418             }
    419             value = true;
    420         }
    421         if (Physics.Raycast(from, _to.UpperLeft - from, out curHitInfo, distance, cullingLayer))
    422         {
    423             if (value)
    424             {
    425                 if (hitInfo.distance > curHitInfo.distance)
    426                     hitInfo = curHitInfo;
    427             }
    428             else
    429             {
    430                 hitInfo = curHitInfo;
    431             }
    432             value = true;
    433         }
    434         return value;
    435     }
    436     #endregion 相机基础功能区 End--------------------------------------------------------------------------------
    437 }
    438  
    439 //视口信息数据类
    440  public static class vExtensions
    441     {
    442         public static T[]  Append<T>(this T[] arrayInitial, T[] arrayToAppend) 
    443         {
    444             if (arrayToAppend == null)
    445             {
    446                 throw new ArgumentNullException("The appended object cannot be null");
    447             }
    448             if ((arrayInitial is string) || (arrayToAppend is string))
    449             {
    450                 throw new ArgumentException("The argument must be an enumerable");
    451             }
    452             T[] ret = new T[arrayInitial.Length + arrayToAppend.Length];
    453             arrayInitial.CopyTo(ret, 0);
    454             arrayToAppend.CopyTo(ret, arrayInitial.Length);
    455             return ret;
    456         }
    457         /// <summary>
    458         /// Normalized the angle. between -180 and 180 degrees
    459         /// </summary>
    460         /// <param Name="eulerAngle">Euler angle.</param>
    461         public static Vector3 NormalizeAngle(this Vector3 eulerAngle)
    462         {
    463             var delta = eulerAngle;
    464             if (delta.x > 180) delta.x -= 360;
    465             else if (delta.x < -180) delta.x += 360;
    466             if (delta.y > 180) delta.y -= 360;
    467             else if (delta.y < -180) delta.y += 360;
    468             if (delta.z > 180) delta.z -= 360;
    469             else if (delta.z < -180) delta.z += 360;
    470             return new Vector3(delta.x, delta.y, delta.z);//round values to angle;
    471         }
    472         public static Vector3 Difference(this Vector3 vector, Vector3 otherVector)
    473         {
    474             return otherVector - vector;
    475         }
    476         public static void SetActiveChildren(this GameObject gameObjet, bool value)
    477         {
    478             foreach (Transform child in gameObjet.transform)
    479                 child.gameObject.SetActive(value);
    480         }
    481         public static void SetLayerRecursively(this GameObject obj, int layer)
    482         {
    483             obj.layer = layer;
    484             foreach (Transform child in obj.transform)
    485             {
    486                 child.gameObject.SetLayerRecursively(layer);
    487             }
    488         }
    489         public static float ClampAngle(float angle, float min, float max)
    490         {
    491             do
    492             {
    493                 if (angle < -360)
    494                     angle += 360;
    495                 if (angle > 360)
    496                     angle -= 360;
    497             } while (angle < -360 || angle > 360);
    498             return Mathf.Clamp(angle, min, max);
    499         }      
    500         public static ClipPlanePoints NearClipPlanePoints(this Camera camera, Vector3 pos, float clipPlaneMargin, float clipOffset = 0f)
    501         {
    502             var clipPlanePoints = new ClipPlanePoints();
    503             clipPlanePoints.center = pos;
    504             var transform = camera.transform;
    505             var halfFOV = (camera.fieldOfView / 2) * Mathf.Deg2Rad;
    506             var aspect = camera.aspect;
    507             var distance = camera.nearClipPlane;
    508             var height = distance * Mathf.Tan(halfFOV);
    509             var width = height * aspect;
    510             height *= 1 + clipPlaneMargin;
    511             width *= 1 + clipPlaneMargin;
    512             clipPlanePoints.width = width * 2;
    513             clipPlanePoints.heigth = height * 2;
    514             height += clipOffset;
    515             width += clipOffset;
    516             clipPlanePoints.Right = pos + transform.right * width;
    517             clipPlanePoints.Left  = pos - transform.right * width;
    518             clipPlanePoints.Top   = pos + transform.up * height;
    519             clipPlanePoints.Lower = pos - transform.up * height;
    520             //todo:will delete
    521             clipPlanePoints.LowerRight = pos + transform.right * width;
    522             clipPlanePoints.LowerRight -= transform.up * height;
    523             clipPlanePoints.LowerRight += transform.forward * distance;
    524             clipPlanePoints.LowerLeft = pos - transform.right * width;
    525             clipPlanePoints.LowerLeft -= transform.up * height;
    526             clipPlanePoints.LowerLeft += transform.forward * distance;
    527             clipPlanePoints.UpperRight = pos + transform.right * width;
    528             clipPlanePoints.UpperRight += transform.up * height;
    529             clipPlanePoints.UpperRight += transform.forward * distance;
    530             clipPlanePoints.UpperLeft = pos - transform.right * width;
    531             clipPlanePoints.UpperLeft += transform.up * height;
    532             clipPlanePoints.UpperLeft += transform.forward * distance;
    533             return clipPlanePoints;
    534         }
    535       
    536         public static BoxPoint GetBoxPoint(this BoxCollider boxCollider)
    537         {
    538             BoxPoint bp = new BoxPoint();
    539             bp.center =  boxCollider.transform.TransformPoint(boxCollider.center)  ;          
    540             var height = boxCollider.transform.lossyScale.y * boxCollider.size.y;          
    541             var ray = new Ray(bp.center, boxCollider.transform.up);
    542            
    543             bp.top =    ray.GetPoint((height * 0.5f));
    544             bp.bottom = ray.GetPoint(-(height * 0.5f));
    545            
    546             return bp;
    547         }
    548         public static Vector3 BoxSize(this BoxCollider boxCollider)
    549         {
    550             var length = boxCollider.transform.lossyScale.x * boxCollider.size.x;
    551             var width = boxCollider.transform.lossyScale.z * boxCollider.size.z;
    552             var height = boxCollider.transform.lossyScale.y * boxCollider.size.y;
    553             return  new Vector3(length, height, width);
    554         }  
    555         public static bool Contains(this Enum keys, Enum flag)
    556         {
    557             if (keys.GetType() != flag.GetType())
    558                 throw new ArgumentException("Type Mismatch");
    559             return (Convert.ToUInt64(keys) & Convert.ToUInt64(flag)) != 0;
    560         }
    561        
    562     }
    563     public struct BoxPoint
    564     {
    565         public Vector3 top;
    566         public Vector3 center;
    567         public Vector3 bottom;
    568        
    569     }
    570     public struct ClipPlanePoints
    571     {
    572         public Vector3 UpperLeft;
    573         public Vector3 UpperRight;
    574         public Vector3 LowerLeft;
    575         public Vector3 LowerRight;
    576         public Vector3 center;
    577         public Vector3 Right;
    578         public Vector3 Left;
    579         public Vector3 Top;
    580         public Vector3 Lower;
    581         public float width;
    582         public float heigth;
    583     }
    584 }
     
  • 相关阅读:
    go语言学习之从例子开始
    分享一个不错的Unittest测试报告
    selenium各种定位方法(转)
    HTMLTESTRunner自动化测试报告增加截图功能
    selenium之chrome驱动版本
    Python基础(六) python生成xml测试报告
    vue+elementUI 表头按钮
    vue+elementUI滚动条
    vue表格表头添加按钮
    elementUI升级版本后Dialog弹空不显示问题
  • 原文地址:https://www.cnblogs.com/hengsoft/p/10230911.html
Copyright © 2020-2023  润新知