6

Addressable热更新资源类型的疑问

 3 years ago
source link: https://blog.uwa4d.com/archives/TechSharing_250.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1)Addressable热更新资源类型的疑问
​2)本地删除FBX的DefaultMaterial在Unity重启后失效
3)如何实现MeshRenderer的效果
4)UGUI动态加载Item的DrawCall问题
5)Loading.CheckConsistency [Editor Only]编辑器上的优化问题


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

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

Addressable

Q:Addressable可以热更新Text/Xml等原始资源,不走AssetBundle吗?正在考虑是否使用Addressable作为热更新方案,有一些资源不想走AssetBundle,想直接读取,不知道Addressable是否支持?

A:Addressable目前没有直接支持Raw资源,基本都是走AssetBundle的。

一个思路就是把这些资源单独打AssetBundle,以AssetBundle为载体,逻辑上还是当成单独的Text,Binary去读取;另外一个思路就是做扩展改造。

可以看到有TextDataProvider这个Provider类,内部用“File.ReadAllText(path);”获取资源,因此其实可以去实现一下AddressableAssetGroupSchema和BuildScriptBase,做一个RawAssetSchema和BuildScriptRawAsset的扩展来打包。

感谢黄程@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/607cef2a6bb31032f9791381


Editor

Q:用了Addressables系统,打包AssetBundle有Default Material有冗余,在打包机上运行脚本把FBX的默认材质删除后变紫,但是重新打开工程后默认材质又回来了,导致冗余还在。(Unity版本2018.4.34)

删除材质的脚本:

using System;
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEditor;
using Object = UnityEngine.Object;

class DisableMaterialImport : AssetPostprocessor {

    [MenuItem("Tools/Reimport All Model")]
    public static void ReimportAllModel()
    {
        var assetPaths = AssetDatabase.GetAllAssetPaths();
        Array.Sort(assetPaths);
        Debug.LogWarning(string.Format("Total assets count: {0}", assetPaths.Length));
        int processedCount = 0;

        foreach (string assetPath in assetPaths)
        {
            string normalizedAssetPath = assetPath.ToLower();
            if (!normalizedAssetPath.EndsWith(".fbx") &&
                !normalizedAssetPath.EndsWith(".obj") &&
                !normalizedAssetPath.EndsWith(".3ds"))
            {
                continue;
            }

            var modelImporter = AssetImporter.GetAtPath(assetPath) as ModelImporter;
            if (modelImporter == null || modelImporter.importMaterials)
            {
                continue;
            }


            AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ImportRecursive | ImportAssetOptions.ForceUpdate);
            Debug.Log(assetPath, AssetDatabase.LoadMainAssetAtPath(assetPath));

            processedCount++;
        }

        Debug.LogWarning(string.Format("Total processed model count: {0}", processedCount));
        AssetDatabase.SaveAssets();
    }

    private static void FixedModelImport(ModelImporter modelImporter, GameObject model)
    {
        //Debug.Log("FixedModelImport "+model);
        var renderers = model.GetComponentsInChildren<Renderer>(true);
        if (renderers == null)
        {
            return;
        }

        modelImporter.importMaterials = false;
        modelImporter.importBlendShapes = false;
        modelImporter.importAnimation = false;
        modelImporter.isReadable = false;
        modelImporter.optimizeMesh = true;

        foreach (var renderer in renderers)
        {
            if (renderer == null)
            {
                continue;
            }

            renderer.sharedMaterials = new Material[renderer.sharedMaterials.Length];
        }

/*        var animator = model.GetComponent<Animator>();
        if(animator!=null) Object.DestroyImmediate(animator);*/
    }

A1:我这边试验过,不会变回来啊,会不会是把工程回滚了。另外这个脚本的ReimportAllModel只对本身就没有勾选Import Materials的模型有效。

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

A2:尝试多次,发现关掉Cache Server就好了。

感谢题主唐@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/609906386bb31032f97915ae


Editor

Q:我有个需求就是要将关卡里的对象通过脚本间接创建,而不是直接将Prefab拖到场景中。因此我需要能象MeshRenderer那样直接在场景中显示并方便我选中与编辑的。

代码类似这样:

    public class SpawnPrefab : MonoBehaviour
    {
        public GameObject prefabEntity;
        void Start()
        {
            Instantiate(prefabEntity);
        }
    }

MeshRenderer有下面两个特性:
1. 在Editor模式下SceneView与GameView下面同时显示;
2. 在运行模式下绘制出的对象可以在SceneView下选中。

目前我是在OnDrawGizmos函数中调用Graphics.DrawMesh,但SceneView中却无法选中,在Update中绘制却在Editor模式下无法显示。我感觉好像尝试的方向错了。

A:OnDrawGizmos里面绘制显然是不行的,这个函数在打包出来Runtime都不会调用。

要在SceneView中选中编辑,一定得是场景中的某个GameObject。(用GameObject挂MeshRenderer肯定能满足“SceneView编辑”和“运行时脚本创建”两个需求的。)

如果题主的需求是一定要用Graphics的立即渲染接口来画Mesh,并且要在Editor下显示,那么给类加一个ExecuteAlways属性就可以了,只是还不能在SceneView中选中编辑。

1.png

如果还想实现Scene窗口下编辑功能,只能给要绘制的Mesh绑定一个场景中挂了MeshRenderer的GameObject。Graphics.DrawMesh绘制物体的Transform与这个GameObject保持一致就行了。如下图,Game窗口为OnPostRender函数中用Graphics.DrawMeshNow函数绘制的效果,Scene窗口中为绑定的用来编辑调整的物体,两者的Transform是一致的:

2.png

关键代码如下:

3.png

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


Q:关于动态加载Item,这样是不是算是穿插了,如果有大量的Item那得多少DrawCall,我感觉我走入了误区,求解如何学习这方面,还是说实际工作中,都不去管这种?

4.png

我这里只是举了个例子,正常项目中元素不可能这么少,如果多,动态加载的如何合批?如果要单独写脚本来处理动态加载的Item中的元素,那可就太不合理了。例如NGUI使用过Depth来控制面板下元素的合批,我只了解UGUI是用摆放顺序来控制,如果只是这样,对动态加载的太不友好了。

A1:共享相同材质的网格,满足其它合批条件,以相邻顺序渲染即可合批,减少DrawCall。所以合批的关键,在于对使用相同材质的物体,控制渲染顺序。

合批条件和优化方案有以下资料:
https://blog.uwa4d.com/archives/optimzation_cpu.html
https://docs.unity3d.com/Manual/DrawCallBatching.html

Unity中影响渲染顺序的因素:
https://zhuanlan.zhihu.com/p/55762351

不同的资源控制渲染顺序的方式不同,如MeshRenderer,可以设置材质的RenderQueue;ParticleSystem可以设置Order In Layer和Sorting Layer等。

UGUI元素的渲染顺序是UGUI这个插件本身决定的,我们要做的是理解UGUI对元素渲染的排序方式,尽可能使相同材质的UI元素以相邻顺序渲染。具体的关键点譬如:避免同一层的UI元素互相重叠,UGUI是一层一层绘制的,保证相同材质的UI作为同一层来绘制。如题主项目中的Img都放在同一层,Txt都放在第二层。如果两个Img发生叠层,就会有一个Img是作为第二层来绘制的,导致Txt的绘制与Img的绘制互相穿插,就会增加DrawCall。

只要不重叠,使用相同图集的同层元素就会自动合批的。如果是复杂的界面就只能尽可能合并图集,叠层多的情况下,只要保证材质相同的元素使用相同图集,并以相邻顺序绘制就可以合批。UGUI里的图集一多,DrawCall就没什么好办法来控制了。

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

A2:只要Item的面积和另外一个Item的面积不重叠,那么所有的文本都算第二层,Image都算第一层,就2个DrawCall而已。如果怕被别的UI元素影响,可以让这些Item单独放在一个Canvas里面,这样就不会受到其它UI元素的影响了。

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


Editor

Q:Loading.CheckConsistency [Editor Only]在编辑器上比较耗时,请问是做什么的,如何优化?

5.png

A:ReadObject实际上是在加载之后,对Object进行反序列化。一个Prefab反序列化后,会有大量的Object。IntegrateAllThreadedObjects会遍历这些Object,而Loading.CheckConsistency就是在遍历这些Object时,对数据进行一致性检验。

所谓一致性检验,就是比如,对下图Prefab的序列化文件,会检查两个红框中的fileID是否一致。

6.png

图片来源:
https://www.cnblogs.com/luguoshuai/p/12323186.html

如这篇博文所讲,如果两个fileID不一致,会有CheckConsistency的报错。

为什么只在Editor下进行一致性检验,而打包后Runtime不需要检验呢?笔者推测是在打包的时候已经对所有对象都检验过了,Runtime就不需要检验,也避免了检验带来的高耗时。

证据如下图,某次打包的报错堆栈里面,包含了CheckConsistency的步骤:

7.png

图片来源:
https://networm.me/2019/06/23/unity-has-stopped-working/

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

封面图来源于:Pixel Sorting
https://lab.uwa4d.com/lab/5dd4587f8bab6aaf02db4018


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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK