10

NGUI Label 自定义材质球无效

 2 years ago
source link: https://blog.uwa4d.com/archives/TechSharing_296.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

NGUI Label 自定义材质球无效

1)NGUI Label 自定义材质球无效
​2)代码保存预制体出现图片丢失的问题
3)升级Unity版本,粒子系统触发的闪退问题
4)场景打包AssetBundle过大


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

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

Q:想在NGUI下做一个字体溶解Shader,自定义的Shader材质球给Label不起作用,有没有大佬了解这块内容?

1.png
2.png
3.png

A:猜测题主是要在编辑器里面的材质球对象上调整_Threshold的数值,但在Game窗口发现文本没有发生变化。

本质原因是NGUI在对Label进行渲染的时候使用的并不是编辑器里面赋值的材质球,而是在NGUI进行合并DrawCall后动态创建的Material,所以我们需要对这个材质球进行材质球属性设置。

这里可以通过脚本来给实际渲染Label的材质球调整属性达到效果。以下分别是Threshold为0和Threshold为0.4的效果。

4.png
5.png
public class TestLabel : MonoBehaviour
{
    public float threshold;
    public UILabel label;

    void Update()
    {
        if (label.drawCall != null)
            label.drawCall.dynamicMaterial.SetFloat("_Threshold", threshold);
    }
}

PS:这样处理的坏处是,和这个Label在同一个DrawCall的Label都会受到影响,所以需要将这些效果的Label的Depth做特殊处理,和其它的Label不放在同一个DrawCall中。

另外在NGUI的UI DrawCall脚本中,可以打开SHOW_HIDDEN_OBJECTS,这样在编辑器里面是可以看到生成具体的DrawCall对象,也就可以看到它们的材质球属性变化。

6.png

从下图可以看到具体的DrawCall,它的材质球名字会在前面加[NGUI]的字样,和编辑器里不是同一个材质球。

7.png
8.png

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


Script

Q:我在Unity 2021.3.x上想根据配置动态生成预制体。现在遇到的问题是,可以把图片动态读取上去,然后保存预制体了以后,图片就丢失了,应该是需要修改.prefab里的值 。

我使用SerializedObject模块.objectReferenceValue去修改m_Sprite不会生效,它是引用类型的,而值类型的都是可以修改的。有大佬知道怎么修改嘛?

A:用下面的代码,是可以在编辑器里改的,不太确定楼主是不是想要在编辑器里操作,还是在Runtime下操作,理论上Runtime时是没有预制体的概念的。在编辑器里面,选中预制体,然后点击Update Prefab Asset按钮即可。

预制体很简单:

public class Example
{
    [MenuItem("Examples/Update Prefab Asset")]
    static void AddBoxColliderToPrefab()
    {
        // Get the Prefab Asset root GameObject and its asset path.
        GameObject assetRoot = Selection.activeObject as GameObject;
        string assetPath = AssetDatabase.GetAssetPath(assetRoot);

        Texture2D tt = AssetDatabase.LoadAssetAtPath("Assets/2.jpg", typeof(Texture2D)) as Texture2D;

        Sprite ss = AssetDatabase.LoadAssetAtPath("Assets/3.jpg", typeof(Sprite)) as Sprite;
        // Load the contents of the Prefab Asset.
        GameObject contentsRoot = PrefabUtility.LoadPrefabContents(assetPath);

    // Modify Prefab contents.
        contentsRoot.transform.Find("RawImage").GetComponent<UnityEngine.UI.RawImage>().texture = tt;
        contentsRoot.transform.Find("Image").GetComponent<UnityEngine.UI.Image>().sprite = ss;


        contentsRoot.AddComponent<BoxCollider>();

        // Save contents back to Prefab Asset and unload contents.
        PrefabUtility.SaveAsPrefabAsset(contentsRoot, assetPath);
        PrefabUtility.UnloadPrefabContents(contentsRoot);
    }
}

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


ParticleSystem

Q:我们升级了版本到2018.4.36f1,但特效是5.6做的,重新激活特效属性后预制件发生了很多的改变。所以大概原因是高版本不兼容低版本的特效。

捕捉crash.dmp反馈异常“该线程尝试读写某个虚拟地址,而它对该地址不具有相应的访问权限”。没有其余的堆栈信息。

已知是特效子物体的某一个粒子导致了闪退,但不知其根本原因是粒子的哪一部分导致。

已知该闪退粒子使用了Emission,Shape,Limit Velocity over Lifetime,Color over Lifetime,Size over lifetime和Renderer。

Shader是共用的,所以我就没有怀疑Shader。

用Demo复现的方法,逐一排查发现只要重新激活Limit Velocity over Lifetime,特效就不会卡死。不能说重新激活,隐藏该属性打包->播特效Win端不卡死->重新激活该属性->播特效Win端不卡死。重新将该预制件回滚,打包->播特效Win端卡死。

A1:以前遇到过这两种粒子系统导致的闪退:

  1. 粒子Renderer的Mesh的RW没勾选,导致闪退;
  2. 粒子Renderer的Mesh没有清理干净,也可能会导致闪退,比如原来粒子Renderer的Rendermode为Mesh,并设置了自定义的Mesh,然后美术修改Rendermode为billBoard,这时候原Mesh的引用关系还在,某个挺早的Unity版本可能会导致闪退。

如果不是这两个问题,那就要用Demo逐一排查。

感谢范世青@UWA问答社区提供了回答

A2:升级之后,所有Prefab用AssetDatabase.ForceReserializeAssets重新序列化一下。

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


AssetBundle

Q:有一个场景,里面有很多物件设置为Static,Unity在打场景AssetBundle的时候会自动将各个物件的Mesh合并成一个大的,导致该场景的Assetbundle(只包含.scene文件)达到10多MB,大家有什么解决方案吗?

A1:首先应该知道为什么场景这么大,有没有优化空间,可以用AssetStudioGUI看下Assetbundle里的资源,把能精简的精简掉。

如果确实无法精简,包体还是太大,可以把场景关联的资源提取出来,动态加载入场景,场景过大容易产生加载卡顿,动态加载可以自己控制加载吞吐量,在优化上也比较好把控。这也是最建议的一种方式。

感谢廖武兴@UWA问答社区提供了回答

A2:可以关掉静态合批,而用手动静态合批,耗时不长,一个比较复杂的场景700ms,普通场景正常200ms左右。

只不过在合并的时候会有一个内存峰值需要注意,还有手动Mesh的RW需要开启:
StaticBatchingUtility.Combine(item.GoList, _inst.gameObject);
mesh.UploadMeshData(true);
Resources.UnloadUnusedAssets();

感谢范世青@UWA问答社区提供了回答

A3:对于一个场景来说,纯Mesh应该到不了10多MB,这个里面估计应该包含了所有引用到的贴图,可以通过调整对应平台的贴图压缩格式来进行简化。

感谢萧小俊@UWA问答社区提供了回答

A4:如果用了GPU Instancing或者SRP Batching,就没有必要设置为Static Batching。

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

封面图来源于网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在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