关于gpu:高通芯片GPU是否有类似于HSR功能

7次阅读

共计 6539 个字符,预计需要花费 17 分钟才能阅读完成。

1)高通芯片 GPU 是否有相似于 HSR 的性能
​2)UGUI 上的 RT 动图会不会导致 UI 更新
3)UI 常常迭代外观,如何尽量少改代码
4)开发过程中该应用 AssetBundle 包模式,还是模仿模式?


这是第 279 篇 UWA 技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫 10 分钟,认真读完必有播种。

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

GPU

Q:高通芯片 GPU 是否有相似于 HSR 性能?望解答,谢谢。

A:参考如下:
测试案例 1:小米 9
点击按钮增加全屏不通明的 Quad,应用 Standard Shader,离相机越远,RenderQueue 越小。

后果: 从 FPS 上看,到 100 层,帧率也都是 60 帧。阐明小米 9 上的确有相似于 HSR 的性能,就是不通明对象不须要手动调整渲染队列从而让凑近相机的先渲染。

测试案例 2:小米 5X
点击按钮增加全屏不通明的 Quad,应用 Standard Shader,离相机越远,RenderQueue 越小。

后果: 从 FPS 上看,1 层的时候 43 帧,2 层就掉到 25 帧,3 层掉到 17 帧。阐明小米 5X 上没有相似于 HSR 的性能。

测试案例 3:小米 5X
点击按钮增加全屏不通明的 Quad,应用 Standard Shader,离相机越远,不调整 RenderQueue。

后果: 从 FPS 上看,1 层的时候 43 帧,5 层的时候仍旧 43 帧。不调整 RenderQueue 后,因为 Unity 的不通明是依照由近到远绘制的,因为 Early- Z 的关系,导致被遮挡的物体不会进行 Fragment Shader 计算了,所以帧率比较稳定。

总结: 对于像地形这样的大面积且 Shader 复杂度通常比拟高的对象,还是须要调整渲染队列到比拟靠后的,因为对于低端机型,并没有 HSR 这样的性能。所以能够通过调整地形的渲染队列靠后,从而让 Early- Z 对于大地形失效,从而缩小地形的渲染像素。

对于高端机型,如小米 9,因为其 GPU 硬件反对 HSR 性能,所以对于不通明物体来说,渲染队列没有关系。

总体来说,还是倡议调整大地形的渲染队列,对低端机型有益处。

感激小苗子 @UWA 问答社区提供了答复

UGUI

Q:在 UGUI 组件上应用 RenderTexture 动图会不会导致 UI 更新?

A:对于这个问题进行了简略的试验:试验设置了一个相机拍摄不停在静止两个物体,而后失去的 RenderTexture 赋给 UGUI 上的 100 个 RawImage。在真机上运行,此时 UI 更新耗时简直为 0。

实践上,这些 RawImage 的顶点属性没有发生变化,的确不会导致 UI 更新。

感激 Faust@UWA 问答社区提供了答复

UGUI

Q:问题:之前的我的项目是用 Lua 做 UI 开发的。一个 ToLua,一个 XLua。策动或美术常常要调曾经做好的 UI 的外观,个别须要变布局或节点层级。最早,代码里拜访某个节点都是用 GameObject.Find 找到节点,层级关系一变,就须要程序配合改,很麻烦。怎么做到调整 UI,不必改代码呢?

思路:想到一个命名标准计划:程序拿到 UI 的 Prefab 绑上 UI 关联 Lua 的脚本后,把所有程序须要拜访的节点,改名成 rd_xxxxx,脚本管制下的子节点 rd_结尾的不能反复,如果有列表的子节点,下面再挂一个辅助的脚本(比方 UItemHelper)。

Lua 第一次加载时遍历所有节点,缓存所有 rd_xxx 的节点关系到脚本里(Lua 里),这样,Lua 代码里间接用 self.rd_xxxxx 就能失去对象,也不怕 Prefab 层级调整,也不必屡次调用 GameObject.Find。

规定其余人员调整 UI Prefab 时,不能改掉 rd_xxxxx,如果须要改则要程序配合。

参考代码:ToLua 我的项目的一个参考批改:

关联 Lua 脚本对象的 LuaXXX.cs 里(比方叫 LuaMono.cs)初始化,减少:

……
        if (m_params.Count == 0)
        {
            //lua 关联对象主动收集
            SetRDObjectRef(luaClass, this.gameObject, true);
        }
        else
        {// 节点整顿期间的兼容 ( 复用 UI 也走这里,防止重复收集)
            foreach (ParamItem pi in m_params)
            {luaClass[pi.name] = pi.value;
            }
        }
……
 
    /// <summary>
    /// 把节点下所有节点查一下,如果名字是 "rd_" 结尾的则是程序须要
    /// </summary>
    /// <param name="luaClass"></param>
    /// <param name="go"></param>
    void SetRDObjectRef(LuaTable luaClass,GameObject go,bool is_root = false)
    {if(go)
        {if(MyExtensions.StringStartsWith(go.name,"rd_"))
            {
#if UNITY_EDITOR
                // 查看是否有反复
                if(luaClass[go.name] != null && !luaClass[go.name].Equals(null))
                {GameFramework.Log.Error("{0} LuaClass already have GO key:{1} {2}", LuaScript, go.name, luaClass[go.name]);
                }
#endif
                luaClass[go.name] = go;
                ParamItem item = new ParamItem();
                item.name = go.name;
                item.value = go;
                m_params.Add(item);
            }
 
            if(is_root || (go.GetComponent<LuaMono>() == null && go.GetComponent<UItemHelper>() == null))
            {
                // 遍历所有子节点
                for(int i=0;i<go.transform.childCount;++i)
                {SetRDObjectRef(luaClass, go.transform.GetChild(i).gameObject);
                }
            }
        }
    }

UItemHelper.cs

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
 
public class UItemHelper : MonoBehaviour
{
#if UNITY_EDITOR
    public class ParamItem
    {
        public string name;
        public UnityEngine.Object value;
    }
#endif
 
    Dictionary<string, GameObject> m_nodes = new Dictionary<string, GameObject>();
    bool init = false;
#if UNITY_EDITOR
    [SerializeField]
    protected List<ParamItem> m_params = new List<ParamItem>();
#endif
    void Awake()
    {Init();
    }
 
    public void Init()
    {if(!init)
        {m_nodes.Clear();
            SetRDObjectRef(this.gameObject, true);
            init = true;
        }
    }
 
    /// <summary>
    /// 把节点下所有节点查一下,如果名字是 "rd_" 结尾的则是程序须要
    /// </summary>
    /// <param name="luaClass"></param>
    /// <param name="go"></param>
    void SetRDObjectRef(GameObject go, bool is_root = false)
    {if (go)
        {if (MyExtensions.StringStartsWith(go.name, "rd_"))
            {
#if UNITY_EDITOR
                // 查看是否有反复
                if (m_nodes.ContainsKey(go.name))
                {GameFramework.Log.Error("sub item node {0} already have GO key:{1} {2}", this.name, go.name, m_nodes[go.name]);
                }
                else
#endif
                {m_nodes.Add(go.name, go);
#if UNITY_EDITOR
                    ParamItem item = new ParamItem();
                    item.name = go.name;
                    item.value = go;
                    m_params.Add(item);
#endif
                }
            }
 
            if (is_root || (go.GetComponent<LuaMono>() == null && go.GetComponent<UItemHelper>() == null))
            {
                int childCount = go.transform.childCount;
                Transform t = go.transform;
                // 遍历所有子节点
                for (int i = 0; i < childCount; ++i)
                {SetRDObjectRef(t.GetChild(i).gameObject);
                }
            }
        }
    }
 
    public GameObject GetNode(string name)
    {if(m_nodes.ContainsKey(name))
        {return m_nodes[name];
        }
        return null;
    }
 
    public Image GetNodeImage(string name)
    {if (m_nodes.ContainsKey(name))
        {GameObject go = m_nodes[name];
            if (go != null)
            {Image img = go.GetComponent<Image>();
                return img;
            }
        }
        return null;
    }
 
    public Text GetNodeText(string name)
    {if (m_nodes.ContainsKey(name))
        {GameObject go = m_nodes[name];
            if (go != null)
            {Text txt = go.GetComponent<Text>();
                return txt;
            }
        }
        return null;
    }
 
    public Button GetNodeButton(string name)
    {if (m_nodes.ContainsKey(name))
        {GameObject go = m_nodes[name];
            if (go != null)
            {Button btn = go.GetComponent<Button>();
                return btn;
            }
        }
        return null;
    }
 
    // 前期增加的节点
    public void AddNode(GameObject go)
    {
#if UNITY_EDITOR
        // 查看是否有反复
        if (m_nodes.ContainsKey(go.name))
        {GameFramework.Log.Error("sub item node {0} already have GO key:{1} {2}", this.name, go.name, m_nodes[go.name]);
        }
        else
#endif
        {m_nodes.Add(go.name, go);
#if UNITY_EDITOR
            ParamItem item = new ParamItem();
            item.name = go.name;
            item.value = go;
            m_params.Add(item);
#endif
        }
    }
 
    // 删除前期增加的节点
    public void RemoveNode(GameObject go)
    {
#if UNITY_EDITOR
        if (m_nodes.ContainsKey(go.name))
#endif
        {m_nodes.Remove(go.name);
#if UNITY_EDITOR
            ParamItem item = new ParamItem();
            item.name = go.name;
            item.value = go;
            m_params.Remove(item);
#endif
        }
    }
 
    public Dictionary<string, GameObject> GetAllRdGameObject()
    {return m_nodes;}
}

其余:当然各个我的项目状况不一样,须要各自实现。不知大家我的项目里遇到相似问题,用的是什么计划?

比方有的计划不心愿一开始初始化,能够在创立关联 Lua 时,设置元表,重写_index,当 self.rd_XXX 这样拜访时,取到索引的前缀是 rd_,则去断定缓存,没有则去找对应节点关联。

A1:基于门路的 UI 控件查找还是比拟软弱,间接应用 Unity 序列化援用更好,能够随便批改构造改名字不必放心失落。

这里有一个不错的计划:UIControlBinding

感激张迪 @UWA 问答社区提供了答复

A2:别用 GameObject.Find 办法,编辑器序列化间接绑定到 Lua。和应用原生 CS 绑定一样。

感激 1 9 7 3-311135@UWA 问答社区提供了答复

A3:把 UI 控件间接序列化到 C# 脚本上,运行时不要用 Find 和 GetComponent,UI 面板的 Prefab 实例化后,间接把这些对象塞到一个 Lua Table 里传给 Lua。

感激唐崇 @UWA 问答社区提供了答复

Asset

Q:应用 AssetBundle 包,可能较大水平保障资源的正确性,但一点资源的批改就要打包,比拟浪费时间,特地是美术、策动同学对它比拟抵制;应用模仿模式,大略只是开发效率高一些,成果谬误、循环援用等问题要延后到打包后能力发现(当然有很多其余形式能够提前发现,但属于附加伎俩)。

最近我的项目中发现,即便预加载了资源,Play 过程中还是会呈现十分重大的卡顿(1s+),这么长时间的卡帧导致体现成果间接不对了:比方,1s 从终点挪动到起点的过程,间接变成闪现到起点,成了 Bug。

卡顿起因查下来是:AssetDatabase.Load 进去的 Prefab 并不会将其依赖的 Texture 一起加载进内存,Prefab 第一次渲染的时候 Texture 才会加载。咱们这一个很简单的(未优化)技能特效,用了 40MB+ 的 Texture,把 UploadTexture 卡了。

以这样一个非凡的问题为契机,筹备重新考虑下要履行的计划,心愿大家能多给些倡议,能够是二者的比照抉择,也能够是其余更好的做法或实现。

A:把 Unity 我的项目放在高速 SSD 中应该能缓解不少。

之前见到一个计划是在预加载时,创立一个玩家看不到的相机,把技能特效的 Animator、ParticleSystem 和音频组件等都执行一下,同时调用 Camere.Render,强制把各类资源都 WarmUp 好,这样进入游戏后根本没有 IO 操作,应该能大大缓解题主形容的问题。

针对一些特效是被 Timeline 的轨道治理的,而后 Timeline 自身是一个独立模块的,能够依据技能配置找到特效(技能配置关联 Timeline,Timeline 关联特效),而后对特效预渲染就能够了,Timeline 只是逻辑流程控制器。当然如果 Timeline 自身卡顿,还是要预执行一遍更好。

感激张迪 @UWA 问答社区提供了答复

20211213
更多精彩问题等你答复~

  1. Unity 增量打包 AssetBundle 没变动的资源也会被从新打包
  2. 在模型有 UV2 的状况下开启 Generate Lightmap UVs
  3. 如何实现 AAB 包的增量更新

封面图来源于网络


明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在 UWA 问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。

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

正文完
 0