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];
时间: 2024-10-25 04:18:17

Unity中无GC Alloc的CalculateFrustumPlanes的相关文章

Unity中的GC以及优化

[简介] 常见的 Unity GC 知识点总结出来的思维导图 Unity 官方文档,正巧在博客园发现了已经有位大神(zblade)把原文翻译出来了,而且质量很高~,译文地址 在这里.下面我就可耻地把译文搬运了过来,作为上面思维导图的知识点补充. [介绍] 在游戏运行的时候,数据主要存储在内存中,当游戏的数据不在需要的时候,存储当前数据的内存就可以被回收再次使用.内存垃圾是指当前废弃数据所占用的内存,垃圾回收(GC)是指将废弃的内存重新回收再次使用的过程. Unity中将垃圾回收当作内存管理的一部

Unity优化之GC——合理优化Unity的GC

最近有点繁忙,白天干活晚上抽空写点翻译,还要运动,所以翻译工作进行的有点缓慢 =.= 本文续接前面的unity的渲染优化,进一步翻译Unity中的GC优化,英文链接在下:英文地址 介绍: 在游戏运行的时候,数据主要存储在内存中,当游戏的数据不在需要的时候,存储当前数据的内存就可以被回收再次使用.内存垃圾是指当前废弃数据所占用的内存,垃圾回收(GC)是指将废弃的内存重新回收再次使用的过程. Unity中将垃圾回收当作内存管理的一部分,如果游戏中垃圾回收十分复杂,则游戏的性能会受到极大影响,此时垃圾

Unity优化之GC——合理优化Unity的GC (难度3 推荐5)

原文链接:http://www.cnblogs.com/zblade/p/6445578.html 最近有点繁忙,白天干活晚上抽空写点翻译,还要运动,所以翻译工作进行的有点缓慢 =.= 本文续接前面的unity的渲染优化,进一步翻译Unity中的GC优化,英文链接在下:英文地址 介绍: 在游戏运行的时候,数据主要存储在内存中,当游戏的数据不在需要的时候,存储当前数据的内存就可以被回收再次使用.内存垃圾是指当前废弃数据所占用的内存,垃圾回收(GC)是指将废弃的内存重新回收再次使用的过程. Unit

C#可空类型的速度和GC Alloc测试

在Unity中进行速度和GC Alloc的测试 测试脚本: using UnityEngine; using System; using System.Collections; using System.Diagnostics; public class NullableTest : MonoBehaviour { void Start() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i

Unity3D游戏GC优化总结---protobuf-net无GC版本优化实践

protobuf-net优化效果图 protobuf-net是Unity3D游戏开发中被广泛使用的Google Protocol Buffer库的c#版本,之所以c#版本被广泛使用,是因为c++版本的源代码不支持Unity3D游戏在各个平台上的动态库构建.它是一个网络传输层协议,对应的lua版本有两个可用的库:一个是proto-gen-lua,由tolua作者开发,另外一个是protoc,由云风开发.protobuf-net在GC上有很大的问题,在一个高频率网络通讯的状态同步游戏中使用发现GC过

关于Unity中的NGUI和UGUI

用Unity开发2D游戏,有三套关系 1.GUI:Unity本身的对象 2.NGUI:以前在Unity中广泛来做2D的,是第三方的包,需要安装 3.UGUI:Unity5.X后,Unity找到NGUI的作者,开发了UGUI,变成内置于Unity中的包,官方主推 所有的元素都在Unity的UI工具栏 3D做2D游戏的方法: 1: 使用正交摄像机;2: 使用透视摄像机,将2D元素移动到合适的距离. 例如设计分辨率为 960x640, 得到在3D世界里面一个图片的大小w*h米,将这个图片移动到一定的距

Unity中使用协程进行服务端数据验证手段

近期在做项目中的个人中心的一些事情,用户头像上传,下载,本地缓存,二级缓存,压缩,这些都要做,麻雀虽小五脏俱全啊,也是写的浑浑噩噩的, 当我们在上传用户头像的时候,向服务端发送上传头像请求之前,一般都会做一次验证,向服务端获取token验证信息,来确保非法上传,如果不做这个那么会有非法用户上传非法图像,使你的服务器 带来未知的灾难. 而验证的逻辑很好写,并没有什么难度,比如: Server.SendMessage("获取token"); Client.Receive(string to

菜鸟学习 - Unity中的热更新 - Lua和C#通信

孙广东 2015-4-6 热更新我是个菜鸟,感谢网上的各位的奉献,这次又当一回搬运工. 准备: 1.了解Lua的语法 推荐书籍<Lua程序设计 第二版> 2.使用ULua插件进行通信 尽量早上真机.因为Bug问题特别多. 大杂烩: 更新LUa其实也是更新资源. Lua被看作一个资源么.Lua代码都是运行时才编译的,不运行的时候就如同一张图片.一段音频一样,都是文件资源:所以更新逻辑只需要更新脚本,不需要再编译,因而Lua能轻松实现"热更新".运行效率由于使用反射,所以成为它

【Unity编程】Unity中关于四元数的API详解

Unity中关于四元数的API详解 Quaternion类 Quaternion(四元数)用于计算Unity旋转.它们计算紧凑高效,不受万向节锁的困扰,并且可以很方便快速地进行球面插值. Unity内部使用四元数来表示所有的旋转. Quaternion是基于复数,并不容易直观地理解. 不过你几乎不需要访问或修改单个四元数参数(x,y,z,w); 大多数情况下,你只需要获取和使用现有的旋转(例如来自"Transform"),或者用四元数来构造新的旋转(例如,在两次旋转之间平滑插入). 大