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

发布时间 2023-05-30 10:39:55作者: UWATech

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.scriptablebuildpipeline@1.21/changelog/CHANGELOG.html

感谢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/ScriptingRestrictions.html

和我这个问题不同点是,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).

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:

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