原理
之前我们在一直使用的光照方式叫做前向渲染或正向渲染。它是我们渲染物体的一种非常直接的方式,在场景中我们根据所有光源照亮一个物体,之后再渲染下一个物体,以此类推。
它非常容易理解,也很容易实现,但是同时它对程序性能的影响也很大,因为对于每一个需要渲染的物体,程序都要对每一个光源每一个需要渲染的片段进行迭代,这是非常多的!因为大部分片段着色器的输出都会被之后的输出覆盖.
延迟渲染为了解决上述问题而诞生了,延迟渲染主要包含了两个Pass。在第一个Pass中,我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现,当发现一个片元是可见的,我们就把它的相关信息存储到G缓冲区中。然后,在第二个Pass中,我们利用G缓冲区的各个片元信息,例如表面法线、视角方向、漫发射系数等,进行真正的光照计算。
实现
要实现延迟渲染,我们首先就要创建自己的G缓冲.
G缓冲一般有4个纹理:
RT0:格式是ARGB32(每个通道8位),RGB通道用于存储漫反射颜色,A通道储存遮挡。
RT1:格式是ARGB32(每个通道8位),RGB通道用于存储高光反射颜色,A通道同于用于存储高光反射的指数部分。
RT2:格式是ARGB2101010,RGB通道用于存储世界空间法线,A通道没有被使用。
RT3:格式是ARGB2101010/ARGBHalf(每个通道16位),(高动态光照渲染/低动态光照渲染)用于存储自发光+lightmap+反射探针深度缓冲和模板缓冲。
完整代码如下:
Shader "Unlit/Deferred"
{
Properties
{
_MainTex("Texture",2D) = "white"{
}
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8.0,256)) = 8.0
}
SubShader
{
Tags {
"RenderType"="Opaque" }
LOD 100
Pass
{
Tags{
"LightMode" ="Deferred"}
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma exclude_renderers nomrt
#pragma multi_compile __ UNITY_HDR_ON
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Diffuse;
fixed4 _Specular;
fixed _Gloss;
struct a2v
{
fixed4 vertex : POSITION;
float2 uv: TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv:TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD1;
float3 worldPos :