头图

1)关于Addressable打包图集与图片都打进去造成冗余
​2)Unity如何计算Root动画旋转
3)IL2CPP编译的Protobuf反射类运行时报空
4)为什么Active Constraints会出现过高的现象


这是第337篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地掌握和学习。

UWA社区主页:community.uwa4d.com
UWA QQ群:465082844

Addressable

Q:关于Addressable打包图集与图片都打进去造成冗余。

Unity版本:2021.2.13f1c1
Addressable版本:1.19.16(cn版本)

使用的是Addressable的默认Group,场景中只使用了decal3的UI图片,但是打包最后的资源,Addressable的包中包含了两个资源,正常应该只有图集资源才对(如下图)。

另外,看了Addressable打包流程的代码,Unity把关联的图片加入依赖打包列表,但是又在之后对图片检测做了生成图集的处理。原生打包不会对图集里的图片再做处理吗?

A:可以切换com.unity.ScriptableBuildPipeline版本到1.21.5试试看,1.21.5修复的问题应该包括这个。
更新日志:
https://docs.unity3d.com/Packages/com.unity.scriptablebuildpi...

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

Animation

Q:想了解Unity的RootMotion的实现细节,请问Unity是怎么计算Root动画旋转的?

一个动画,如果配置正确,AnimationClip里会多两段曲线数据,RootT、RootQ分别是根节点的位移和旋转信息。但是当我用Animator跑起来后,我们每帧RootMotion旋转多少,Root节点逆向旋转多少,是怎么计算出来的呢?

朴素的想法是:旋转当前帧的RootQ相对于第0帧RootQ的旋转的eulerAngles.y。但是经过我多次测试,并不是这个值,而是有偏差的一个值。有时候多几度,有时候少几度。

没有Unity源码的情况下,很难知道它的计算方法。我去看了Godot,其方法是正常把当前旋转和第0帧做差值。

比如这个动画,我已经把数据删得差不多了。第1帧,Animator认为应该转24.068,这两个旋转的欧拉角表示分别是(277.77, 66.96, 81.36) 、(279.53, 74.28, 100.03),from to旋转的欧拉角是(3.29, 25.78, 0.02) 。这个25.78和24差得不多,但是总归不一样。其他测试数据类似,都是差一点。

A:对于旋转的计算,Unity使用了四元数(Quaternions)来表示旋转。旋转的差异可能是由于以下原因之一导致的:

  1. 欧拉角(Euler angles)转换为四元数的过程中可能存在精度损失。欧拉角存在万向锁问题和旋转顺序问题,这可能导致从欧拉角转换为四元数时出现不准确的结果。
  2. 根节点旋转的计算可能受到其他因素的影响,例如动画过程中的插值算法、关键帧的设置、平滑过渡等。这些因素可能会导致计算结果与期望的差异。

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

Script

Q:IL2CPP编译的Protobuf反射类运行时报空,问题发生时,会闪崩,闪崩日志信息:
ErrorNotNull:"c# exception:System.TypeInitializationException: The type initializer for 'abcConfigReflection' threw an exception. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ExecutionEngineException: Attempting to call method 'Google.Protobuf.Reflection.ReflectionUtil+ReflectionHelper`2[[System.IntPtr&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.n

at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 n

at System.Activator.CreateInstance (System.Type type, System.Boolean nonPublic) [0x00000] in <00000000000000000000000000000000>:0 n

at Google.Protobuf.Reflection.ReflectionUtil.GetReflectionHelper (System.Type t1, System.Type t2) [0x00000] in <00000000000000000000000000000000>:0 n

at Google.Protobuf.Reflection.ReflectionUtil.CreateFuncIMessageObject (System.Reflection.MethodInfo method) [0x00000] in <00000000000000000000000000000000>:0 n
...
具体信息请见原网页。

看下来是因为AOT编译时代码剔除所致,问题非常偶现。我们的QA基本上没有跑出来过这个问题,但是放到外网就有一堆玩家遇到此问题,蹊跷的是哪怕同一个手机也是偶然才报。

Proto Github项目有人提过:
https://github.com/protocolbuffers/protobuf/issues/5422

这个问题包括下面回复主要提了两点:
1. linker包含Google.Protobuf程序集
2. AOT编译器不会为T、为AnyEnum的泛型方法,针对枚举参数泛型方法创建显式调用类https://docs.unity3d.com/cn/current/Manual/ScriptingRestricti...

和我这个问题不同点是,abcConfigReflection是一个类,不是枚举,而且整个项目这个类会有很多。

我用的Proto版本3.6.1,而且Proto也在3.6.0版本说修改了> AOT generics issues in Unity/il2cpp have a workaround (see commit 1b219a1 for details)。

Protobuf源码确实加了强制反射的代码:

static FileDescriptor()

        {
            ForceReflectionInitialization<Syntax>();
            ForceReflectionInitialization<NullValue>();
            ForceReflectionInitialization<Field.Types.Cardinality>();
            ForceReflectionInitialization<Field.Types.Kind>();
            ForceReflectionInitialization<Value.KindOneofCase>();
        }

当然我有加Google.Protobuf程序集到linker,还是不能解决。后来我加了Assembly-CSharp程序集到linker,也就是整个自定义代码全部不剔除,目前因为不方便放外网,也不清楚有没有解决这个问题。

使用Protobuf序列化数据应该是常规操作,相信应该有很多人遇到,不知道大家处理方案是什么?

A:可以尝试以下方法:
Initialize the library and verify operation | Android Developers

Ahead-of-time compile (AOT)
Ahead-of-time compile is required for the IL2CPP backend and Unity versions 2017 and 2018 (but not for later versions of Unity).<br/>
The AOT compiler may not generate code for generic methods. You need to force the compiler to generate the proper code required for protobuf by adding the following method:<br/>

using Google.Protobuf.Reflection;
using UnityEngine.Scripting;

...

// Don't call this method.
[Preserve]
void ExampleOfForceReflectionInitializationForProtobuf()
{
    FileDescriptor.ForceReflectionInitialization<Scene>();
    FileDescriptor.ForceReflectionInitialization<ShadowType>();
    FileDescriptor.ForceReflectionInitialization<LevelType>();
    ...
    // Add FileDescriptor.ForceReflectionInitialization<T> for each generated enum.
    // You can find the list of enums in DevTuningfork.cs -> enum section
    // or in the list of enums in Google -> Android Performance Tuner.
}

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

Physics

Q:通过Profiler分析项目,发现其中Active Constraints这一项会突然出现一个很不合理的峰值。目前只发现与角色身上是否挂载刚体有关。

但是与刚体数量对比起来,这种极高的Active Constraints为何会发生是毫无头绪的。在此向各位请教下。

A:从官方文档的截图里可以看到,在一个刚体的情况下,官方的实例里依旧也会产生17.29KB的Active Constraints。估计是统计方式有问题,又或者是理解上存在差异。

我在Unity 2018和Unity 2020这两个版本都见到过Active Constraints过高的现象。

至少目前来讲,这个数量级的Active Constraints还属于可接受范围(官方自己都觉得没问题),不需要去专门花费大量时间去排查优化。

感谢题主午休达人@UWA问答社区提供了回答

封面图来源于网络


今天的分享就到这里。生有涯而知无涯,在漫漫的开发周期中,我们遇到的问题只是冰山一角,UWA社区愿伴你同行,一起探索分享。欢迎更多的开发者加入UWA社区。

UWA官网:www.uwa4d.com
UWA社区:community.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:465082844


侑虎科技
62 声望21 粉丝

UWA官网:[链接]