zoukankan      html  css  js  c++  java
  • Unity中无GC Alloc的CalculateFrustumPlanes

          如果你需要在逻辑层做一些预先的剔除操作,可能需要从MainCamera构建视锥体,然后进行简易相交测试,这时候在unity里面用到的函数接口是CalculateFrustumPlanes:

     1 namespace UnityEngine
     2 {
     3     // 摘要: 
     4     //     Utility class for common geometric functions.
     5     public sealed class GeometryUtility
     6     {
     7         public GeometryUtility();
     8 
     9         // 摘要: 
    10         //     Calculates frustum planes.
    11         public static Plane[] CalculateFrustumPlanes(Camera camera);
    12         //
    13         // 摘要: 
    14         //     Calculates frustum planes.
    15         public static Plane[] CalculateFrustumPlanes(Matrix4x4 worldToProjectionMatrix);
    16         //
    17         // 摘要: 
    18         //     Returns true if bounds are inside the plane array.
    19         public static bool TestPlanesAABB(Plane[] planes, Bounds bounds);
    20     }
    21 }

          然而它的主要问题是有gc alloc,每次调用都会自己new一个Plane数组,这很明显是不科学的,然而unity迟迟未修复此问题。

         下面提供的函数在C#层中重新实现了这个接口,同时没有gcalloc,然而由于在C#中实现的原因,其效率比引擎提供的C++版本慢一倍。C#版本实测一次调用在0.01毫秒左右。所以使用哪一个版本,根据实际需求来是最好的。

      C#版本的实现:

     1 public static class GeometryUtilityUser
     2 {
     3     /**
     4      * @warning OutPlanes must be new Plane[6]
     5      *    Plane Position :
     6      *       Left
     7      *       Right
     8      *       Bottom
     9      *       Top
    10      *       Near
    11      *       Far
    12     */
    13     enum EPlaneSide
    14     {
    15         Left,
    16         Right,
    17         Bottom,
    18         Top,
    19         Near,
    20         Far
    21     }
    22 
    23     static float[] RootVector = new float[4];
    24     static float[] ComVector = new float[4];
    25 
    26     public static void CalculateFrustumPlanes(Camera InCamera, ref Plane[] OutPlanes)
    27     {
    28         Matrix4x4 projectionMatrix = InCamera.projectionMatrix;
    29         Matrix4x4 worldToCameraMatrix = InCamera.worldToCameraMatrix;
    30         Matrix4x4 worldToProjectionMatrix = projectionMatrix * worldToCameraMatrix;
    31 
    32         RootVector[0] = worldToProjectionMatrix[3, 0];
    33         RootVector[1] = worldToProjectionMatrix[3, 1];
    34         RootVector[2] = worldToProjectionMatrix[3, 2];
    35         RootVector[3] = worldToProjectionMatrix[3, 3];
    36 
    37         ComVector[0] = worldToProjectionMatrix[0, 0];
    38         ComVector[1] = worldToProjectionMatrix[0, 1];
    39         ComVector[2] = worldToProjectionMatrix[0, 2];
    40         ComVector[3] = worldToProjectionMatrix[0, 3];
    41 
    42         CalcPlane(ref OutPlanes[(int)EPlaneSide.Left], ComVector[0] + RootVector[0], ComVector[1] + RootVector[1], ComVector[2] + RootVector[2], ComVector[3] + RootVector[3]);
    43         CalcPlane(ref OutPlanes[(int)EPlaneSide.Right], -ComVector[0] + RootVector[0], -ComVector[1] + RootVector[1], -ComVector[2] + RootVector[2], -ComVector[3] + RootVector[3]);
    44 
    45         ComVector[0] = worldToProjectionMatrix[1, 0];
    46         ComVector[1] = worldToProjectionMatrix[1, 1];
    47         ComVector[2] = worldToProjectionMatrix[1, 2];
    48         ComVector[3] = worldToProjectionMatrix[1, 3];
    49 
    50         CalcPlane(ref OutPlanes[(int)EPlaneSide.Bottom], ComVector[0] + RootVector[0], ComVector[1] + RootVector[1], ComVector[2] + RootVector[2], ComVector[3] + RootVector[3]);
    51         CalcPlane(ref OutPlanes[(int)EPlaneSide.Top], -ComVector[0] + RootVector[0], -ComVector[1] + RootVector[1], -ComVector[2] + RootVector[2], -ComVector[3] + RootVector[3]);
    52 
    53         ComVector[0] = worldToProjectionMatrix[2, 0];
    54         ComVector[1] = worldToProjectionMatrix[2, 1];
    55         ComVector[2] = worldToProjectionMatrix[2, 2];
    56         ComVector[3] = worldToProjectionMatrix[2, 3];
    57 
    58         CalcPlane(ref OutPlanes[(int)EPlaneSide.Near], ComVector[0] + RootVector[0], ComVector[1] + RootVector[1], ComVector[2] + RootVector[2], ComVector[3] + RootVector[3]);
    59         CalcPlane(ref OutPlanes[(int)EPlaneSide.Far], -ComVector[0] + RootVector[0], -ComVector[1] + RootVector[1], -ComVector[2] + RootVector[2], -ComVector[3] + RootVector[3]);
    60 
    61     }
    62 
    63     static void CalcPlane(ref Plane InPlane, float InA, float InB, float InC, float InDistance)
    64     {
    65         Vector3 Normal = new Vector3(InA, InB, InC);
    66 
    67         float InverseMagnitude = 1.0f / (float)System.Math.Sqrt(Normal.x * Normal.x + Normal.y * Normal.y + Normal.z * Normal.z);
    68 
    69         InPlane.normal = new Vector3(Normal.x * InverseMagnitude, Normal.y * InverseMagnitude, Normal.z * InverseMagnitude);
    70 
    71         InPlane.distance = InDistance * InverseMagnitude;
    72     }
    73 }

          下面的代码可用于验证其正确性:

     1 private Plane[] CalcFrustum(Camera InCamera)
     2     {
     3         GeometryUtilityUser.CalculateFrustumPlanes(InCamera, ref CachedPlanes);
     4 #if UNITY_EDITOR && false
     5         Plane[] SysPlanes = GeometryUtility.CalculateFrustumPlanes(InCamera);
     6         for (int i = 0; i < SysPlanes.Length; ++i )
     7         {
     8             if( !IsEqual(SysPlanes[i], CachedPlanes[i]) )
     9             {
    10                 DebugHelper.Assert(false, "Internal error in CalcFrustum");
    11             }
    12         }
    13 #endif
    14             return CachedPlanes;
    15     }
    16     private static bool IsEqual(Plane InFirst, Plane InSecond)
    17     {
    18         return IsEqual(InFirst.normal, InSecond.normal) &&
    19             IsEqual(InFirst.distance, InSecond.distance);
    20     }
    21     private static bool IsEqual(Vector3 InFirst, Vector3 InSecond)
    22     {
    23         return IsEqual(InFirst.x, InSecond.x) &&
    24             IsEqual(InFirst.y, InSecond.y) &&
    25             IsEqual(InFirst.y, InSecond.y);
    26     }
    27     private static bool IsEqual(float InFirst, float InSecond)
    28     {
    29         return System.Math.Abs(InFirst - InSecond) < 0.001f;
    30     }
    31     private Plane[] CachedPlanes = new Plane[6];
  • 相关阅读:
    POI实现Excel导入导出
    2017春季_京东_Java后端研发岗面经
    java中的IO流和多线程
    Java静态代理&动态代理&Cglib代理详解
    Java8新特性——stream流
    Java8新特性——接口默认方法
    Java8新特性——lambda函数式编程
    难题解决:Mycat数据库中间件+Mybatis批量插入数据并返回行记录的所有主键ID
    物料导出FreeMaker模板定义
    Mysql的MyISAM和InnoDB存储引擎的区别
  • 原文地址:https://www.cnblogs.com/bodong/p/4800018.html
Copyright © 2011-2022 走看看