【UnityShader入门精要学习笔记】第十六章 Unity中的渲染优化技术 (下)

在这里插入图片描述
本系列为作者学习UnityShader入门精要而作的笔记,内容将包括:

  • 书本中句子照抄 + 个人批注
  • 项目源码
  • 一堆新手会犯的错误
  • 潜在的太监断更,有始无终

我的GitHub仓库

总之适用于同样开始学习Shader的同学们进行有取舍的参考。


文章目录

  • 减少需要处理的顶点数目
    • 优化几何体
    • 模型的LOD技术
    • 遮挡剔除技术
  • 减少需要处理的片元数目
    • 控制绘制顺序
    • 小心透明物体
    • 减少实时光照和阴影
  • 节省带宽
    • 减少纹理大小
    • 使用分辨率缩放
  • 减少计算复杂度
    • Shader 的LOD技术
    • 代码方面的优化


上一节我们描述了如何通过减少DrawCall来减轻CPU的资源调度压力。本章中我们将从其他方面来优化性能:

减少需要处理的顶点数目

优化几何体

3D游戏制作离不开3D模型。由于渲染时需要逐顶点逐面片渲染,因此优化3D模型是很重要的。

一般的原则是优化模型的网格结构,减少模型中的顶点数量(面数)

有时,Unity中显示的顶点数量会超过模型本身的顶点数量。这是由于在GPU看来,有时为了计算的需要,会将一个顶点拆分为两个顶点,主要目的有两个:一个是为了分离纹理坐标(uv splits),另一个是为了产生平滑的边界(smoothing splits)

它们的本质其实是对于GPU来说的,顶点的每一个属性和顶点之间必须是一对一的关系。例如一个立方体,它的六个面之间有一些相同的顶点,但是这些顶点相对于每个面的纹理坐标就不同了,因此就会拆分为多个不同纹理坐标的顶点,平滑边界也是类似的。因此一个顶点可能会对应多个法线信息和切线信息。

因此我们需要尽可能减少顶点数量,一个建议是——移除不必要的硬边以及纹理衔接,避免边界平滑和纹理分离。


模型的LOD技术

另一个减少顶点数目的方法是使用LOD技术,LOD技术的原理是为模型准备好几套不同细节程度的模型(纹理),然后根据摄像机和物体间的距离选择为模型加载的LOD层级,Unity就会自动使用对应等级的模型。

一般离得越远则细节程度越低,离得越近细节程度越高


遮挡剔除技术

遮挡剔除就是Occlusion Culling,就是剔除那些我们看不到的物体(面),避免计算不必要的资源。

像摄像机自带的Culling效果,对层级手动设置的Culling效果,包括Shader的背面和正面剔除都是出于这一目的的。

注意区分摄像机的遮挡剔除和视锥体剔除(Frustum Culling),视锥体剔除是剔除不在摄像机视锥内的物体,而遮挡剔除是剔除摄像机视锥内看不见的物体,其原理是用一个虚拟摄像机来遍历场景,并识别那些物体是可见的,哪些是不可见的。

LOD技术和遮挡剔除技术可以同时减少CPU和GPU的负荷,CPU可以提交更少的DrawCall,而GPU需要处理的顶点和面数也少了。


减少需要处理的片元数目

另一个造成GPU的性能瓶颈的原因是需要处理过多的片元。除了我们之前说的减少模型网格顶点数减少片元外,这部分的重点更在于减少OverDraw——即同一个像素的重复绘制。

想象一下,有一个B物体挡在了A物体的前面。若我们先渲染A物体,再渲染B物体,那么同一个像素被渲染了两次,显然A物体是没必要渲染的,就造成了OverDraw,这时我们可以用深度测试来避免这一情况

在这里插入图片描述
我们可以再Scene视图下查看overdraw的情况,来判断物体之间的遮挡。

控制绘制顺序

为了避免OverDraw ,一个重要的优化策略就是控制绘制顺序。由于深度测试的存在,如果我们可以保证物体都是从前往后绘制的,就可以最大限度减少OverDraw。这是因为,在后面绘制的物体由于无法通过深度测试因此不会重复渲染。

在Unity中,那些渲染队列数目小于2500的(如BackGround ,Geometry,AlphaTest)的对象都被认为是不透明的(Opaque)的物体,不透明的物体通常是从前往后绘制的。

而其他队列例如(“Transparent”,“Overlay"等)则是从后往前绘制的,因为这些队列常常是透明度渲染的,这些渲染就比较麻烦,为了正确的渲染效果我们往往还需要手动控制渲染顺序。

在开发中,我们考虑到摄像机下一些人或物在屏幕上的渲染顺序,为它们设置不同的渲染队列,将节省很多渲染时间。


小心透明物体

对于半透明物体来说,由于它们没有开启深度写入,因此如果想要得到正确的渲染结果,必须从后往前渲染,因此为了正确的渲染效果,半透明物体一定会产生overdraw的。

因此,如果屏幕上存在大量半透明物体或者粒子效果,甚至多层半透明效果相互堆叠的情况,就会有大量的OverDraw,这是我们需要避免的。特别是GUI对象的渲染常常要用到半透明效果。

对于上述的情况,我们可以减少视窗中GUI的面积以减少OverDraw的像素。也可以把GUI的绘制和三维场景的绘制交给不同的摄像机,并且三维摄像机的视角范围尽量不要和GUI的相互重叠。


减少实时光照和阴影

实时光照和阴影的计算是很昂贵的,我们之前讲光照的时候说过,实时光照的渲染(特别不属于主光源的部分,例如点光源)会调用每个照射到的物体上的Pass。导致Pass一下子增多了。

例如一个场景如果包含了3个逐像素的光照,而且使用了逐像素的Shader,那么很有可能将DrawCall的数量提高3倍。

并且无论是静态批处理还是动态批处理,额外的逐像素光照pass都会导致中断批处理!

当然游戏是少不了光照的,少用实时光不代表不用光照效果,我们往往会为模型提前烘焙好一张光照纹理和阴影纹理,根据光照方向来进行计算采样来代替实时光照效果。只有某些动态物体才会使用实时光照


节省带宽

大量使用未经压缩的纹理以及使用过大的分辨率都会造成由于带宽引发的性能瓶颈。

减少纹理大小

使用纹理图集atlas可以帮助我们减少DrawCall的数量(因为图集中的所有纹理都可以通过一次DrawCall提交),除此之外纹理大小也是一个需要考虑的问题。所有纹理的长宽比最好是正方形,而且长宽值最好是2的整数幂,这样很多的优化策略才能发挥最大的作用。

除此之外,我们还可以用多级渐远技术和纹理压缩来优化纹理,当勾选了Generate Mip Maps则生成多级渐远纹理,和LOD技术相似,根据远近来选择渲染的纹理。在GUI和2D游戏中使用的纹理等,都应该为纹理生成相应的多级渐远纹理。

纹理压缩同样可以节省带宽,不同的GPU架构可能有不同的纹理压缩格式,除了有时我们需要纹理特别清晰时(例如GUI)我们不希望对纹理进行压缩。


使用分辨率缩放

过大的屏幕分辨率和糟糕的GPU也会造成带宽压力大, 在特定的设备上,我们还需要对程序指定分辨率缩放。


减少计算复杂度

Shader 的LOD技术

Shader的LOD技术和模型的LOD技术类似,其原理是当Shader的LOD值小于当前的LOD值,该shader才会被使用,否则使用了该Shader的物体不渲染。

在未设置LOD值的Shader中,LOD是无限大的,也就是无论如何都使用。在设定了LOD值之后,我们若想要剔除部分复杂计算的Shader就可以通过设置LOD值来剔除,方法是使用Shader.maximumLODShader.globalMaximumLOD来设定允许的最大LOD


代码方面的优化

通常来说,游戏需要计算的数量排序是:游戏对象数量<顶点数量<像素数量。因此我们应当尽可能将操作放在游戏对象上或者顶点上。

例如之前我们采样坐标时放在了顶点着色器上而非片元着色器,就大大提高了计算性能。

(以下说的优化策略在某些设备上不成立,这很正常)

  1. 尽量使用低精度的浮点数进行运算。最高精度的float类型用于存储顶点坐标等变量,但是像颜色值,归一化值这类范围为[0,1]的我们就会使用fixed,half通常使用与一些标量,纹理坐标等变量,计算速度大概是float的两倍。尽量避免不同精度间的值转换。(特别考虑别在片元着色器中使用高精度计算)
  2. 对于大多数的GPU,在数据传递阶段,例如用v2f将数据从顶点着色器传递到片元着色器的时候,我们尽可能使用少的插值变量,例如可以用一个fixed4存储,就不用两个fixed2。(有些平台,例如PowerVR例外)
    3.尽量不使用全屏的屏幕后处理效果,尽量把多个特效合并在一个Pass中
  • 尽量别用if分支语句和for循环语句
  • 尽量避免sin,tan,pow,log等复杂数学运算,我们可以用查找表来代替
  • 尽量不要使用discard

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构复习指导之交换排序(冒泡排序,快速排序)

目录 交换排序 复习提示 1.冒泡排序 1.1基本思想 1.2算法代码 1.3性能分析 2.快速排序 2.1基本思想 2.2算法代码 2.3性能分析 交换排序 复习提示 所谓交换&#xff0c;是指根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置。 基于交换的排序算法很…

ROS无人机追踪小车项目开发实战 | 第四届中国智能汽车创新大会圆满结束

2024年5月26日&#xff0c;阿木实验室在深圳第四届中国智能汽车创新大会上&#xff0c;开展的《Prometheus开源平台-ROS无人机追踪小车项目开发实战课》圆满结束。 该实战课从初学者的角度出发&#xff0c;通过实践性讲解和开发&#xff0c;使开发者们系统地学习了硬件系统架构…

vue3使用vue3-print-nb打印

打印效果 1.下载插件 Vue2.0版本安装方法 npm install vue-print-nb --saveVue3.0版本安装方法&#xff1a; npm install vue3-print-nb --save2.main.js引入 vue2引入 import Print from vue-print-nb Vue.use(Print)vue3引入 import print from vue3-print-nb // 打印…

在Windows安装Flutter

一、安装 Android Studio 官网&#xff1a; 下载 Android Studio 和应用工具 - Android 开发者 | Android Developers 教程&#xff1a;Android Studio 安装配置教程 - Windows(详细版)-CSDN博客 Flutter 官网&#xff1a;Windows | Flutter 中文文档 - Flutter 中文开发…

JVM学习-详解类加载器(一)

类加载器 类加载器是JVM执行类加载机制的前提 ClassLoader的作用 ClassLoader是Java的核心组件&#xff0c;所有的Class都是由ClassLoader进行加载的&#xff0c;ClassLoader负责通过各种方式将Class信息的二进制数据流读入JVM内部&#xff0c;转换为一个与目标类型对应的ja…

打开C语言常用的内存函数大门(三) —— memset()函数(内含讲解用法和模拟实现)

文章目录 1. 前言2. memset函数2.1 memset函数原型2.2 memset函数参数的介绍2.3 memset函数的使用演示 3. memset函数的模拟实现4. 总结 1. 前言 哈喽&#xff0c;我们又见面了。通过前面两个内存函数(memcpy、memmove函数)讲解的锤炼后&#xff0c;对如何解析一个自己从来没有…

V90PN伺服驱动器支持的标准报文介绍

1、V90 PN总线伺服通过FB285实现速度控制 V90 PN总线伺服通过FB285速度控制实现正弦位置轨迹运动(解析法和数值法对比测试)-CSDN博客文章浏览阅读448次。上面的位置函数有明确的解析函数&#xff0c;这里我们可以利用解析法求解其导数(微分),当然我们这里借助第三方数学软件求…

【LIN】STM32新能源汽车LIN通信实现过程

【LIN】STM32新能源汽车LIN通信实现过程 文章目录 前言一、软件二、接线图三、硬件原理图四、上位机五、PICO示波器串行解码1.软件中的LIN波特率设置-192002.PIC设置3.PIC串行解码 六.引用总结 前言 【电机控制】直流有刷电机、无刷电机汇总——持续更新 使用工具&#xff1a;…

opencv笔记(13)—— 停车场车位识别

一、所需数据介绍 car1.h5 是训练后保存的模型 class_directionary 是0&#xff0c;1的分类 二、图像数据预处理 对输入图片进行过滤&#xff1a; def select_rgb_white_yellow(self,image): #过滤掉背景lower np.uint8([120, 120, 120])upper np.uint8([255, 255, 255])#…

单片机原理及应用复习

单片机原理及应用 第二章 在AT89S52单片机中&#xff0c;如果采用6MHz晶振&#xff0c;一个机器周期为 2us 。 时钟周期Tocs1focs 机器周期 Tcy12focs 指令周期&#xff1a;一条指令所用的时间&#xff0c;单字和双字节指令一般为单机器周期和双机器周期。 AT89S5…

Unity2D横版摄像机跟随

在Unity2D横版游戏中&#xff0c;摄像机跟随是一个非常重要的功能。一个流畅的摄像机跟随系统可以让玩家更好地沉浸在游戏世界中。本文将介绍如何在Unity中实现2D横版摄像机跟随&#xff0c;并分享一些优化技巧。 一、准备工作 在开始实现摄像机跟随之前&#xff0c;请确保您…

chatgpt之api的调用问题

1.调用api过程中&#xff0c;出现如下报错内容 先写一个测试样例 import openaiopenai.api_key "OPEN_AI_KEY" openai.api_base"OPEN_AI_BASE_URL" # 是否需要base根据自己所在地区和key情况进行completion openai.ChatCompletion.create(model"g…

python对文本操作,生成可执行文件

.exe文件主要包含pingmianF.py文件和read_inp_auto.py文件 实现效果 代码 read_inp_auto.py #-*- coding: utf-8 -*- import re import sys import os import os.path import time import pingmianF from pingmianF import vector import numpy as np from tkinter import me…

61. UE5 RPG 实现敌人近战攻击技能和转向攻击

在前面&#xff0c;我们实现了敌人的AI系统&#xff0c;敌人可以根据自身的职业进行匹配对应的攻击方式。比如近战战士会靠近目标后进行攻击然后躲避目标的攻击接着进行攻击。我们实现了敌人的AI行为&#xff0c;但是现在还没有实现需要释放的技能&#xff0c;接下来&#xff0…

VBA字典与数组第十五讲:多行多列数组与同列数单行数组间的运算规则

《VBA数组与字典方案》教程&#xff08;10144533&#xff09;是我推出的第三套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;字典是VBA的精华&#xff0c;我要求学员必学。7.1.3.9教程和手册掌握后&#xff0c;可以解决大多数工作中遇到的实际问题。…

开源模型应用落地-LangSmith试炼-入门初体验-监控和自动化(五)

一、前言 在许多应用程序中&#xff0c;特别是在大型语言模型(LLM)应用程序中&#xff0c;收集用户反馈以了解应用程序在实际场景中的表现是非常重要的。 LangSmith可以轻松地将用户反馈附加到跟踪数据中。通常最好提供一个简单的机制(如赞成和反对按钮)来收集用户对应用程序响…

Vue3中的常见组件通信之props和自定义事件

Vue3中的常见组件通信 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs4. 默认…

【计算机毕业设计】331基于微信小程序的家庭财务管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Linux——多线程(一)

一、线程的概念 1.1线程概念 教材中的概念&#xff1a; (有问题?) 线程是进程内部的一个执行分支&#xff0c;线程是CPU调度的基本单位 之前我们讲的进程&#xff1a; 加载到内存中的程序&#x…

数据库与缓存⼀致性⽅案

数据库与缓存⼀致性⽅案 1、背景2、数据⼀致性⽅案设计3、数据⼀致性⽅案流程图4、关键代码4.1、 处理数据⼀致性的消息队列⼊⼝4.2、数据⼀致性配置的常量信息 1、背景 现有的业务场景下&#xff0c;都会涉及到数据库以及缓存双写的问题&#xff0c;⽆论是先删除缓存&#xf…