IsAlive

U3D的粒子系统脚本接口相信很多人都用过,ParticleSyetem类的一系列接口都有一个bool类型的参数——withChildren,通过这个参数可以直接将相同的判断或者操作应用到一整个通过Transform父子关系树关联起来的ParticleSystem实例集合上。然而,但凡方便的功能,里面就必然有性能陷阱……
以IsAlive这个接口为例(用来判断粒子系统是否所有粒子都已经消亡,一般用在非loop的例子发射器上),看看U3D里是如何实现这个接口的:

public bool IsAlive()
{
bool withChildren = true;
return this.IsAlive(withChildren);
}
public bool IsAlive(bool withChildren)
{
if (withChildren)
{
ParticleSystem[] particleSystems = ParticleSystem.GetParticleSystems(this);
ParticleSystem[] array = particleSystems;
for (int i = 0; i < array.Length; i++)
{
ParticleSystem particleSystem = array[i];
if (particleSystem.Internal_IsAlive())
{
return true;
}
}
return false;
}
return this.Internal_IsAlive();
}

可以看到,如果传递的withChildren参数为true,那么函数会先尝试调用GetParticleSystems(this)来获取包括下级gameObject在内的所有能找得到的粒子系统组件,然后对这些粒子系统组件依次再调用IsAlive判断。而如果withChildren为false,就仅仅会判断自身。那么自然,开销大小与否,关键就在GetParticleSystems的实现上了。


internal static ParticleSystem[] GetParticleSystems(ParticleSystem root)
{
if (!root)
{
return null;
}
List<ParticleSystem> list = new List<ParticleSystem>();
list.Add(root);
ParticleSystem.GetDirectParticleSystemChildrenRecursive(root.transform, list);
return list.ToArray();
}
private static void GetDirectParticleSystemChildrenRecursive(Transform transform, List<ParticleSystem> particleSystems)
{
foreach (Transform transform2 in transform)
{
ParticleSystem component = transform2.gameObject.GetComponent<ParticleSystem>();
if (component != null)
{
particleSystems.Add(component);
ParticleSystem.GetDirectParticleSystemChildrenRecursive(transform2, particleSystems);
}
}
}

U3D对获取所有下级gameObject实例上的粒子系统组件使用了递归的方式,并在递归结束后返回结果列表时做了一次列表元素复制(List.ToArray()),并且在获取粒子系统组件的时候用的是transform2.gameObject.GetComponent<ParticleSystem>(),而不是transform2.GetComponent<ParticleSystem>(),从上一篇文章里我们已经用实验证实了,前一种方式开销更大。看到这里,我们心里大概已经有谱了,那就是——效率绝对不会高到哪里去,影响性能的地方太多了……还是设计一个小实验来看看这种情况下应该用什么样的方式更好吧:


设计实验——一个两层结构,一个父gameObject挂载一个ParticleSystem组件,两个子gameObject分别挂载一个PariticleSystem组件,采用两种不同的方式对这个组合判断IsAlive各8×1024×1024次。
方案一,直接对父gameObject上的PariticleSystem调用IsAlive(true);
方案二,在循环前,先用GetComponentsInChildren将所有的PariticleSystem存入一个List,循环中对这个List做遍历,对List里每一个ParticleSystem调用IsAlive(false);
实验结果——方案一约3900ms,方案二约65ms。

结果对比很明显。其实,U3D提供的这个接口的意义在于,当不是需要进行那么频繁的调用时,可以用IsAlive(true)来省掉手动获取所有子粒子系统的过程,让代码简洁一些,虽然U3D目前对这个接口的实现有的地方还值得斟酌。ParticleSystem提供的这一族接口(IsAlive只是其中之一,此外还有Play,Pause,Stop等等),如果使用频率不是很高,比如仅仅是初始化或者销毁的时候做一次性调用,那么即便是withChildren参数是true也没有什么大不了的,还能少些很多代码,何乐而不为;但如果需要频繁调用,比如每帧都对粒子系统集合判断IsAlive,这种情况下,一定不能懒惰,该写的东西还是要写的。另外值得注意的一点,IsAlive这一族接口的无参形式,是默认withChildren为true的,使用的时候可别搞错了。

PS,留意一下GetDirectParticleSystemRecursive的实现方式,你会发现它有一个递归条件,就是节点上必须要有PariticleSystem组件,在递归过程中,一旦发现某个节点上没有ParticleSystem组件时,父子关系树上的这一枝就算遍历到头了,再往下即便是还有ParticleSystem存在也会被忽略。因此,如果你面对的ParticleSystem集合就恰好存在这样的断层,那最好还是自己勤快一点,自己动手用GetComonentsInChildren来查找所有的粒子系统组件。

[Unity 3D] Unity 3D 性能优化(二)的更多相关文章

  1. EMW 性能优化二之---并发配置

    EMW 性能优化二之---并发配置 在前一个日志中写到交货的异步更新,对于RFUI RF的前台操作会提升效率,异步更新不用等待更新状态的返回,启用更新队列的方式执行(SM13). 下面再补全性能相关的 ...

  2. MySQL性能优化(二):优化数据库的设计

    原文:MySQL性能优化(二):优化数据库的设计 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.n ...

  3. Unity技术支持团队性能优化经验分享

    https://mp.weixin.qq.com/s?__biz=MzU5MjQ1NTEwOA==&mid=2247490321&idx=1&sn=f9f34407ee5c5d ...

  4. 【Unity游戏开发】性能优化之在真机上开启DeepProfile与踩坑

    一.引子 最近马三入职了新公司,平时除了负责编辑器开发之外还要做一些游戏性能优化方面的工作.在这里首先给大家安利一下Unity官方的性能测试分析工具URP ,这个工具目前是免费,测试的过程中也不需要接 ...

  5. Spark性能优化(二)

    资源调优 调优概述 在开发完Spark作业之后,就该为作业配置合适的资源了.Spark的资源参数,基本都可以在spark-submit命令中作为参数设置.很多Spark初学者,通常不知道该设置哪些必要 ...

  6. mysql性能优化(二)

    ###> mysql中有一个explain 命令可以用来分析select 语句的运行效果,例如explain可以获得select语句使用的索引情况.排序的情况等等.除此以外,explain 的e ...

  7. Tomcat性能优化(二) ExpiresFilter设置浏览器缓存

    Tomcat性能调优 通过ExpiresFilter设置资源缓存 [官方文档] http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#E ...

  8. Tomcat性能优化(二) 启动参数设置

    一.tomcat绿色版设置方法 进入tomcat/bin目录下,找到catalina.bat文件在文件首行中插入下面这段配置即可. set JAVA_OPTS=-server -Djava.awt.h ...

  9. Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译

    本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

  10. Unity性能优化(3)-官方教程Optimizing garbage collection in Unity games翻译

    本文是Unity官方教程,性能优化系列的第三篇<Optimizing garbage collection in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

随机推荐

  1. asp.net 连接access数据库方法

    在 Web.Config 中配置 Access 数据库驱动和数据库文件名称. 请看代码 <appSettings> <add key="DBDriver" val ...

  2. POJ 2253 Frogger floyd算法

    题目:click here 题意: 给出两只青蛙的坐标A.B,和其他的n-2个坐标,任意两坐标间是双向连通的.显然从A到B存在至少一条的通路,每一条通路的元素都是这条通路中前后两个点的距离,这些距离中 ...

  3. 27_Blog Reader

    这个App是用来读取 Official Google Blog 的内容,然后显示出来. 用了新建工程时用了 Master-Detail Application 这个模板.用了Core Data用来存储 ...

  4. SQL中采用Newtonsoft.Json处理json字符串

    原文 SQL中采用Newtonsoft.Json处理json字符串 使用环境: SQL Server2005; VS2010; 关于SQL中部署CLR程序集的方法,网上一搜一大把,需要了解的自行查阅, ...

  5. ThinkPHP 3.1.2 视图-2

    一.模板的使用 (重点) a.规则 模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和模块名同名的文件夹[Index]/和方法名同名的文件[index].html(.tpl) 更换模板文件 ...

  6. libcurl post上传文件

    #include <stdio.h>#include <string.h> #include <curl/curl.h> int main(int argc, ch ...

  7. 2014年去哪儿网笔试题--有两个文件context.txt和words.conf,请尝试将他们合并成为一段文字,并打印出来。

    有两个文件context.txt和words.conf,请尝试将他们合并成为一段文字,并打印出来. 这两个文件内容如下: context.txt “并不是每个人都需要$(qunar)自己的粮食,$(f ...

  8. C#实现的内存分页机制的一个实例

    C#实现的内存分页机制的一个实例 //多页索引表管理类(全局主索引表管理类) public class MuliPageIndexFeatureClass : IDisposable { protec ...

  9. JavaScript推断E-mail地址是否合法

    编写自己定义的JavaScript函数checkEmail(),在该函数中首先推断E-mail文本框是否为空,然后在应用正則表達式推断E-mail地址是否合法,假设不合法提示用户 <script ...

  10. 怎样在SharePoint管理中心检查数据库架构版本号、修补级别和修补程序的常规监控

    怎样在SharePoint管理中心检查数据库架构版本号.修补级别和修补程序的常规监控 准备: 确保你是可以訪问管理中心的场管理员. 開始: 1. 打开管理中心--升级和迁移. 2. 点击"查 ...