【UnityShader入门精要学习笔记】第九章 更复杂的光照(1)——渲染路径

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

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

我的GitHub仓库

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


文章目录

  • 更复杂的光照
    • Unity的渲染路径
  • 前向渲染路径
    • Unity中的前向渲染
    • 顶点照明渲染路径
    • 延迟渲染路径
      • 延迟渲染原理
      • Untiy中的延迟渲染
      • 可访问的内置变量和函数


更复杂的光照

在之前的章节中,我们学习了关于基础光照计算的Shader,之前的场景中往往只有一个光源且光源类型是平行光。但在实际开发过程中,我们往往需要处理更多数目、类型更复杂的光源。本章将会学习实现更复杂的光照,并且还可以得到阴影。

在学习这些之前,我们有必要知道Unity是如何处理这些光源的。当我们在场景里放置了各种类型的光源后,Unity的底层渲染引擎是如何让我们在Shader中访问它们的?

Unity的渲染路径

在Unity中,渲染路径(Rendering Path) 决定了光照是如何应用到UnityShader中的。因此,如果要和光源打交道,则需要为每个Pass指定它们的渲染路径。

在这里插入图片描述
新版后的Rendering Path在Open Editor里找到

在这里插入图片描述

Unity支持多种渲染路径,在2018中可以看到支持一下四种:
在这里插入图片描述
分别为前向渲染路径(Forward Rendering Path)、延迟渲染路径(Deferred Rendering Path)和顶点照明渲染路径(Vertex Lit Rendering Path) (其中Legacy Deferred指的是旧版中遗留的延迟渲染路径,用于兼容旧版程序的,顶点照明渲染路径的UntiyShader已经被抛弃,但仍然兼容)

大多数情况下,一个项目只用一种渲染路径,因此我们可以为整个项目设置渲染时的渲染路径。但有时我们也希望使用多种渲染路径,通常我们会在摄像机设置中对渲染路径进行设置:

在这里插入图片描述
使用setting代表使用项目默认设置的渲染路径。如果当前显卡不支持该渲染路径,则会自动启用更低一级的渲染路径,例如不支持延迟渲染时会自动启用前向渲染。

完成了渲染路径的设置之后,我们就能在Pass中使用标签来指定Pass使用的渲染路径了。不同的渲染路径可能会包含多种标签设置,例如之前shader中的标签:

Tags{"LightMode" = "ForwardBase"}

标签指明了使用前向渲染路径中的ForwardBase路径,而前线渲染还有一种路径叫做ForwardAdd ,如下表所示:

在这里插入图片描述
虽然现在看不懂这些标签的含义,只需明白使用渲染路径标签设置,我们为Pass指定了渲染路径,如果没有指定,则可能一些光照变量不会被正确赋值,可能计算出错误的效果。(例如之前说过ForwardBase会指定_LightColor0,但如果光源较多则可能出错)


前向渲染路径

前向渲染路径是最常用的一种渲染路径。每进行依次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息,一个是颜色缓冲区,一个是深度缓冲区。

深度缓冲判断一个图元是否可见(深度测试),如果可见则更新颜色缓冲区的颜色值。下列伪代码描述了前向渲染的大致过程:
在这里插入图片描述
我们会逐图元,逐片元,在每个片元着色器中逐像素(或者逐顶点)地进行光照计算。对于每个逐像素光照都需要进行一次上述的完整渲染过程,如果一个物体在多个逐像素光源影响的范围内,就需要执行多个逐像素Pass,然后在帧缓冲中将光照结果混合起来得到最终的颜色值。

如果场景中又N个物体,而每个物体受M个光源影响,那么场景渲染就需要N*M个Pass。为了避免过多的渲染Pass,渲染引擎通常会限制每个物体的逐像素光照的数目。

Unity中的前向渲染

一个pass不仅仅可以用来计算逐像素光照,也可以计算逐顶点光照。这取决于光照计算的流水线阶段以及计算时使用的数学模型。

当渲染物体时,unity会计算哪些光源照亮了它以及这些光源照亮物体的方式。

在Unity中,前向渲染路径有3种处理渲染方式:逐顶点处理,逐像素处理,球谐函数(Spherical Harmonics ,SH)处理

在这里插入图片描述
决定一个光源使用哪种处理模式取决于它的类型和渲染模式。光源类型指光源是平行光还是点光源等其他类型的光源,而光源的渲染模式需要指定是否为重要的光源。如果是Important的光源,那么Unity就会对这个光源渲染Pass进行逐像素处理。越重要的当然需要越精细。

在前向渲染时,当我们渲染也给物体,Unity会根据场景中各个光源的设置以及这些光源对物体的影响程度(例如距离物体的远近,光源强度等)来对光源进行重要度排序,越重要的渲染越精细。

根据排序,一定数量的光源会按照逐像素方式处理,最多4个光源按照逐顶点方式处理,其余的使用SH处理。Unity的判断规则如下:

  • 场景中最亮的平行光总是逐像素的
  • 渲染模式是Not Important的光源,会逐顶点或者SH处理
  • 渲染模式是Important的光源会逐像素处理
  • 如果根据以上规则得到的逐像素处理的光源数量小于Quality Setting中的逐像素光源数量,那么会有更多的光源以逐像素进行渲染

光照计算都是在Pass中进行的。在前向渲染中又Base Pass 和Additional Pass两种。这两种Pass进行的标签和渲染设置如图所示:

在这里插入图片描述

  • 上图中提到的例如**#pragma multi_compile_fwdbase** 和 #pragma multi_compile_fwdbase 这样的预编译指令,可以为Pass生成对应的Shader variant(变体,变种),用于处理不同条件下的逻辑渲染,例如是否使用LightMap,使用哪种光源类型等。只有设置正确的预编译指令,我们才能在相关Pass中得到一些正确的光照变量。
  • 对于前向渲染来说,一个Unity Shader通常会定义一个Base Pass(当然也可以定义多次,例如需要双面渲染时)以及一个Additional Pass。Base Pass通常用于计算一个最重要的逐像素光源,该Pass只执行一次,而Additional Pass会计算多种光源的逐像素光照,每个光源都会执行一次该Pass。
  • Base Pass中渲染的平行光默认支持阴影,而Additional Pass中渲染的光源在默认情况下是没有阴影效果的,即使我们在它的Light组件中设置了Shadow Type。我们可以使用#pragma multi_compile_fwdadd_fullshadows来替代,从而为点光源和聚光灯开启阴影效果,但需要在Unity内部使用更多的shader variants
  • 环境光和自发光也是在BasePass中计算的,因为对于一个物体来说我们只希望计算一次环境光和自发光,而如果我们想要在Additional Pass中计算这两种光照就会造成叠加多次环境光和自发光。
  • 在Additional Pass的渲染设置中,我们还开启和设置了混合模式,因为Additional Pass会计算多次,我们希望每个Pass可以在帧缓存中与上一次的光照结果进行叠加,从而得到最终有多个光照叠加的混合效果。如果不开启Blend就会导致缓存被覆盖,通常情况下我们选择混合模式Blend One One

顶点照明渲染路径

顶点照明渲染路径使用逐顶点的方式来计算光照,对硬件配置要求最少,运算性能最高,得到的效果最差。且不支持逐像素渲染才能得到的效果,例如阴影、法线映射、高精度的高光反射等。

实际上,顶点照明渲染路径仅仅只是前向渲染路径的一个子集。也就是说,所有可以在顶点照明渲染路径中实现的功能都可以在前向渲染路径中完成。且顶点照明渲染路径只能使用逐顶点相关的变量,不可使用逐像素照明变量。

所以顶点照明渲染完全可以被逐像素照明渲染代替。虽然文中花了一些笔墨来介绍,但是暂且先不深入了解了。


延迟渲染路径

前向渲染的问题是:当场景中包含大量实时光照时,前向渲染的性能会急剧下降。例如某个区域放置了多个光源,而这些光源相互影响的区域又互相重叠,就会导致重叠区域中的每个物体的逐像素平行光照结果都要计算多次Pass。从而导致这个物体被重复渲染,很多计算实际上是多余的。

延迟渲染是一种古老的渲染方法,由于前向渲染可能造成的问题而被再次使用。除了前向渲染使用的颜色缓冲和深度缓冲之外,延迟渲染还会利用额外的缓冲区,这些缓冲区被称为G-buffer,(G即Germetry)。G缓冲区包含了几何体的表面的其他信息(通常是离摄像机最近的表面),例如该表面的法线、位置、用于光照计算的材质属性等。

延迟渲染原理

延迟渲染主要包含了两个Pass,第一个Pass中我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现的。若一个片元是可见的,我们就把它的相关信息存储在G缓冲区中。然后,在第二个Pass中,我们利用G缓冲区的各个片元信息,例如表面法线、视角方向、漫反射系数等进行真正的光照计算。

在这里插入图片描述
可以看出延迟渲染使用的Pass数量通常是两个,和场景中光源的数量无关。因此延迟渲染的效率不依赖于场景的复杂度,而和我们使用的屏幕空间的大小有关,因为所有的信息都存储在缓冲区中,缓冲区可以视为一张张的2D图形,所有计算都是在图像空间中进行的。


Untiy中的延迟渲染

在Untiy中有两种延迟渲染路径,新版的和遗留的。如果游戏中使用了大量的实时光照,那么我们可能希望选择延迟渲染路径,但这种路径需要一定的硬件支持。

旧版的延迟渲染路径不支持基于物理的Standrad Shader。延迟渲染的使用情况是:场景中光源较多、使用前向渲染会导致性能瓶颈的情况下(例如实时光照)下使用。但是延迟渲染也存在一些缺点:

  • 不支持真正的抗锯齿
  • 不能处理半透明物体
  • 对显卡有一定要求,显卡必须支持MRT,Shader Model 3.0及以上,深度渲染纹理以及双面的模板缓冲

当使用延迟渲染时,Unity要求我们提供两个Pass:

  • 第一个Pass用于渲染G缓冲,在这个Pass中,我们会将物体的漫反射颜色,高光反射颜色、平滑度、法线、自发光和深度等信息渲染到屏幕空间的G缓冲区中,对于每个物体来说,该Pass只会执行一次
  • 第二个Pass用于计算真正的光照模型,这个Pass会使用上一个Pass中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中。
    在这里插入图片描述
    如图所示是《彩六围攻》中使用的GBuffer缓冲区作为一个示例,RT指的是渲染目标(Render Targets) ,不仅仅是颜色值,甚至速度值,所有数据都能被存放到GBuffer中。

在Unity的GBuffer中,一般会包含以下几个渲染目标(Unity似乎只保存颜色值,因此被称为渲染纹理):

  • RT0:格式ARGB32,RGB通道用于存储漫反射颜色Diffuse,A通道没有使用
  • RT1:格式ARGB32,RGB通道存储高光反射颜色Specular。A通道用于存储高光反射的指数部分Gloss
  • RT2:格式ARGB2101010,RGB通道用于存储法线,A通道没有使用
  • RT3:格式ARGB32(非HDR)或ARGBHalf(HDR),用于存储自发光+lightMap +反射探针(reflection probes)

当在第二个Pass中计算光照时,默认仅可使用Unity内置的Standrad光照模型,若想要使用其他光照模型,就需要替换掉原有的Internal-DeferredShading.shader文件。(URP的延迟渲染好像还在开发中)

可访问的内置变量和函数

在这里插入图片描述

Unity官方文档中给出了四种渲染路径的比较。总的来说,我们需要根据游戏发布的目标平台来选择渲染路径。如果当前显卡不支持所选渲染路径,那么Unity会自动使用比其低一级的渲染路径。


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

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

相关文章

【每日一题】元素和最小的山形三元组 I

文章目录 Tag题目来源解题思路方法一:预处理枚举 写在最后 Tag 【预处理枚举】【数组】【2024-03-29】 题目来源 2908. 元素和最小的山形三元组 I 解题思路 方法一:预处理枚举 思路 朴素的方法是枚举所有可能的 山形三元组,找出最小的元…

解决npm init vue@latest证书过期问题:npm ERR! code CERT_HAS_EXPIRED

目录 一. 问题背景 二. 错误信息 三. 解决方案 3.1 临时解决办法 3.2 安全性考量 一. 问题背景 我在试图创建一个新的Vue.js项目时遇到了一个问题:npm init vuelatest命令出现了证书过期的错误。不过这是一个常见的问题,解决起来也简单。 二. 错误…

Rust编程(五)终章:查漏补缺

闭包 & 迭代器 闭包(Closure)通常是指词法闭包,是一个持有外部环境变量的函数。外部环境是指闭包定义时所在的词法作用域。外部环境变量,在函数式编程范式中也被称为自由变量,是指并不是在闭包内定义的变量。将自…

小狐狸JSON-RPC:钱包连接,断开连接,监听地址改变

detect-metamask 创建连接,并监听钱包切换 一、连接钱包,切换地址(监听地址切换),断开连接 使用npm安装 metamask/detect-provider在您的项目目录中: npm i metamask/detect-providerimport detectEthereu…

主从复制与读写分离

前言: 在企业应用中,成熟的业务通常数据量都比较大,单台MySQL在安全性、高可用性和高并发方面 都无法满足实际的需求? 配置多台主从数据库服务器以实现读写分离 一 主从复制的工作原理 ①Master节点将数据的改变记录成二进制…

机器学习算法的另一个分支-贝叶斯算法原理(贝叶斯要解决什么问题)

目录 一、贝叶斯简介 二、贝叶斯要解决的问题 三、例子(公式推导) 四、实例 1. 拼写纠正实例 2. 垃圾邮件过滤实例 一、贝叶斯简介 1. 贝叶斯:英国数学家。1702年出生于伦敦,做过神甫。贝叶斯在数学方面主要研究概率论.对于…

使用unplugin-auto-import页面不引入api飘红

解决方案:. tsconfig.json文件夹加上 {"compilerOptions": {"target": "ES2020","useDefineForClassFields": true,"module": "ESNext","lib": ["ES2020", "DOM", &q…

【2024系统架构设计】案例分析- 4 嵌入式

目录 一 基础知识 二 真题 一 基础知识 1 基本概念 ◆系统可靠性是系统在规定的时间内及规定的环境条件下,完成规定功能的能力,也就是系统无故障运行的概率。或者,可靠性是软件系统在应用或系统错误面前,在意外或错误使用的情况下维持软件系统的功能特性的基本能力。

Discuz采集发布插件

Discuz(简称DZ)是一款知名的开源论坛系统,广泛应用于各类网站社区。对于许多站长来说,保持论坛内容的更新是一项挑战,特别是在内容量庞大的情况下。为了解决这个问题,有一类特殊的插件是用于在Discuz论坛中…

论文阅读-Policy Optimization for Continuous Reinforcement Learning

摘要 我们研究了连续时间和空间环境下的强化学习( RL ),其目标是一个具有折扣的无限时域,其动力学由一个随机微分方程驱动。基于连续RL方法的最新进展,我们提出了占用时间(专门针对一个折现目标)的概念,并展示了如何有效地利用它…

使用mysql官网软件包安装mysql

确定你的操作系统,我的是Centos myqsl 所有安装包的地址:https://repo.mysql.com/yum/ 如果你是使用rpm安装你可以到对应的版本里面找到对应的包。 mysql 发行包的地址:http://repo.mysql.com/ 在这里你可以找到对应的发布包安装。 这里使用y…

Windows下安装使用Squirrel

引言 SQuirrel SQL Client是一个用Java写的数据库客户端,用JDBC统一数据库访问接口以后,可以通过一个统一的用户界面来操作MySQL PostgreSQL MSSQL Oracle等等任何支持JDBC访问的数据库。使用起来非常方便。而且,SQuirrel SQL Client还是一个典型的Swing程序。 如果您的工作…

git:git rm --cached和git rm -f和git restore --staged的区别(附带详细步骤测试)和git diff比较本地分支和远程分支的区别(细分到文件/文件)

git rm --cached和git rm -f和git restore --staged的区别 当试图删除一个已经git add在暂存区的文件,我们使用 git rm --cached:从暂存区中移除,但保留在工作区中,且工作区中的文件内容在执行命令前需要还原到最后一次git add的…

统信 UOS V20 一键安装 Oracle 11GR2(231017)单机版

Oracle 一键安装脚本,演示 统信 UOS V20 一键安装 Oracle 11GR2(231017)单机版过程(全程无需人工干预):(脚本包括 ORALCE PSU/OJVM 等补丁自动安装) ⭐️ 脚本下载地址:…

100 个 Kotlin 面试问题及答案(其二)

尤其是在Android开发中,Kotlin已经成为一种流行的编程语言。为了帮助您在 Kotlin 面试中取得成功,我们为您简化了 100 个最常见的面试问题。本指南涵盖了广泛的主题,包括基本语言概念和高级功能。每个问题都附有简单的答案和实际示例&#xf…

Webpack常见插件和模式

目录 目录 目录认识 PluginCleanWebpackPluginHtmlWebpackPlugin自定义模版 DefinePlugin的介绍 ( 持续更新 )Mode 配置 认识 Plugin Loader是用于特定的模块类型进行转换; Plugin可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等 …

Voodoo中国区刘毅:全球爆款休闲游戏的创意选品与研发发行 | TopOn观察

10月28日,由TopOn联合罗斯基主办的“游戏赛道新机会”主题沙龙在成都举办。活动邀请了多位国内外知名公司及游戏爆款产品的负责人分享,分别从各自的方向及经验出发,以数据、案例、产品分析、行业趋势等多个维度,为行业从业者带来独…

DataX-Oracle新增writeMode支持update

目录 前言 第一步下载源码 第二步修改源码 1、Oraclewriter 2、WriterUtil 2.1、修改getWriteTemplate方法 2.2、新增onMergeIntoDoString与getStrings方法 3、CommonRdbmsWriter 3.1、修改startWriteWithConnection 3.2、修改doBatchInsert 3.3、修改fillPreparedStatem…

QT6实现音频输出方法

一.QT6音频调用及与QT5的区别 1.音频输入 QAudioSource代替QAudioInput类 QAudioSource类提供了一个接口&#xff0c;用于从音频输入设备接收音频数据。 Header: #include <QAudioSource> qmake: QT multimedia 2.音频输出 QAudioSink代替QAudioOutput类 QAudioSi…

硬件10、从网站获取封装

百度搜索IC封装网或者网址https://www.iclib.com/ 搜索想要的器件&#xff0c;直接下载他的原理图库和封装库