动画骨骼节点批处理

栏目: 后端 · 发布时间: 6年前

内容简介:这是第140篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员)

这是第140篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com

UWA QQ群2:793972859(原群已满员)

本期目录:

  • 动画骨骼节点批处理
  • 粒子系统崩溃
  • 自定义Shader在iOS上出现异常
  • Editor里可以达到100帧,真机上FPS一直低于30帧
  • 多语言下Text组件大小和文本长度的适配

动画

Q:动画系统中开启Optimize GameObject选项后,不必要的骨骼会消失,我们在骨骼下面挂了很多特效挂点,也清楚可以通过 Extra Transforms to Expose暴露出挂点,但是每个模型去手选暴露太过麻烦,能否有批量处理的方法呢?

A1:这个可以通过Asset Postprocessor在导入的时候对模型进行遍历,将符合指定前缀的节点路径加入到Model Importer的Extra Exposed Transform Paths属性里,之后再调用Optimize Transform Hierarchy去实现优化节点的效果,不知道我有没有理解错。

感谢Enak@UWA问答社区提供了回答

UWA:补充楼上,如果是已知确定的节点名字,可以直接赋值,总之都是用OnPreprocessModel,具体规则自己项目组里约定好就好了。

public static string[] NodeNames = new string[]
{
    "node_head",
    "node_arm",  
    "node_leg", 
};

void OnPreprocessModel()
{
    ModelImporter importer = assetImporter as ModelImporter;
    importer.optimizeGameObjects = true;
    //若实际骨骼中没有以下节点,可能会报错,但不影响使用
    importer.extraExposedTransformPaths = EWEquipmentsBase.nodeNames;
}

A3:楼上两个回答都有效,但还有一个更简单的办法。

先说一下Extra Transforms to Expose的大概原理(不一定都对),观察UnityEditor.dll相关实现可知:

1)开发者修改ExtraTransformstoExpose后,Unity会将信息保存在fbx的meta文件的extraExposedTransformPaths属性中。

2)在Unity根据fbx文件生成Prefab时,会依据meta文件中的extraExposedTransformPaths每一个String创建一个对应名字的空GameObject,并且不需考虑父子关系。

3)运行时,(推测)Prefab被Instantiate后,其Animator组件Awake时触发了Animator.Rebind方法,该方法会遍历Transform的子节点,将子节点的name和Avatar中骨骼信息对比,随后自动绑定节点。

这也是Optimized之后Animator组件上必须有Avatar的原因(非Optimized的GameObject可以将Animator组件的Avatar引用置空),想进一步研究Avatar可以将Inspector改为Debug模式查看。

基于以上分析,我们可以模仿这一过程,直接在Optimized之后的Prefab下面创建空的GameObject,随后将该空GameObject的名字改成约定好的骨骼挂点名字,这样就实现了和ExtraExposedTransformPaths相同的功能。

更进一步,我们可以利用Animator.Rebind方法实现运行时动态添加删除挂点的功能。这样做的好处是一来特效和策划同学无需反复修改Prefab(当然也可以离线制作好);二是无需为Prefab绑定所有的挂点,只需创建配置表里实际用到的挂点,甚至可以把挂点GameObject放入对象池回收利用,角色比较多且默认挂点比较多的情况下可以起到优化内存的作用。缺点就是Animator.Rebind耗时比较大,可以考虑随着Instantiate调用。

动态绑定挂点示例:

1private static readonly string[] s_BindPoints = new string[]
 2{
 3    "node_head",
 4    "node_arm",
 5    "node_leg",
 6};
 7
 8private Animator m_Animator = null;
 9private void Awake()
10{
11    m_Animator = GetComponent<Animator>();
12    Assert.IsNotNull(m_Animator);
13    foreach (var bindPoint in s_BindPoints)
14    {
15        GameObject bindPointObj = new GameObject(bindPoint);
16        bindPointObj.layer = gameObject.layer;
17        bindPointObj.transform.SetParent(transform);
18    }
19    m_Animator.Rebind();    // important!
20}

感谢张迪@UWA问答社区分享了该经验

该问答来自UWA问答社区,欢迎大家转至社区交流:

https://answer.uwa4d.com/question/5c0a256a28c4e32cba3192eb

崩溃

Q:求助一个低概率随机崩溃问题,下面是崩溃的堆栈信息,我在网上搜索了下 “Abort message: ‘* Assertion at mini-arm.c:2634, condition `pdata.found == 1’ not met” 有人提到是与DLL相关,Android平台上应该是与本地的native code代码相关(当前项目使用了liblua53.so和其他 lua 相关的.so库),看了下mini-arm.c的源码,的确是在处理 mono_code_manager 相关一些东西,不知道有哪位大神遇见过并解决了的,请不吝赐教!

动画骨骼节点批处理

题主:上周我们项目进行了7天外网小规模(2000左右玩家)测试,在这期间面对的崩溃问题的处理过程和问题原因,仍旧比较深刻。

之前,崩溃在libmono.so “Abort message: Assertion at mini-arm.c:2634, condition `pdata.found == 1’ not met” 的这个低概率随机崩溃问题一直困扰着我,主要是这个问题崩溃在mono,崩溃的栈信息完全与libunity.so,libmain.so无关,更别说基于Unity的逻辑层代码,面对我们的对外测试11月30号时间临近,我在28号的时候对mono进行一次简单的处理:将mono代码mini-arm.c:2634 中的断言 g_assert (pdata.found == 1); 注释掉,换成了普通的错误信息输出,编译后直接提交到项目工程中,毕竟这个改动算是无害处理,然后开始去优化项目中卡顿点去了,也没有继续跟踪这个改动,因为当时想到是小概率事件。

11月29号提交给发行版本后,晚上发行反馈说,感觉这个版本的崩溃率有点高,但说没有实际统计过,得到这个反馈后,我也没有特别在意,继续处理其他问题去了(真后悔当时没有去看bugly)

11月30号中午正式开测,到下午4-5点后,部分同事反馈告诉我说,崩溃率有点高,平时测试都不会闪退,今天闪退2-3次了…其中一个同事告诉我说,挂机15分钟内必崩溃…当时听到这个问题后心里一紧,赶紧去看了下bugly,发现崩溃率到了7.x%,远高于平时我们测试2.x%的统计,我再仔细一看,都集中在各种粒子系统崩溃中:

动画骨骼节点批处理 动画骨骼节点批处理 动画骨骼节点批处理

看到这些崩溃后,回忆了下最近两天的优化,在优化卡顿的问题中,当时对粒子系统组件 ParticleSystem 进行了本地引用缓存,不需要每次播放技能特效时都进行一次GetGetComponentsInChildren(true),同时对技能特效粒子系统停止时调用stop()修改为pause()(技能特效播放完后就回收到pool中,所以调用pause()不会有残留,此时不需要释放数据,在切换场景时真正释放特效数据),这时我从崩溃栈看到信息首先想到的修改应该是stop()修改pause造成的崩溃,我让程序同学帮我在iOS上挂机复现这个问题,果然连续2次挂机打怪都复现了,8-12分钟内必崩,崩溃栈和bugly上统计一样。

动画骨骼节点批处理

这时我立刻开始在iOS上直接修改编译测试,将pause()还原为stop(),继续测试… 意外的是问题依然存在,15分钟内挂机必崩溃闪退,然后又思考了下,stop()只是停止当前粒子更新和粒子发射,但数据没有清,然后继续修改代码:stop()调用后,立刻调用clear()再次测试,郁闷的是仍旧15分钟内挂机必闪退崩溃…再仔细看了下播放特效的代码上下逻辑处理,找不出问题,平时的崩溃率绝对没有这么高,仔细回想了下,这2天还剩余唯一的改动就是添加了对 ParticleSystem本地引用缓存,于是直接在iOS上修改为播放完后立刻本地引用置空,编译,更新到真机测试…一直测试了30多分钟,40多分钟都没有再闪退崩溃,哪怕改回pause()调用,也没有再崩溃了…这个测试结果有点让我意外,当时没有细想,立刻正式修改热更新到外网…果然外网的崩溃率第二天的记录再下降,但仍然存在,但我心里已经知道问题了,因为还剩余UI特效播放未处理(技能特效和UI特效我们是划分开的,技能有高低配设置,初始化解析不同),同样修改UI特效之后,闪退崩溃几率继续下降,一直降低到1-2%,剩余的崩溃仍旧是UI粒子系统相关的,主要是部分UI功能业务层未主动调用回收特效的接口导致。

这次对外测试结束后,我再回头看看崩溃信息,意外地发现让我最头痛的mono崩溃数据终止在28号,也就是在我28号修改mono代码之后就再也没有报崩溃在libmono.so “Abort message: ‘* Assertion at mini-arm.c:2634, condition `pdata.found == 1’ not met” 这个堆栈数据,回忆了下,以前低概率崩溃本质就是UI粒子系统导致的,有部分业务层逻辑未主动调用释放接口的,而mono-arm.c崩溃行 g_assert (pdata.found == 1) 断言阻断了继续向上层抛出堆栈信息…

我们的Unity版本是5.6.5P4,为什么缓存粒子系统组件不立刻释放会导致崩溃未知,可能是Unity的底层Bug,也可能真的是我们对粒子系统组件ParticleSystem逻辑上下调用有问题。

感谢yangyonggen@UWA问答社区分享了该经验,欢迎大家转至社区交流: https://answer.uwa4d.com/question/5becf477a1dae055a7c051b7

Shader

Q:自定义Shader在安卓手机上正常,在iOS上出现异常, 伴随一大堆的警告,而且资源会都变成黑色。

动画骨骼节点批处理

A1:第一行提示不完整,应该是说是没有顶点Shader;

第二行提示Pass都被移除了;

第三行提示没有可用的Subshaders或者Fallbacks;

总结起来,就是Shader是个空Shader,不可用。所以进行了替换,表现就是黑色,而不是材质丢失。

没用过ShaderForge,但是看过几眼美术同学从ShaderForge导出来的Shader,包含有关于平台的编译选项,大概是编译选项不对,要检查下ShaderForge编译选项设置。

感谢赵林@UWA问答社区提供了回答

A2:首先切换到iOS平台,选择出错的Shader,有可能会显示Shader is not supported on this GPU,点击Compile and Show Code,应该会显示“Compile errors generating this shader.”

如果是这样的话,说明你用了Graphics API不支持的Feature。

感谢凯奥斯@UWA问答社区提供了回答
该问答来自UWA问答社区,欢迎大家转至社区交流: https://answer.uwa4d.com/question/5c07c21b28c4e32cba3192b8

帧率

Q:最近跑一个项目,在真机上无法超过30帧,看了耗时是只是十几毫秒。代码里没有对Application.targetframerate的限制。是什么原因呢?

可能是开了垂直同步限帧30帧那一档,垂直同步修改为60帧那一个,或者关闭垂直同步,用Application.targetframerate自己限帧。

感谢赵林@UWA问答社区提供回答,欢迎大家转至社区交流: https://answer.uwa4d.com/question/5c04d886a7bd4622df98d6f0

UI

Q:多语言下,如何做Text组件大小和文本长度的适配?同一段文本,同一字体大小,不同语言下其长度(文字个数)和文字大小(像素宽高)不同,那么如何防止文本超出Text组件显示范围?如何保证视觉效果合理(文字不会太小也不会太大,位置不会太偏)?有哪些自动化的方案?

首先应该根据一种语言规划好文本框的大致大小,建议根据英语来规划,汉字有时候两个字,翻译成其他语言就是一长串。英语较为折中。

一种方式是固定好文本框大小,Bestfit,设置好最小和最大的字体,如果不拓展Bestfit,这种就有点粗暴。我们之前的项目就是这么粗暴;另一种方式是用ContentSizeFitter,可以计算出单个字符的大小,根据自己设定的最大最小值,通过扩展脚本可以动态的实现水平和垂直的扩展。

一般来说,肯定逃不掉特别极端的,所以再扩展个脚本处理这种非常特殊的。

感谢赵林@UWA问答社区提供了回答,欢迎大家转至社区交流: https://answer.uwa4d.com/question/5c09e4f8f937bd2cbf9deb03

今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com

官方技术博客:blog.uwa4d.com

官方问答社区:answer.uwa4d.com

官方技术QQ群:793972859(原群已满员)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

走进搜索引擎

走进搜索引擎

梁斌 / 电子工业出版社 / 2007-1 / 49.80元

《走进搜索引擎》由搜索引擎开发研究领域年轻而有活力的科学家精心编写,作者将自己对搜索引擎的深刻理解和实际应用巧妙地结合,使得从未接触过搜索引擎原理的读者也能够轻松地在搜索引擎的大厦中邀游一番。《走进搜索引擎》作为搜索引擎原理与技术的入门书籍,面向那些有志从事搜索引擎行业的青年学生、需要完整理解并优化搜索引擎的专业技术人员、搜索引擎的营销人员,以及网站的负责人等。《走进搜索引擎》是从事搜索引擎开发的......一起来看看 《走进搜索引擎》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具