Unity Shader入门精要总结--渲染路径

来源:互联网 发布:怎么在淘宝举报店铺 编辑:程序博客网 时间:2024/05/23 02:05

前向渲染路径

  • 原理

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

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

    ​ 在Unity中,前向渲染路径有3种处理光照的方式:逐顶点处理逐像素处理球谐函数处理。而决定一个光源使用哪种处理模式取决于它的类型和渲染模式。光源类型指的是该光源是平行光还是其他类型的光源,而光源的渲染模式指的是该光源是否是重要的。如果我们把一个光照的模式设置为Important,意味着我们告诉Unity“这个光源很重要,把它当成一个逐像素光源来处理”。我们可以在光源的Light组件中设置这些属性。

    • Unity 使用的判断规则如下。
      场景中最亮的平行光总是按逐像素处理的。
      渲染模式被设置成Not Important的光源,会按逐顶点或者SH处理。
      如果根据以上规则得到的逐像素光源数量小于Quality Setting 中的逐像素光源数量(Pixel Light Count),会有更多的光源以逐像素的方式进行渲染。

    前向渲染有两种Pass:Base Pass 和 Addition Pass。这两种Pass 进行的标签和渲染设置以及常规光照计算如下图所示。

  • 内置光照变量和函数

顶点照明渲染路径

​ 顶点照明渲染路径是对硬件配置要求最少、运算性能最高、但同时也是得到的效果最差的一种类型,它不支持那些逐像素才能得到的效果,例如阴影、法线映射、高精度的高光反射等。它只是使用了逐顶点的方式来计算光照。实际上,我们在上面的前向渲染路径中也可以计算一些逐顶点的光源。但如果选择使用顶点照明渲染路径,那么Unity会只填充那些逐顶点相关的光源变量,意味着我们不可以使用一些逐像素光照变量。

  • Unity中的顶点照明渲染

    ​ 顶点照明渲染路径通常在一个Pass 中就可以完成对物体的渲染。在这个Pass中,我们会计算我们关心的所有光源对该物体的照明,并且这个计算是按逐顶点处理的。这是Unity中最快速的渲染路径,并且具有最广泛的硬件支持。

  • 内置光照变量和函数

延迟渲染路径

​ 前向渲染的问题是:当场景中包含大量实时光源时,前向渲染的性能会急速下降。例如,如果我们在场景的某一块区域放置了多个光源,这些光源影像的区域互相重叠,那么为了得到最终的光照效果,我们就需要为该区域内的每个物体执行多个Pass来计算不同光源对物体的光照结果,然后再颜色缓存中把这些结果混合起来得到最终的光照。然而,每执行一个Pass我们都需要重新渲染一遍物体,但很多计算实际上是重复的。
​ 延迟渲染是一张更古老的渲染办法。除了前向渲染中使用的颜色缓冲和深度缓冲外,延迟渲染还会利用额外的缓冲区,这些缓冲区也被称为G缓冲。G缓冲区存储了我们所关心的表面的其他信息,例如该表面的法线、位置、用于光照计算的材质属性等。

  • 延迟渲染原理

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

延迟渲染的过程大致可以用下面的伪代码来描述:

Pass1{      //第一个Pass不进行真正的光照计算      //仅仅把光照计算需要的信息存储到G缓冲中      for (each primitive in this model){          for (each fragment covered by this primitive){              if(failed in depth test){                  discard;              }              else{                  //如果该片元可见                  //就把需要的信息存储到G缓冲中                  writeGBuffer(materialInfo,pos,normal,lightDir,viewDir);              }          }      }  }  Pass2{      //利用G缓冲中的信息进行真正的光照计算      for(each pixel in the screen){          if(the pixel is valid){              //如果该像素是有效的              //读取它对应的G缓冲中的信息              readGBuffer(pixel,materialInfo,pos,normal,lightDir,viewDir);              //根据读到的信息进行光照计算              float4 color = Shading(materialInfo,pos,normal,lightDir,viewDir);              //更新帧缓冲              writeFrameBuffer(pixel,color);          }      }  }  

​ 可以看出,延迟渲染使用的Pass数目通常就是两个,这跟场景中包含的光源数目是没有关系的。换句话说,延迟渲染的效率不依赖于场景的复杂的,而是和我们使用的屏幕空间的大小有关。这是因为,我们需要的信息都存储在缓冲区中,而这些缓冲区可以理解成是一张张2D图像,我们的计算实际上就是在这些图像中进行的。

  • Unity中的延迟渲染路径

    ​ Unity有两种延迟渲染路径,一种是Unity5之前使用的延迟渲染路径,而另一种是Unity5.x中使用的延迟渲染路径。新旧延迟渲染路径之间的差别很小,只是使用了不同的技术来权衡不同的需求
    ​ 当使用延迟渲染时,Unity 要求我们提供两个Pass:

    1. 第一个Pass用于渲染G缓冲。在这个Pass中,我们会把物体的漫反射颜色、高光发射颜色、平滑度、法线、自发光和深度等信息渲染到屏幕空间的G缓冲区中。对于每个物体来说,这个Pass仅会执行一次。

    2. 第二个Pass用于计算真正的光照模型。这个Pass会使用上一个Pass中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中。

    默认的G缓冲区(注意,不同Unity版本的渲染纹理存储内容会有所不同)包含了以下几个渲染纹理(Render Texture,RT)。

    • RT0:格式是ARGB32,RGB通道用于存储漫反射颜色,A通道没有被使用。
    • RT1:格式是ARGB32,RGB通道用于存储高光反射颜色,A通道同于用于存储高光反射的指数部分。
    • RT2:格式是ARGB2101010,RGB通道用于存储法线,A通道没有被使用。
    • RT3:格式是ARGB32,用于存储自发光+lightmap+反射探针
    • 深度缓冲和模板缓冲。
  • 可访问的变量和函数

    这里写图片描述

原创粉丝点击