【原】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 }

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM