【技术美术图形部分】关于前向渲染和延迟渲染

学习参考

【技术美术百人计划】图形 3.4 延迟渲染管线介绍

《Unity Shader 入门精要》 


1 Unity的渲染路径

关于渲染路径,我在图形渲染管线1.0中就提过了,但只是初步的了解了渲染路径有前向渲染、延迟渲染、Forward+等等,也了解到了前向渲染做了很多无效渲染,难以支持过多光源;延迟渲染可以支持大量的实时光照,基于缓存,因此对空间的要求也比前向渲染高。

这一篇博客我们再在Unity中了解一下这两种渲染路径里面的门道,同时自己上手看看前向渲染和延迟渲染在Unity中的对比效果。

1.1 设置渲染路径的2种方法

Unity中可以给当前项目设置一个总体的渲染路径,如Project Settings -> Graphics:

也可以给不同的摄像机设置不同的渲染路径,这个就在每个摄像机的Inspector窗口设置,可以选择与Graphics Settings同步,也可以选择Forward/Deferred等等:

还需要知道,Camera的Rendering Path设置是优先于整个项目的设置的。

1.2 指定Pass的渲染路径

在之前的实践中已经尝试过为每个Pass设置LightMode标签,例如:

Pass {Tags {"LightMode"="ForwardBase"}
}

表示当前Pass使用的是前向渲染路径中的ForwardBase路径。

Pass还可以设置的LightMode标签类型有:

Tags解释
Always当前Pass总是会被渲染,但不会计算人和光照
ForwardBase前向渲染,该Pass会计算环境光、最重要的平行光、逐顶点/SH光源和Lightmaps
ForwardAdd前向渲染,该Pass会计算额外的逐像素光源,每个Pass对应一个光源
Deferred延迟渲染,该Pass会渲染G-buffer
ShadowCaster把物体的深度信息传递给阴影映射纹理(shadowmap)或一张深度纹理中
PrepassBase遗留的延迟渲染,该Pass会渲染法线和高光反射的指数部分
PrepassFinal用于遗留的延迟渲染,该Pass通过合并纹理、光照和自发光来渲染得到最后的颜色
Vertex/VertexLMRGBM/VertexLM用于遗留的顶点照明渲染

2 前向渲染

2.1 原理

前向渲染是最常用的一种渲染路径,原理也通俗易懂:首先利用深度缓存决定当前渲染对象的每个图元的每个片元是否可见,如果可见再计算光照结果并储存进帧缓存中,如下的伪代码展示了前向渲染的大概流程:

Pass {for (each primitive in this model) {for (each fragment covered by this primitive) {if(failed in depth test) {discard; //没通过深度测试,则该片元不可见} else { //该片元可见,可继续进行光照计算float4 color = Shading(...);//更新帧缓冲,写入到颜色缓冲中writeFrameBuffer(fragment, color);}}}
}

2.2 Unity中如何限制光照数目?

我们讨论过,如果一个物体在多个光源的影响范围内,那肯定要执行很多次Pass,每个Pass都计算一个光照结果,最后混合所有的结果得到最终的颜色值。大量的逐像素光照会带来大量的Pass,为了节省开销,引擎通常会限制每个物体的逐像素光照数目

Unity中,Project Settings -> Quality -> Pixel Light Count对逐像素光照数目做了限制,默认为4,意味着一个物体可以接受除了场景中最亮的平行光外的4个逐像素光照。

2.3 三种处理光照的方式

渲染一个物体时,Unity会计算哪些光源照亮了它,以及计算这些光源照亮该物体的方式。处理光源照亮物体的方式有3种:逐顶点处理逐像素处理球谐函数(Spherical Harmonics, SH)处理。

  • 逐顶点和逐像素我在【Unity Shader】实现基础光照模型中就已经尝试了
  • 关于球谐函数,它是相对于逐像素和逐顶点效率更高的、一种模拟光照的计算方式。大概去学习了一下,发现跟之前101讲的BRDF的辐射度量学只是有重合的点,准备之后再进行系统的了解,所以这里先挖个坑,不做过多的介绍~

2.3.1 光源的渲染模式和类型

我们已经知道了有三种处理光照的方式,下一步肯定就是考虑Unity是通过什么判断?答案是——通过设置光源的渲染模式(Render Mode)和类型(Type)来实现的,二者都可以在光源Light的Inspector窗口设置:

  •  RenderMode——有Auto/Important/Not Important三个选项
  • Type——即光源类型,spot/point/directional/area四个选项

2.3.2 Unity如何判断?

那么,Unity是如何判断的?前向渲染中,Unity会根据场景中光源的设置光源对物体的影响程度对光源做一个重要度排序,影响程度包括:光源距离物体的远近、光源强度等。距离好说,当其他参数都相同时,越近当然越重要;但对于距离、强度和光颜色等到底是如何考虑得到排序的我们并不知道(Unity文档也未告知),仅仅知道这个重要度排序跟这么多参数都有关。

通常Unity会使用以下判断规则:

  • 最亮的平行光总是按照逐像素考虑的
  • Render Mode设置成Not Important的光源,会按逐顶点或SH的方法处理
  • Render Mode设置成Important的光源,会按逐像素处理
  • 光源数量小于上面提到的Pixel Light Count,会有更多的光源按逐像素处理

2.4 Base Pass和Additonal Pass

光照计算都是在Pass中实现的。而对于前向渲染,Pass的“LightMode”标签有“ForwardBase”和“ForwardAdd”两个选项,也就意味着前向渲染通常都包含两个Pass。

Pass

可实现的

光照效果

渲染设置进行的光照计算执行次数
标签额外编译指令混合模式
Base

光照纹理/

环境光/自发光/平行光的阴影

ForwardBase#pragma multi_compile_fwdbase一个逐像素的平行光和SH光源仅1次
Additonal默认不支持阴影ForwardAdd#pragma multi_compile_fwdbaddBlend One One其他逐像素光照-point和spot每个光源执行1次

需要补充的是,

  • 关于渲染设置的额外编译指令:只有设置了编译指令,Unity才会在对应的Pass中获得正确的光照变量,具体有哪些光照变量,后面会进行补充
  • 关于阴影:Base Pass支持平行光阴影(取决于光源的Shadow Type是否开启阴影),Additional Pass默认无阴影(即使Shadow Type设置了阴影类型),需要额外使用#pragma multi_compile _fwdadd_fullshadows代替#pragma multi_compile_fwdbadd为point和spot光源设置阴影
  • 关于Blend模式:Additional Pass开启设置了混合模式,为什么要开启?因为一个Shader里Base Pass只会执行一次(排除双面渲染的情况),而Additional Pass会被多次调用,这就需要处理每次光照结果在帧缓存中的叠加,于是就需要定义Blend,通常使用的是Blend One One

2.5 内置的光照变量和函数

直接盘点一下前向渲染的内置光照变量: 

名称类型描述
_lightColor0float4该Pass处理的逐像素光源的颜色
_WorldSpaceLightPos0float4_WorldSpaceLightPos0.xyz是内置变量,如果该光源是平行光,则_WorldSpaceLightPos0.w是0,其他光源的值是1
_LightMatrix0float4X4世界空间->光源空间的变换矩阵
unity_4LightPosX0, unity_4LigthPosY0, unity_4LightPosZ0float4仅用于Base Pass,前4个非重要点光源在世界空间中的位置
unity_4LightAtten0float4仅用于Base Pass,储存了前4个非重要的点光源的衰减因子
unity_LightColorhalf4[4]仅用于Base Pass,储存着颜色

还有内置光照函数,这些函数都是仅用于前向渲染的:

函数名描述
float3 WorldSpaceLightDir(float4 v)输入一个模型空间的顶点位置,得到lightDir,但没有被归一化
float3 UnityWorldSpaceLightDir(float4 v)输入世界空间的顶点位置,返回世界空间中lightDir
float3 ObjSpaceLightDir(float4 v)输入模型空间的顶点位置,返回模型空间中的lightDir
float3 Shade4PointLights(...)计算4个点光源的光照

2.6 实现前向渲染

Shader "Unity Shaders Book/Chapter 9/ForwardRendering"
{Properties{_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)_Specular ("Specular", Color) = (1, 1, 1, 1)_Gloss ("Gloss", Range(8, 256)) = 20.0}SubShader {// Pass for ambient light & directional lightPass {Tags {"LightMode"="ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"//need to add this declaration#pragma multi_compile_fwdbase//propertiesfixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));fixed3 halfDir = normalize(worldViewDir + worldLightDir);fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(halfDir, worldNormal)), _Gloss);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//attenuation of directional lightfixed atten = 1.0;return fixed4 (ambient + (diffuse + specular) * atten, 1.0);}ENDCG}Pass {Tags {"LightMode"="ForwardAdd"}Blend One OneCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "Autolight.cginc"#pragma multi_compile_fwdadd//propertiesfixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);#ifdef USING_DIRECTIONAL_LIGHTfixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));#else  //is pointlightfixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);#endiffixed worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));fixed3 halfDir = normalize(worldViewDir + worldLightDir);fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(halfDir, worldNormal)), _Gloss);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//attenuation of directional light#ifdef USING_DIRECTIONAL_LIGHTfixed atten = 1.0;#else//1.Change point from world to lightspace, add-> "Autolight.cginc"float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;//2.samplefixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#endifreturn fixed4 (ambient + (diffuse + specular) * atten, 1.0);}ENDCG}}FallBack  "Specular"
}

效果如下:

3 延迟渲染

我们知道前向渲染是每个光源对物体的影响都计算出来,但随着场景中光源数量增多,需要计算的三角面和顶点数量也会增多,那前向渲染的性能会急速下降!这个时候延迟渲染就体现出它的优点了。

3.1 原理

延迟渲染是一种比较古老的方法,它分为两个Pass,但和前向渲染的截然不同(前向渲染有可能会有多个Pass,取决于场景中的光源),它的两个Pass分工非常明确:(不再写出伪代码了)

  • 第一个Pass——不进行任何的光照计算,仅计算当前可见的片元,片元通过了深度测试?那就把这个片元的信息储存在G缓冲中,这就是第一个Pass干的事情
  • 第二个Pass——利用G-buffer中的信息进行真正的光照计算,将计算得到的结果写入帧缓冲中

我们会发现,除了前向渲染的颜色缓冲和深度缓冲,延迟渲染还多了一个G缓冲,也叫G-buffer,这个G是Geometry的缩写,G缓冲中储存了各种计算光照需要的表面信息。此外,还会发现!这么说来,延迟渲染的Pass数量就只有2个,也就是说它与场景中的光源数目无关,而与屏幕大小有关。这不难理解吧?屏幕空间越大,当前帧包括在camera视角中的物体不就多了,物体多了G-buffer需要纳入的表面信息也就多了。

3.2 Unity中如何实现延迟渲染

我们知道第二个Pass纯粹用于计算光照,可以叫做lightPass,这个Pass在Unity中是使用内置的、默认的standard光照模型。

可以按照路径project settings->Graphics->Built-in Shader Settings里进行自定义。

《入门精要》其实也是小篇幅的介绍延迟渲染。我就简单的写一些第一个Pass的G-buffer有哪几个渲染纹理(Render Texture, RT)

  • RT0——ARGB32,储存漫反射颜色,A通道不使用
  • RT1——ARGB32,储存高光反射颜色,A通道储存高光反射的指数部分,就是那个_GLOSS
  • RT2——ARGB2101010,储存法线,A通道不适用
  • RT3——储存自发光+lightmap+反射探针(reflection probes)
  • 深度缓冲和模板缓冲

4 两种渲染路径的优劣

之前的叙述中,或多或少的提到了前向渲染和延迟渲染之间的对比,百人计划里老师也列出了二者的优点与缺点:

我们一条一条说说:

4.1 前向渲染的优点和缺点

关于优点,

  • 支持半透明渲染——之前做的半透明效果的透明度测试和透明度混合都是前向渲染实现的
  • 支持多个光照Pass——这里的多个我觉得是指对于不同的光源(平行光、点光源等)可以分别进行处理吧,毕竟大多数时候还是有两个Pass(双面渲染需要两个Base Pass除外)
  • 支持自定义光照计算方式

 关于缺点,

  • 计算复杂度很大——相比延迟渲染,只要影响到物体的光源它都给计算了,这计算量能不大嘛
  • 访问深度需要额外的计算——这是因为不同于延迟渲染,直接将信息储存在了一个G-buffer中,只要不clear,每次需要用的时候直接调用即可;前向渲染需要每次用到深度信息的时候都需要额外计算

4.2 延迟渲染的优点和缺点

关于优点,

  • 大量光照场景优势明显——当场景中超级多光照的时候,延迟渲染肯定会比前向渲染更节省性能,需要的计算量也大大降低
  • 节省计算量——其实跟上面一条的道理一样,只渲染当前屏幕空间大小内的可见的片元
  • 对后处理支持良好——这一点还是得益于G-buffer,需要深度信息的后处理操作,直接访问就行!不需要再进行计算,那么关于屏幕后处理后面会再进行学习

关于缺点,

  • 占用大量显存宽带——由于需要G-buffer,深度信息一直存在一张图里,那么需要的显存也更多了
  •  对MSAA支持不友好——其实就是延迟渲染不支持真正的抗锯齿功能
  • 不能渲染半透明物体——所以在延迟渲染中如果遇到半透明材质的物体,会选择最后前向渲染给它实现出来

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

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

相关文章

art-template数据渲染的问题

问题 当使用art-template渲染数据的时候,经常会出现这种错误, 错误:说未定义title,明明从数据库里查出来的数据,为何会未定义,其实主要的原因是,先加载了art-template语句,而这时候…

如何选择好用的效果图渲染平台

在现代的建筑设计、室内设计、电影动画等行业中,效果图已经成为了一个重要的工具,能够帮助设计师和制作人员更好地呈现他们的想法和概念。而要制作出高质量的效果图,一个好用的效果图渲染平台是非常必要的。 如何选择好用的效果图渲染平台呢…

计算机专业开题报告这么写,有效有用还能过

最近收到很多私信,在问我关于开题报告的问题。基本都是毕业论文题目怎样选?系统好不好弄?开题报告怎么写啊?啥也不会怎样办呢?系统运行不会?查重问题呀,要马上交开题报告了等等。 今天就来分享下…

关于学术文献推荐系统的调研报告

关于学术文献推荐系统的调研报告 1 引言 1.1 研究背景 随着大数据时代的到来,互联网在给人们的生活带来丰富多彩的同时,海量信息也导致了“信息过载”问题。对于信息使用者来说,如何从海量信息中找到自己需要的信息是一件越来越困难的事&am…

论文调研

一、论文部分 基于傅里叶文档恢复的鲁棒文档去锐化与识别https://www.semanticscholar.org/paper/Fourier-Document-Restoration-for-Robust-Document-Xue-Tian/64dcd0cac46b936eb413f36b462be3b5b298c75b 1. 由于这篇论文没有给代码,所以去参考文献查找&#xff…

毕业论文中的调查问卷怎样设计以及分析?

人文社科以及部分自然科学在进行学术研究时,会通过调查问卷的方式获取数据,如何进行问卷的设计和分析会极大的影响论文质量。很多人都写过调察问卷,但不一定知道如何涉设计,本文就针对调查问卷的涉及与分析,教大家如何…

百度地图api实现路线规划之步行驾车

着手做一个用户轨迹的demo,大概分了下步骤:1、过滤边缘点;2、分段量化聚类焦点关键点;3、基于关键点的百度地图api路线规划;4:路线择优 我们先看下第三点基于键点的百度地图api路线规划的方案,…

智慧高速 3D 可视化,构建互联协同智能交通体系

随着智能交通科技和产业的发展,我国正在形成一个安全可靠、便捷高效、绿色智能、开放共享的现代化综合交通运输体系。《“十四五”现代综合交通运输体系发展规划》明确提出,加快智能技术深度推广应用,坚持创新驱动发展,推动互联网…

数据可视化之交通可视化

一 前言 智慧城市的概念自 2008年提出以来,在国际上引起广泛关注,并持续引发了全球智慧城市的发展热潮。智慧城市已经成为推进全球城镇化、提升城市治理水平、破解大城市病、提高公共服务质量、发展数字经济的战略选择。近年来,我国智慧城市…

智能交通车路协同系统的应用场景和发展趋势

随着城市化进程的加速和汽车保有量的增加,城市交通拥堵、交通事故等问题日益突出。为了解决这些问题,智能交通车路协同系统应运而生。智能交通车路协同系统是一种基于车载终端、路侧设备和交通管理中心等多个组成部分构成的智能交通系统,可以…

一文搞定腾讯地图开发中的路线规划和小车平滑移动

前言 在网约车行业的开发者,需要用到LBS(Location Based Service),即基于位置的服务,国内提供LBS服务的有百度地图、腾讯地图、高德地图,本文选取的是腾讯地图的LBS即腾讯位置服务,这个demo可以…

智慧城市系列之智能交通系统(ITS)

第四章 ITS的主要内容 ITS的基本功能表现在:减少出行时间、保障交通安全、缓解交通拥挤、减少交通污染等四个方面,其最终目标是建立一个实时、准确、高效的交通运输管理系统。ITS的基本功能模块包括:先进的出行者信息系统(ATIS&…

基于百度、高德路线规划的出行圈获取

想获取更准确的出行圈数据该怎么办呢?这个时候,我们就可以使用百度、高德的路线规划API去实现这一点。 百度、高德的路径规划服务以海量的交通大数据为基础,综合考虑道路拥堵、红绿灯等待等实际交通情况,是一种已经过大量实际项目检验的商业级数据服务。我们常用的地图导航…

以数字化、智能化、可视化为中心,打造智慧交通运维新标杆

交通作为国民经济和社会发展的基础性、先行性产业,在整个社会经济、民生发展中占有举足轻重的地位,随着包括5G基站建设、城际高速铁路和城市轨道交通、大数据中心、工业互联网在内的新基建按下加速键,轨道交通云联网加速实施。在此背景下&…

【大数据】城市公交网络分析与可视化(四):绘制城市公交(地铁)线路图

内容介绍 梗概:爬取公交路径坐标,处理成为符合高德地图Map Lab线形图的格式,通过该平台绘制公交(地铁)线路图等 一些必要的知识点可在该系列博客的其他内容中获得! 1 采用循环法获取线路名 怎么获取一个…

自动驾驶轨迹预测/规划可视化工具

该可视化工具在ubuntu18.04下基于ros实现。该文档基于EPSILON的README操作流程完成。 参考文献:EPSILON: An Efficient Planning System for Automated Vehicles in Highly Interactive Environments github:GitHub - HKUST-Aerial-Robotics/EPSILON 目…

图扑数字孪生智慧公路,构建互联协同智能交通系统

前言 随着智能交通科技和产业的发展,我国正在形成一个安全可靠、便捷高效、绿色智能、开放共享的现代化综合交通运输体系。《“十四五”现代综合交通运输体系发展规划》明确提出,加快智能技术深度推广应用,坚持创新驱动发展,推动…

【腾讯地图API】制作多途经点的线路导航——路线坐标规划

面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>> 最近百度地图转腾讯地图以前用过百度地图实现路线坐标规划,不过搜索了一些没有搜索到腾讯地图的路线坐标规划,于是参数百度的思路写了个腾讯地图的路线坐标规划. 这两家地图…

GPT专业应用:自动撰写宣传稿

●图片由Lexica 生成,输入:Staff working on product promotion 宣传稿是指按照有关政策文件或相关精神,以宣传某种主张、某项工作、某件事情等为目的,为获得理解、支持而撰写的应用文。基本格式包含四个要素,分别是标…

百度AI 人工智能可以申请体验了,附登录方式

百度发布了一款名为“文心一言”的知识增强大语言 AI 模型, 它基于百度飞桨深度学习平台和文心知识增强大模型,旨在帮助人们从大量信息中挑选所需内容,获取灵感和知识,以使生活和工作更加便捷。该模型具有强大的中文语料库&#…