UGUI优化篇(更新中)

news2024/11/15 18:49:21

UGUI优化篇

  • 1. 基础概念
  • 2. 重要的类
    • 1. MaskableGraphic类继承了IMaskable类
    • 2. 两种遮罩的实现区别
      • RectMask2D
      • Mask
  • 3. 渲染部分知识
    • 深度测试
      • 深度测试的工作原理
    • 渲染队列
      • 透明物体在渲染时怎么处理
      • 为什么透明效果会造成性能问题

1. 基础概念

  • 所有UI都由网格绘制的
  • 如image由两个三角形构成,四个顶点
    在这里插入图片描述
    在这里插入图片描述
  • drawcall(绘制调用)是指向GPU发送绘制指令的过程。每个draw call都是一次向图形处理器提交渲染命令的操作。具体来说,每当Unity需要绘制一个物体或一批物体时,它会生成一个或多个draw call。
  • 填充率(Fill Rate)是指图形处理器(GPU)能够每秒填充像素的数量。它通常用来衡量GPU的渲染能力和性能。
  • 屏幕的分辨率决定了需要渲染的像素数量。更高的分辨率意味着需要填充更多的像素,因此会影响填充率。
  • Overdraw指的是在渲染过程中多次绘制同一个像素的现象。这通常发生在复杂的场景中,特别是当许多物体重叠或者遮挡彼此时。
  • 在Overdrall模式下,可以看到重叠的部分,两次drawcall,同一像素被绘制两次
    在这里插入图片描述
  • 批处理(Batching)是一种优化技术,用于减少向图形处理器(GPU)发送的绘制调用(draw call)数量。每个draw call都是向GPU发送绘制命令的操作,而过多的draw call会增加CPU和GPU的负载,可能导致性能下降。
  • Unity中有静态批处理和动态批处理。静态批处理适用于不会移动或改变的物体,而动态批处理适用于能够共享相同材质的移动物体。这些技术可以减少draw call数量,提高性能。
  • 在这个例子中,两个image会有两次绘制调用drawcall,重叠的部分绘制的两次,可以将两个网格合并成一个网格,最后,在渲染时,只需要发送一个绘制调用drawcall来渲染一个网格,而不是每个image一个绘制调用。这样就大大减少了CPU发送绘制命令的开销,也减少了GPU处理多个绘制调用的开销。

在这里插入图片描述

2. 重要的类

1. MaskableGraphic类继承了IMaskable类

  • 继承MaskableGraphic类的组件都可以被mask进行一个遮挡
    在这里插入图片描述

2. 两种遮罩的实现区别

RectMask2D

在这里插入图片描述
IClipper接口是有一个剪切的方法

public interface IClipper
{
    /// <summary>
    /// Function to to cull / clip children elements.
    /// </summary>
    /// <remarks>
    /// Called after layout and before Graphic update of the Canvas update loop.
    /// </remarks>

    void PerformClipping();
}

Mask

在Mask有一个方法GetModifiedMaterial,用模板缓存实现遮罩

/// Stencil calculation time!
public virtual Material GetModifiedMaterial(Material baseMaterial)
{
    if (!MaskEnabled())
        return baseMaterial;

    var rootSortCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform);
    var stencilDepth = MaskUtilities.GetStencilDepth(transform, rootSortCanvas);
    if (stencilDepth >= 8)
    {
        Debug.LogWarning("Attempting to use a stencil mask with depth > 8", gameObject);
        return baseMaterial;
    }

    int desiredStencilBit = 1 << stencilDepth;

    // if we are at the first level...
    // we want to destroy what is there
    if (desiredStencilBit == 1)
    {
        var maskMaterial = StencilMaterial.Add(baseMaterial, 1, StencilOp.Replace, CompareFunction.Always, m_ShowMaskGraphic ? ColorWriteMask.All : 0);
        StencilMaterial.Remove(m_MaskMaterial);
        m_MaskMaterial = maskMaterial;

        var unmaskMaterial = StencilMaterial.Add(baseMaterial, 1, StencilOp.Zero, CompareFunction.Always, 0);
        StencilMaterial.Remove(m_UnmaskMaterial);
        m_UnmaskMaterial = unmaskMaterial;
        graphic.canvasRenderer.popMaterialCount = 1;
        graphic.canvasRenderer.SetPopMaterial(m_UnmaskMaterial, 0);

        return m_MaskMaterial;
    }

    //otherwise we need to be a bit smarter and set some read / write masks
    var maskMaterial2 = StencilMaterial.Add(baseMaterial, desiredStencilBit | (desiredStencilBit - 1), StencilOp.Replace, CompareFunction.Equal, m_ShowMaskGraphic ? ColorWriteMask.All : 0, desiredStencilBit - 1, desiredStencilBit | (desiredStencilBit - 1));
    StencilMaterial.Remove(m_MaskMaterial);
    m_MaskMaterial = maskMaterial2;

    graphic.canvasRenderer.hasPopInstruction = true;
    var unmaskMaterial2 = StencilMaterial.Add(baseMaterial, desiredStencilBit - 1, StencilOp.Replace, CompareFunction.Equal, 0, desiredStencilBit - 1, desiredStencilBit | (desiredStencilBit - 1));
    StencilMaterial.Remove(m_UnmaskMaterial);
    m_UnmaskMaterial = unmaskMaterial2;
    graphic.canvasRenderer.popMaterialCount = 1;
    graphic.canvasRenderer.SetPopMaterial(m_UnmaskMaterial, 0);

    return m_MaskMaterial;
}
  • 因为两种遮罩实现不同,进行UI优化也不同

3. 渲染部分知识

深度测试

深度测试(Depth Testing)是指用于确定哪些像素应该显示在其他像素之上的一种技术。起到剔除优化的作用。

深度测试的工作原理

通过比较每个像素的深度值(Depth Value)来确定像素是否应该被渲染。深度值是从相机到像素的距离的反映,通常是从0(最近)到1(最远)的范围。具体来说:

  1. 深度缓冲(Depth Buffer):
  • 在渲染每个像素之前,Unity会将每个像素的深度值写入到一个称为深度缓冲(Depth Buffer)的特殊缓冲区中。
  • 深度缓冲是一个与屏幕大小相同的二维数组,每个元素存储与像素位置对应的深度值。
  1. 深度测试的执行:
  • 当一个物体的像素要渲染到屏幕上时,Unity会首先将该像素的深度值与深度缓冲中对应像素的深度值进行比较。
  • 如果当前像素的深度值小于深度缓冲中的深度值(即当前像素更接近相机),则该像素被渲染,并更新深度缓冲。
  • 如果当前像素的深度值大于深度缓冲中的深度值(即当前像素在深度上在后面),则该像素被丢弃,不会渲染到屏幕上。

渲染队列

渲染队列(Rendering Queue)是一个用来管理和排序需要被渲染的物体、几何体或者图形效果的机制。渲染队列的目的是为了优化渲染流程,确保图形处理单元(GPU)以最高效的方式处理和渲染场景中的各个元素。

透明物体在渲染时怎么处理

透明物体在渲染时主要采取从后向前(back-to-front)的渲染顺序。这是因为透明物体不会写入深度缓冲(depth buffer),也就是说它们不会遮挡其他物体,因此渲染的顺序决定了它们如何叠加在一起。

  1. 排序:首先,将所有需要渲染的透明物体按照它们在场景中的深度(通常是距离观察者的距离)进行排序。
  2. 从后向前渲染:按照排序后的顺序,从距离观察者最远的透明物体开始渲染,逐渐向前渲染到距离观察者最近的物体。
  3. 混合:在渲染每个透明物体时,使用Alpha混合(Alpha blending)技术将当前物体的颜色与已经渲染到屏幕上的颜色进行混合。这通常涉及到将当前物体的颜色和Alpha值(表示透明度的值)与屏幕上的颜色和Alpha值进行某种计算,得到新的颜色和Alpha值。
  4. 关闭深度写入:由于透明物体不会写入深度缓冲,因此需要确保在渲染透明物体时关闭深度写入功能,以避免它们错误地遮挡其他物体。
  5. 开启深度测试:虽然透明物体不会写入深度缓冲,但仍然需要开启深度测试来确保它们正确地叠加在其他不透明的物体之上。

通过这种方法,可以确保透明物体在渲染时能够正确地叠加在一起,并产生正确的视觉效果。

为什么透明效果会造成性能问题

透明效果会造成性能问题,主要是因为它们涉及到Alpha混合(Alpha blending)和渲染顺序(通常是从后向前)的处理,这会导致以下几个方面的性能开销:

  1. Overdraw(过度绘制):当一个像素被多次绘制时,就发生了overdraw。对于不透明物体,由于深度测试(depth testing)的存在,只有离观察者最近的物体会被绘制到屏幕上,因此overdraw通常不是问题。但对于透明物体,由于它们不会写入深度缓冲,并且需要按照从后向前的顺序渲染,所以每个透明物体都会与已经绘制在屏幕上的颜色进行混合,这可能导致一个像素被多次绘制和混合。
  2. 排序开销:为了正确渲染透明物体,需要将它们按照从后向前的顺序进行排序。这个排序过程可能涉及到大量的计算,特别是对于动态场景中的大量透明物体。
  3. Alpha混合的计算开销 :Alpha混合是一个相对复杂的计算过程,需要将当前像素的颜色和Alpha值与屏幕上的颜色和Alpha值进行混合。这个过程比简单的不透明渲染要复杂得多,因此会增加GPU的计算负担。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1926298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

成为CMake砖家(2): macOS创建CMake本地文档的app

大家好&#xff0c;我是白鱼。 使用 CMake 的小伙伴&#xff0c; 有的是在 Windows 上&#xff0c; 还有的是在 macOS 上。之前咱们讲了 windows 上查看 cmake 本地 html 文档的方式&#xff0c; 这篇讲讲 macOS 上查看 cmake 本地 html 文档的方法。 1. 问题描述 当使用 CMa…

数模·图论

matlab中图的表示 顶点集权值集的形式 s是源点&#xff0c;t是终点&#xff0c;w是对应的权值 调用graph(s,t,w)作为参数创建图 调用plot函数绘图plot(G,EdgeLabel,G.Edges.Weight,LineWidth,2) 设置x和y的坐标范围set(gca,XTick,[],YTick,[]) s[1 2 3]; t[4 1 2]; w[5 2 6]; …

程序包不存在【java: 程序包org.springframework.boot不存在】

1、问题提示&#xff1a;java: 程序包org.springframework.boot不存在 注意&#xff1a;已经下载好了程序包&#xff0c;就是提示不存在 2、解决办法

一个开源完全免费的无损视频或音频的剪切/裁剪/分割/截取和视频合并工具

大家好&#xff0c;今天给大家分享一款致力于成为顶尖跨平台FFmpeg图形用户界面应用的软件工具LosslessCut。 LosslessCut是一款致力于成为顶尖跨平台FFmpeg图形用户界面应用的软件工具&#xff0c;专为实现对视频、音频、字幕以及其他相关媒体资产的超高速无损编辑而精心打造。…

《后端程序猿 · EasyPOI 导入导出》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

蓝桥杯嵌入式第十五届模拟考试3解析

1 题目 2 程序 /* USER CODE BEGIN PTD */ char buf1[20],buf2[20],buf3[20],buf4[20],buf5[20],buf6[20],buf7[20],buf8[20],buf9[20]; struct keys {int step;int length;int state; }key[5]; int display; double v1,v2; int t; double v1l1.2,v1u2.2,v2l1.4,v2u3.0; dou…

深度学习复盘与论文复现D

文章目录 一、新环境搭建与适应1、easy_install和pip的安装使用2、关于安装包超时的解决方案3、brew安装包安装4、使用新环境运行以前项目5、解决win的pycharm修改内存后无法启动 二、Dataset 数据读取问题1、Lightning Torch 读取数据2、Pytorch的DataLoader数据读取机制3、Py…

Dify中的经济索引模式实现过程

当索引模式为经济时&#xff0c;使用离线的向量引擎、关键词索引等方式&#xff0c;降低了准确度但无需花费 Token。 一.提取函数**_extract** 根据不同文档类型进行内容的提取&#xff1a; def _extract(self, index_processor: BaseIndexProcessor, dataset_document: Data…

力扣经典题目之->移除值为val元素的讲解,的实现与讲解

一&#xff1a;题目 博主本文将用指向来形象的表示下标位的移动。 二&#xff1a;思路 1&#xff1a;两个整形&#xff0c;一个start&#xff0c;一个end&#xff0c;在一开始都 0&#xff0c;即这里都指向第一个元素。 2&#xff1a;在查到val之前&#xff0c;查一个&…

C语言 ——— 将一句英语短句中的单词进行倒置

目录 题目要求 代码实现 题目要求 将一句英语短句中的单词进行倒置&#xff0c;标点符号不倒置 如&#xff1a; 输入&#xff1a;"I like chongqing very much," 输出&#xff1a;"much, very chongqing like I" 代码实现 #include<stdio.h> #i…

c#与欧姆龙PLC通信——如何更改PLC的IP地址

前言 我们有时候需要改变欧姆龙Plc的ip地址,下图有两种更改方式,一种是已知之前Plc设置的Ip地址,还有一种是之前不知道Pl的Ip地址是多少,下面分别做介绍。 1、已知PLC的IP地址的情况下更改地址 假设已知PLC的Ip地址,比如本文中PLC的IP为192.168.1.2,我首先将电脑的IP地…

搭建调用链监控Zipkin和Sleuth

项目环境: win7、jdk8 1、添加依赖&#xff0c;添加了spring-cloud-starter-zipkin会自动导入Sleuth <!--Sleuth&#xff0c;zipkin--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zipkin</…

安卓onNewIntent 什么时候执行

一.详细介绍 onNewIntent 方法 onNewIntent 是 Android 中 Activity 生命周期的一部分。它在特定情况下被调用&#xff0c;主要用于处理新的 Intent&#xff0c;而不是创建新的 Activity 实例。详细介绍如下&#xff1a; 使用场景 singleTop 启动模式&#xff1a; 如果一个 Ac…

python+mysql图书管理系统,谈谈思路及实现代码

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

【链表】算法题(一) ---- 力扣 / 牛客

一、移除链表元素 移除链表中值为val的元素&#xff0c;并返回新的头节点 思路&#xff1a; 题目上这样说&#xff0c;我们就可以创建一个新的链表&#xff0c;将值不为val的节点&#xff0c;尾插到新的链表当中&#xff0c;最后返回新链表的头节点。 typedef struct ListNo…

java《字符串进阶篇》--习题逐语句分析及认识链式编程

一、前言 字符串相关的习题分享&#xff0c;随着学习的深入&#xff0c;应该要多做一些习题来巩固知识点&#xff0c;而不是一味的去学习新的东西。这几天尽可能地去给大家分享一些常用的方法及习题的讲解&#xff0c;希望大家认真观看&#xff0c;每一道题都有对应的分析。基…

GAMMA数据处理(八)

新学习了一个命令&#xff1a; SLC_cat_ScanSAR - Concatenate sequential ScanSAR burst SLC images (Sentinel-1, TSX, RCM...)&#xff0c;做数据拼接的。之前一直没有涉及到拼接问题&#xff0c;就一直没管。如果研究区包含两景SLC&#xff0c;可以拼接成一景。但是不知道…

计算机丢失CH375DLL怎么办,CH375DLL.DLL;计算机找不到CH375DLL怎么办,CH375DLL.DLL

翻遍CSDN&#xff0c;发现的文章不是只有描述不给资源&#xff0c;要不就是资源收费。 真是狗屎啊&#xff1b; 在千辛万苦找到资源后&#xff0c;我决定写一篇&#xff1b; 首先是资源文件下载 我上传的&#xff1a;&#xff08;肯定是0积分&#xff0c;如果收费了告诉我&…

Nuxt.js 错误侦探:useError 组合函数

title: Nuxt.js 错误侦探&#xff1a;useError 组合函数 date: 2024/7/14 updated: 2024/7/14 author: cmdragon excerpt: 摘要&#xff1a;文章介绍Nuxt.js中的useError组合函数&#xff0c;用于统一处理客户端和服务器端的错误&#xff0c;提供statusCode、statusMessage和…

IOT 可编程控制系统

IOT&#xff08;物联网&#xff09;可编程控制系统&#xff0c;如GF-MAXCC等&#xff0c;是一种集成了多种先进技术和功能的智能化控制设备&#xff0c;它能够在物联网系统中发挥关键作用&#xff0c;实现对多种设备的集中管理和控制。具体来说&#xff0c;IOT可编程控制系统的…