骨骼数目和骨骼层级数目的美术规范

骨骼数目和骨骼层级数目的美术规范

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

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)


本期目录:

  • 骨骼数目和骨骼层级数目的美术规范
  • 如何获取优化前所有骨骼的名字
  • 如何打包的时候从代码里面获取SVN版本号
  • 如何避免或解决Git上两条分支的Prefab冲突问题
  • 现在仍然使用ETC1格式是否有必要

FBX

Q:想请教一个问题,骨骼数量和骨骼层级数目对性能的影响真的很大吗(有的文章是这么说的 )?我们经过了简单的测试,发现影响并没有很显著。
一个3000面的角色,100骨骼,7层,是否是一个合理的指标?还是存在很大的浪费?

A:不知道题主是如何测试的,默认不开启GPU skin或者用特殊的处理方式的情况下,这块影响的主要是CPU的性能,所以我觉得比较科学的方法是,通过统计不同骨骼数量的情况下CPU中动画模块的时间消耗来进行判断。

比如目标场景内会有n个角色,那么按照60根骨骼和100根骨骼放置n个角色,比较耗时差异。

另外,还要看100根骨骼是最大化骨骼,还是所有角色参与蒙皮的骨骼数量都是100根,这里可能也会有性能差异。我也做过一个简单的测试,最终影响Animator.Update性能消耗的是参与蒙皮的骨骼数量,这样如果采用最大化骨骼方案的话,其实不用特别限定最大化骨骼的数量,而是应该限定每个角色参与蒙皮的骨骼数量。

比如在电脑上,动画相关的模块的性能消耗对比:

100个角色,300根骨骼全部参与蒙皮:
请输入图片描述

100个角色,300根骨骼,但是其中只有60根参与蒙皮。(这里更新一下:确认了一下,发现Unity在导出时,不参与蒙皮的骨骼就不再会导出了,所有这里300根骨骼的概念只存在于Max中,在Unity中已经被优化成60根骨骼了。)
请输入图片描述

100个角色,60根骨骼全部参与蒙皮:
请输入图片描述

当然这里只是测试性能差异,更真实的数据是在目标机型上进行。

另外,骨骼层次可能过深并不好,但是假设在开启了GameObject优化选项的情况下,我不觉得像7层和10层这样的性能差异有很大。这块不是非常确定,只是从动画计算过程来推断——逐层计算的时候引擎一般会存储一个到根节点的变换矩阵供子节点直接使用,因此应该不会增加很多的额外消耗在这里。不过这点需要进行一些测试,没有看过Unity源码并不确定。

单纯从性能考虑的规范来说,对于刚刚立项的项目,100根骨骼,7层我个人觉得是OK的,3000面有点保守了,这个要看具体的游戏类型。当然,骨骼数量也要根据游戏类型来判断是否合理,比如动作类游戏可能就需要更多骨骼。

PS:测试数据使用的是人形模式。

PPS:再解释一下这个试验,@xin跟我沟通之后我发现这个试验是没有太大意义的。
之前做自研引擎的时候,模型导出之后,即使不参与蒙皮的骨骼也被导出到了模型身上,因此在动画更新的时候有个优化是将不参与蒙皮的骨骼剔除掉。我最初想通过这个试验验证的是Unity是否会做这样的优化(猜想是会做的,因为比较基础),从结果看也是这样的。但是我发现Unity是在导出的部分就已经做了这样的优化,即在Max中有300根骨骼,只有60根参与蒙皮,导入到了Unity内就只有60根骨骼。

这个的意义在于前文说的对于最大化骨骼数量的限制,我们之前的骨骼数量的限制是在最大化骨骼这层的,但现在看起来应当限制在最终模型的骨骼数量这一层。

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


FBX

Q:动画系统中开启Optimize Game Object选项后不必要的骨骼会消失,我们在骨骼下面挂了很多特效挂点,也清楚可以通过Extra Transforms to Expose暴露出挂点,之后采用编辑器工具批处理。
现在遇到一个问题,美术希望新增一个暴露的挂点。实际上有些FBX没有这样的挂点,希望在工具处理的时候检测FBX是否存在该挂点,不存在就不增加。因为之前处理就把所有FBX的Optimize Game Object选项勾上了,没办法通过LoadAsset之后取到优化前的所有骨骼点名字。有什么办法可以取到FBX的所有骨骼点名字吗?

A1:可以使用 ModelImporter.transformPaths 拿到FBX下面所有的节点路径。
感谢张首峰@UWA问答社区提供了回答

A2:除了ModelImporter,解析Avatar也是可行的:

public static bool HasSkeleton(this GameObject gameObject, string skeletonName)
{
    Avatar avatar = gameObject.GetComponentInChildren<Animator>(true).avatar;
    SerializedObject serializedObject = new SerializedObject(avatar);
    var property = serializedObject.FindProperty("m_TOS");
    for (int i = 0; i < property.arraySize; i++)
    {
        string fullSkeletonPath = property.GetArrayElementAtIndex(i).FindPropertyRelative("second").stringValue;
        if (fullSkeletonPath.EndsWith(skeletonName))
            return true;
    }
    return false;
}

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


Script

Q:我想在打包的时候获取到我这个工程的SVN版本号,请问下有没有人知道应该如何获取?

A1:用命令行的SVN info,然后从返回值里拆出版本号。

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

A2:用CI打包

svn log -v -r BASE:HEAD $unity_project_path

SvnVersion=`svn info | grep "Last Changed Rev" | tr -d "Last Changed Rev: "`

echo "SvnVersion:"$SvnVersion

启动Unity传入参数

$unity_path -batchmode -projectPath $unity_project_path -executeMethod BuildUi.BuildFromCI SvnVersion-$SvnVersion

C#获取

public static string SvnVersion
        {
            get
            {
                //SvnVersion-$1
                foreach (string arg in System.Environment.GetCommandLineArgs())
                {
                    if (arg.StartsWith("SvnVersion"))
                    {
                        return arg.Split("-"[0])[1];
                    }
                }
                return "";
            }
        }

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


版本管理

Q:请问对于Git上两条分支的Prefab冲突问题是怎么规避或解决的呢?如果出现外网版本正在快速迭代,内部版本正在开发几周后的大版本,但是两个版本都改动到同一个Prefab,遇到要合并怎么办呢?题主用的是Git,如果用SVN能解决吗?或者有什么比较好的解决冲突工具(Unimerge或UnityYAMLMerge哪个更好?)

A1:提供一个思路,我们是参考了Unimerge实现了个跨Unity进程的对比合并工具,开2个Unity来对比对应的Prefab。

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

A2:Unity 2018.3 中提供了Nested Prefab的功能,可以把Prefab的粒度拆得更细,从而降低冲突出现的几率。

感谢加菲教主@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c6aab7b2b3589332f1a4a50


Texture

Q:现在(2019年初)仍然使用ETC1格式是否有必要?4、5年前的说法是,低端机是不支持ETC2,所以需要用ETC1+Alpha分离的方式来支持低端机。
时至今日,几年前的高端机到现在都只能勉强算中端机了。当年的低端机大多可能也都淘汰。在游戏的iOS版本都默认ASTC格式不支持5S的背景下,是否还有必要使用ETC1+Alpha分离的方式来设置纹理格式?毕竟默认ETC2能比ETC1+Alpha的方式更节省内存+省事,而且效果更好。

A:如果是针对国内市场的游戏,只要不是棋牌类(或者对低端手机有特殊支持要求的),Android端都可以直接采用ETC2了。

但如果是针对海外市场,比如越南、泰国、印度等地区,则依然需要慎重考虑了。就目前大量团队反馈,不少国外地区还存在较低档次的机型设备,对于这种情况,建议与运营团队沟通下设备的占用率。

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c7695f363826a332ad9970b


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

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:793972859(原群已满员)

封面图来源:Unity GPU Instanced Animation
https://lab.uwa4d.com/lab/5b564c09d7f10a201fd90752