Unity_Shader中级篇_9_Unity Shader入门精要

本文深入探讨Unity的渲染路径,包括前向渲染、延迟渲染和顶点照明渲染,详细讲解不同渲染路径下的光源类型、光照衰减和阴影处理。通过实例分析了如何在Shader中实现复杂的光照计算,包括逐像素光照、逐顶点光照和球谐函数处理。此外,文章还介绍了Unity中光源类型的影响,以及如何控制光源的渲染模式以优化性能。最后,文章讨论了Unity的阴影映射技术,包括阴影投射和接收的设置,以及屏幕空间阴影映射的应用。
摘要由CSDN通过智能技术生成

中级篇是本书的进阶篇,将讲解Unity中的渲染路径、如何计算光照衰减和阴影、如何使用高级纹理和动画等一系列进阶内容。
第九章 更复杂的光照
在初级篇中实现的光照模型中没有考虑一些重要的光照计算,如阴影和光照衰减。本章首先讲解Unity中的3种渲染路径和3种重要的光源类型,再解释如何在向前渲染路径中实现包含了光照衰减、阴影等效果的完整的光照计算。在本章最后,会给出基于之前学习内容实现的包含了完整光照计算的Unity Shader
第十章 高级纹理
这一章即将会讲解如何在Unity Shader中使用立方体纹理、渲染纹理和程序纹理等类型的纹理。
第十一章 让画面动起来
静态的画面往往是无趣的。这一章将帮助读者学习如何在Shader中使用时间变量来实现纹理动画、顶点动画等动态效果。

需要注意的是,本章实现的代码大多是为了阐述一些计算的实现原理,依旧不可以直接用于项目。但是9.5会给出包含完整光照计算的Unity Shader。

这里写图片描述

9.1 Unity的渲染路径
在Unity里,渲染路径(Rendering Path)决定了光照是如何应用到Unity Shader中的。因此,如果要和光源打交道,我们需要为每个Pass指定它使用的渲染路径,只有这样才能让Unity知道,也就是说,我们只有为Shader正确地选择和设置了需要的渲染路径,该Shader的光照计算才能被正确执行。
Unity支持多种类型的渲染路径。在Unity5.0版本之前,主要有三种:向前渲染路径(Forward Rendering Path)延迟渲染路径(Deferred Rendering Path)顶点照明渲染路径(Vertex Lit Rendering Path)。但在Unity5.0版本之后,Unity做了很对更改,主要有两个变化:首先,顶点照明渲染路径已经被Unity抛弃(但目前仍然可以对之前使用了顶点照明渲染路径的Unity Shader兼容);其次,新的延迟渲染路径代替了原来的延迟渲染路径(同样,目前也提供了对旧版本的兼容)。
大多数情况下,一个项目只使用一种渲染路径,因为我们可以为整个项目设置渲染时的渲染路径。我们可以通过在Unity的Edit>Project Settings>Player>Other Setting>Renddering Path中选择项目所需的渲染路径。默认情况下,该设置选择的是向前渲染路径,如下图所示:
这里写图片描述
但有时,我们希望可以使用多个渲染路径,例如摄像机A渲染的物体使用前向渲染路径,而摄影机B渲染的物体使用延迟渲染路径。这是,我们正在每个摄影机的渲染路径设置中该摄影机使用的渲染路径,以覆盖Project Setting中的设置。如下图所示:
这里写图片描述
上面的设置中,如果选择了Use Player Settings,那么这个摄像机会使用Project Settings中的设置;否则就会覆盖掉Project Settings中的设置。需要注意的是,如果当前的显卡并不支持所选择的渲染路径,Unity会自动使用更低一级的渲染路径。例如,如果一个GPU不支持延迟渲染,那么Unity就会使用前向渲染。
完成了上面的设置后,我们就可以在每个Pass中使用标签来指定该Pass使用的渲染路径。这是通过设置Pass的LightMode标签实现的。不同类型的渲染路径可能会包含多种标签设置。
例如,我们之前在代码中写的:

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

上面的代码将告诉Unity,该Pass使用前向渲染路径中的ForwardBase路径。而前向渲染路径还有一种路径叫ForwardAdd
这里写图片描述
如果我们没有指定任何渲染路径(实际上,在Unity5.x版本中如果使用了前向渲染又没有为Pass指定任何前向渲染合适的标签,就会被当成一个和顶点照明渲染路径等同的Pass),那么一些光照变量很可能不会被正确赋值,我们计算出的效果也就很有可能是错误的。

前向渲染路径
原理:每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:
一个是颜色缓冲区,一个是深度缓冲区。我们利用深度缓冲来决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值。我们可以用下面的伪代码来描述前向渲染路径的大致过程:

Pass{
     foreach primotive in this model){
        for(each fragment covered by this primitive){
         if(failed in depth test){
               // 如果没有通过深度测试,说明该片元是不可见的
               discard;
               }else{
                 //如果该片元可见就进行光照计算
                 float4 color = Shading(materialInfo,pos,normal,lightDir,viewDir);
                 //更新帧缓冲
                 writeFrameBuffer(fragment,color);            
                }
           }    
      }
}

对于每个逐像素光源,我们都需要进行上面一次完整的渲染流程。如果一个物体在多个逐像素光源的影响区域内,那么该物体就需要执行多个Pass,每个Pass计算一个逐像素光源的光照结果,然后在帧缓冲中把这些光照结果混合起来得到最终的颜色值。假设,场景中N个物体,每个物体受M个光源的影响,那么要渲染整个场景一共需要N*M个Pass。可以看出,如果有大量逐像素光照,那么需要执行的Pass数目也会很大。因此,渲染引擎通常会限制每个物体的逐像素光照的数目。

Unity中的前向渲染
事实上,一个Pass不仅仅可以用来计算逐像素光照,它也可以用来计算逐顶点等其他光照。这取决于光照计算所处流水线阶段以及计算时使用的数学模型。当我们渲染一个物体时,Unity会计算哪些光源照亮了它,以及这些光源照亮该物体的方式。
在Unity中,前向渲染路径有三种处理光照(即照亮物体)的方式:逐顶点处理、逐像素处理,球谐函数(Spherical Harmonics,SH)处理。而决定一个光源使用哪种处理模式取决于它的类型和渲染模式。光源类型指的是该光源是平行光还是其他类型的光源,而光源的渲染模式指的是该光源是否是重要的(Important)。如果我们把一个光照的模式设置为Important,意味着我们告诉Unity,这个光源很重要,并把它当成一个逐像素光源来处理。我们可以在光源的Light组件中设置这些属性,如下图所示:
这里写图片描述
在前向渲染中,当我们渲染一个物体时,Unity会根据场景中各个光源的设置以及这些光源对物体的影响程度(例如,距离该物体的远近、光源强度等)对这些光源进行一个重要度排序。其中,一定数目的光源会按逐像素的方式处理,然后最多有四个光源按照逐顶点的方式处理,剩下的光源可以按SH方式处理。Unity使用的判断规则如下;/
·场景中最亮的平行光总是按逐像素处理的。
·渲染模式被设置长成Not Important的光源,会按逐顶点或者SH处理。
·渲染模式被设置成Important的光源,会按逐像素处理。
·如果根据以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量(Pixel Light Count),会有跟多的光源以逐像素的方式进行渲染。
已知,前向渲染又两种Pass:Base Pass 和Additional Pass。两种Pass进行的标签和渲染设置以及常规光照计算如下图所示:
这里写图片描述
上图中有几点需要说明的地方。
·首先。可以发现在渲染设置中,我们除了设置了Pass的标签外,还使用了#pragma multi_compile_fwdbase这样的编译指令。虽然#pragma multi_compile_fwdbase#pragma multi_compile_fwdadd在官方文档中还没有给出相关说明,但实验表明,只有分别为Bass Pass和Additional Pass 使用这两个编译指令,我们才可以在相关的Pass中得到一些正确的光照变量,例如光照衰减值等。
·Base Pass旁边的注释给出了Base Pass中支持的一些光照特性。例如在Base Pass中,我们可以访问光照纹理(lightmap)。
·Base Pass中渲染的平行光默认时支持阴影的(如果开启了光源的阴影功能),而Additional Pass中渲染的光源在默认情况下是没有阴影效果的,即便我们在它的Light组件中设置了有阴影的Shadow Type。但我们可以在Additional Pass中使用#pragma multi_compile_fwdadd_fullshadows代替#pragma multi_compile_fwdadd编译指令,为点光源和聚光灯开启阴影效果,但这需要Unity在内部使用跟多的Shader变种。
·环境光和自发光也是在Base Pass中计算的。这是因为,对于一个物体来说,环境光和自发光我们只希望计算一次即可,而如果我们在Additional Pass中计算这两种光照,就会造成叠加多次环境光和自发光,这不是我们想要的。
·在Additional Pass的渲染设置中,我们还开启和设置了混合模式。这是因为,我们希望每个Additional Pass可以与上一次的光照结果在帧缓存中进行叠加,从而得到最终的有多个光照的渲染效果。如果我们没有开启和设置混合模式,那么Additional Pass的渲染结果会覆盖掉之前的渲染结果,看起来就好像该物体只受该光源的影响。通常情况下,我们选择的混合模式是Blend One One
·对于前向渲染来说,一个Unity Shader 通常会定义一个Base Pass(Base Pass也可以定义多次,例如需要双面渲染等情况)以及一个Additional Pass。一个Base pass仅会执行一次(定义了多个Base Pass的情况除外),而一个Additional Pass会根据影响该物体的其他逐像素光源的数目被多次调用,即每个逐像素光源会执行一次Additional Pass。
上图给出的光照计算是通常情况下我们在每种Pass中进行的计算。实际上,渲染路径的设置用于告诉Unity该Pass在前向渲染路径中的位置,然后底层的渲染引擎会进行相关计算并填充一些内置变量(如_LightColor0等),如何使用这些内置变量进行计算完全取决于开发者的选择。例如,我们完全可以利用Unity提供的内置变量在Base Pass中只进行逐顶点光照;同样,我们也完全可以在Additional Pass中按逐顶

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值