前向渲染对每个物体每个光源都需要一个额外的附加渲染通道,这使得如果灯光变多draw call会急剧的增加。
在每次前向渲染的过程中,我们都要转换模型数据,再进行fragmentshader求出光照。这么麻烦,我们为什么不将几何数据缓存起来。而这对于多个光源的场景来书会节省很多draw call
1.延迟路径第一步:填充几何缓冲区
struct FragmentOutput{
float4 gBuffer0:SV_TARGET0;
float4 gBuffer1:SV_TARGET1;
float4 gBuffer2:SV_TARGET2;
float4 gBuffer3:SV_TARGET3;
};
1.缓冲区0
第一个G缓冲区用于存储漫反射率和表面遮挡。这是一个ARGB32纹理,就像一个常规的帧缓冲区。反射率存储在RGB通道中,遮挡存储在A通道中。
finalOutput.gBuffer0.xyz=albedo;
finalOutput.gBuffer0.a=GetAO(i);
2.缓冲区1
第二个G缓冲器用于存储RGB通道中的镜面高光颜色,以及A通道中的平滑度值。它也是一个ARGB32纹理。
finalOutput.gBuffer1.xyz=specular;
finalOutput.gBuffer1.a=smoothness;
3.缓冲区2
第三个G缓冲区包含的是世界空间中的法向量。它们存储在ARGB2101010纹理的RGB通道中。
因为我们输出的值域为0-1,而世界坐标中法线方向的向量范围是-1,1。对此应做映射
finalOutput.gBuffer2=float4(normal*0.5+0.5,1.0);
4.缓冲区3
用于存储积累的光照,格式分为两种一种是储存低动态对比度的ARGB2101010,另一种存高动态对比度颜色ARGBHalf;
对于积累的光照,在写入GBuffer时,应加入SH球谐环境光、和自发光;
也可以加入反射,或者是在延迟光照的方法考虑进去
当关闭HDR时,要将光照进行编码
#pragma multi_compile _ UNITY_HDR_ON
#if !defined(UNITY_HDR_ON)
finalCol=exp2(-finalCol);
#endif
finalOutput.gBuffer3=float4(finalCol,1.0);
GBuffer-shader
Shader"myshader/DeferredMat"{
Properties{
_mainTex("MainTex",2D)="white"{}
_Tine("Time",Color)=(1,1,1,1)
[NoScaleOffset]_MetallicMap("MetallicMap",2D)="black"{}
_Metallic("Metallic",Range(0,1))=0
_Smoothness("smoothness",Range(0,1))=0
[NoScaleOffset]_NormalMap("NormalMap",2D)="Bump"{}
_NormalScale("NormalScale",float)=1
_AoScale("AoScale",Range(0,1))=1
[NoScaleOffset]_EmissionMap("EmissionMap",2D)="black"
}
SubShader{
Tags{"RenderType"="Opaque"}
pass{
Tags{"LightMode"="Deferred"}
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ UNITY_HDR_ON
#include"WriteInGBuffer.cginc"
ENDCG
}
}
Fallback "Diffuse"
}
#if !defined(MY_LIGHTING_INCLUDED)
#define MY_LIGHTING_INCLUDED
#include"UnityPBSLighting.cginc"
#include"AutoLight.cginc"
#include"UnityStandardUtils.cginc"
sampler2D _mainTex;
float4 _mainTex_ST;
float3 _Tine;
sampler2D _MetallicMap;
float _Metallic;
float _Smoothness;
sampler2D _NormalMap;
float _NormalScale;
float _AoScale;
sampler2D _EmissionMap;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float2 uv:TEXCOORD;
float4 tangent:TANGENT;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD0;
float3 normal:TEXCOORD1;
float4 tangent:TEXCOORD2;
float2 uv:TEXCOORD3;
};
v2f vert(a2v v){
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
o.normal=UnityObjectToWorldNormal(v.normal);
o.tangent=float4(UnityObjectToWorldDir(v.tangent.xyz),v.tangent.w);
o.uv=TRANSFORM_TEX(v.uv,_mainTex);
return o;
}
float3 GetAlbedo(v2f i){
return tex2D(_mainTex,i.uv).xyz * _Tine.xyz;
}
float GetMetallic(v2f i){
return tex2D(_MetallicMap,i.uv).r + _Metallic;
}
float GetSmoothness(v2f i){
return _Smoothness;
}
float3 GetNormal(v2f i){
float3 worldNormal=normalize(i.normal);
float3 worldTangent=normalize(i.tangent.xyz);
float3 worldBinormal=cross(worldNormal,worldTangent) * i.tangent.w * unity_WorldTransformParams.w;
float3 tangentNormal=UnpackScaleNormal(tex2D(_NormalMap,i.uv),_NormalScale);
return float3(
tangentNormal.x*worldTangent+
tangentNormal.y*worldBinormal+
tangentNormal.z*worldNormal
);
}
float GetAO(v2f i){
return 1.;
}
UnityLight GetdirLight(v2f i){
UnityLight dirLight;
dirLight.dir=UnityWorldSpaceLightDir(i.worldPos);
UNITY_LIGHT_ATTENUATION(attenuation,i,i.worldPos);
dirLight.color=_LightColor0.xyz * attenuation;
return dirLight;
}
UnityIndirect GetindirLight(v2f i,float3 viewDir){
UnityIndirect indirLight;
indirLight.diffuse=0;
indirLight.specular=0;
indirLight.diffuse-=max(0,ShadeSH9(float4(i.normal,1)));
Unity_GlossyEnvironmentData envData;
envData.roughness = 1 - GetSmoothness(i);
float3 reflectDir=reflect(-viewDir,i.normal);
float3 reflectDir1=BoxProjectedCubemapDirection(reflectDir, i.worldPos,unity_SpecCube0_ProbePosition,unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
envData.reflUVW = reflectDir1;
float3 probe0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData);
float3 reflectDir2=BoxProjectedCubemapDirection(reflectDir, i.worldPos,unity_SpecCube1_ProbePosition,unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
envData.reflUVW = reflectDir2;
float3 probe1= Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0),unity_SpecCube0_HDR, envData);
indirLight.specular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w);
float AO = GetAO(i);
indirLight.diffuse*=AO;
indirLight.specular*=AO;
#if defined(UNITY_ENABLE_REFLECTION_BUFFERS)
indirLight.specular=0;
#endif
return indirLight;
}
float3 GetEmission(v2f i){
float3 emission=tex2D(_EmissionMap,i.uv).xyz;
return emission;
}
struct FragmentOutput{
float4 gBuffer0:SV_TARGET0;
float4 gBuffer1:SV_TARGET1;
float4 gBuffer2:SV_TARGET2;
float4 gBuffer3:SV_TARGET3;
};
FragmentOutput frag(v2f i){
float3 albedo=GetAlbedo(i);
float metallic=GetMetallic(i);
float3 specular;
float OneMinuseReflectivity;
albedo = DiffuseAndSpecularFromMetallic(albedo,metallic,specular,OneMinuseReflectivity);
float smoothness=GetSmoothness(i);
float3 normal=GetNormal(i);
float3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
UnityLight dirLight; //将直接光照设置为0,
dirLight.dir=float3(0,1,0);
dirLight.color=float3(0,0,0);
UnityIndirect indirLight=GetindirLight(i,viewDir);
fixed3 BRDF=UNITY_BRDF_PBS(albedo,specular,OneMinuseReflectivity,smoothness,normal,viewDir,dirLight,indirLight);
fixed3 emissionCol=GetEmission(i);
fixed3 finalCol=BRDF+emissionCol;
#if !defined(UNITY_HDR_ON)
finalCol=exp2(-finalCol);
#endif
FragmentOutput finalOutput;
finalOutput.gBuffer0.xyz=albedo;
finalOutput.gBuffer0.a=GetAO(i);
finalOutput.gBuffer1.xyz=specular;
finalOutput.gBuffer1.a=smoothness;
finalOutput.gBuffer2=float4(normal*0.5+0.5,1.0);
finalOutput.gBuffer3=float4(finalCol,1.0);
return finalOutput;
}
#endif
二、延迟光照
目前我们已经得到4个缓冲区,现在我们利用这些缓冲区在lightingshader中计算灯光
1.deferredLighting中的两个Pass
第一个pass中用来计算光照,第二个pass是,当关闭HDR时,才会被调用,用来将HDR转换为LDR
SubShader{
pass{
Blend [_SrcBlend] [_DstBlend]
Cull Off
ZTest Always
ZWrite Off
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma exclude_renderers nomrt
#pragma multi_compile_lightpass
#pragma multi_compile _ UNITY_HDR_ON
#include "DeferredLighting.cginc"
ENDCG
}
pass{
Cull off
ZTest Always
ZWrite off
//用蒙版缓冲区消除对背景的影响
Stencil{
Ref [_StencilNonBackground]
ReadMask [_StencilNonBackground]
CompBack Equal
CompFront Equal
}
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma exclude_renderers nomrt
#include"UnityCG.cginc"
struct a2v{
float4 vertex:POSITION;
float2 uv:TEXCOORD0;
};
struct v2f{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
sampler2D _LightBuffer;
v2f vert(a2v v){
v2f o;
o.uv=v.uv;
o.pos=UnityObjectToClipPos(v.vertex);
return o;
}
float4 frag(v2f i):SV_TARGET{
return -log2(tex2D(_LightBuffer,i.uv));
}
ENDCG
}
}
灯光计算(第一个pass)
1.读取G缓冲区的uv坐标
i.pos = UnityObjectToClipPos(v.vertex);
i.uv = ComputeScreenPos(i.pos);
float2 uv = i.uv.xy / i.uv.w;
2.世界坐标
normal的法线信息是沿着视角射线的方向的
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
i.ray = v.normal;
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
depth = Linear01Depth(depth);
float3 rayToFarPlane = i.ray * _ProjectionParams.z / i.ray.z;
float3 viewPos = rayToFarPlane * depth;
float3 worldPos = mul(unity_CameraToWorld, float4(viewPos, 1)).xyz;
3.读取G缓冲数据
sampler2D _CameraGBufferTexture0;
sampler2D _CameraGBufferTexture1;
sampler2D _CameraGBufferTexture2;
float3 worldPos = mul(unity_CameraToWorld, float4(viewPos, 1)).xyz;
float3 albedo = tex2D(_CameraGBufferTexture0, uv).rgb;
float3 specularTint = tex2D(_CameraGBufferTexture1, uv).rgb;
float3 smoothness = tex2D(_CameraGBufferTexture1, uv).a;
float3 normal = tex2D(_CameraGBufferTexture2, uv).rgb * 2 - 1;
4.计算BRDF
float3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
float3 albedo = tex2D(_CameraGBufferTexture0, uv).rgb;
float3 specularTint = tex2D(_CameraGBufferTexture1, uv).rgb;
float3 smoothness = tex2D(_CameraGBufferTexture1, uv).a;
float3 normal = tex2D(_CameraGBufferTexture2, uv).rgb * 2 - 1;
float oneMinusReflectivity = 1 - SpecularStrength(specularTint);
UnityLight light;
light.color = 0;
light.dir = 0;
UnityIndirect indirectLight;
indirectLight.diffuse = 0;
indirectLight.specular = 0;
float4 color = UNITY_BRDF_PBS(albedo, specularTint, oneMinusReflectivity, smoothness,normal, viewDir, light, indirectLight);
5.平行光灯光参数
间接灯光在写入GBuffer中时已经加入了,所以indirLight继续填0
灯光方向和颜色是从float4 _LightColor, _LightDir 中读取,注意LightDir为灯光前进方向,应取反
float4 _LightColor, _LightDir;
UnityLight CreateLight () {
UnityLight light;
light.dir =- _LightDir;
light.color = _LightColor.rgb;
return light;
}
6.平行光阴影+COOKIE
1.依靠AutoLight的宏来确定由阴影引起的光衰减。 不幸的是,该文件没有写入延迟光源。 所以我们自己来进行阴影采样。阴影贴图可以通过_ShadowMapTexture变量来访问。但是,我们不能随便声明这个变量。 它已经为UnityShadowLibrary中被定义点光源和聚光光源的阴影,我们间接导入了它们。 所以我们不应该自己定义它,除非使用方向光源的阴影。
2.UnityComputeShadowFadeDistance(worldPos, viewZ) 计算阴影衰减
UnityComputeShadowFade 计算衰减距离
#if defined (SHADOWS_SCREEN)
sampler2D _ShadowMapTexture;
#endif
float attenuation = 1;
float shadowAttenuation =1.0;
#if defined(DIRECTIONAL) || defined(DIRECTIONAL_COOKIE)
#if defined(DIRECTIONAL_COOKIE)
float2 uvCookie = mul(unity_WorldToLight, float4(worldPos, 1)).xy;
attenuation *= tex2Dbias(_LightTexture0, float4(uvCookie, 0, -8)).w;
//attenuation *= tex2D(_LightTexture0, uvCookie).w;
#endif
#if defined (SHADOWS_SCREEN)
shadowAttenuation = tex2D(_ShadowMapTexture, uv).r;
float shadowFadeDistance = UnityComputeShadowFadeDistance(worldPos, viewZ);
float shadowFade = UnityComputeShadowFade(shadowFadeDistance);
shadowAttenuation = saturate(shadowAttenuation + shadowFade);
#endif
#else
light.dir = 1;
#endif
light.color = _LightColor.rgb * shadowAttenuation * attenuation;
不要忘记LDR的编码,像GBuffer写入时 一样
#if !defined(UNITY_HDR_ON)
color = exp2(-color);
#endif
7.加入聚光灯
1.金字塔区域被渲染为一个常规的3D对象。
摄像机可能会在聚光光源照亮的体积的内部。 甚至可能近平面的一部分都在聚光光源照亮的体积的内部,而其余部分位于聚光光源照亮的体积的外部。在这些情况下,模板缓冲区不能用于限制渲染。
Blend [_SrcBlend] [_DstBlend]
//Cull Off
//ZTest Always
ZWrite Off
2.计算光源方向
float4 _LightColor, _LightDir, _LightPos;
float3 lightVec = _LightPos.xyz - worldPos;
light.dir = normalize(lightVec);
3.再次计算世界坐标
当时平行光的时候,_LightAsQuad=1
float _LightAsQuad;
i.ray = lerp(UnityObjectToViewPos(v.vertex) * float3(-1, -1, 1),v.normal,_LightAsQuad);
4.Cookie衰减
_LightTexture0存入Cookie的数值
float4 uvCookie = mul(unity_WorldToLight, float4(worldPos, 1));
uvCookie.xy /= uvCookie.w;
attenuation *= tex2Dbias(_LightTexture0, float4(uvCookie.xy, 0, -8)).w;
attenuation *= uvCookie.w < 0;
5.距离衰减
聚光光源的光线也会根据距离进行衰减。该衰减存储在查找纹理中,可通过_LightTextureB0获得。
光源的范围存储在_LightPos的第四个变量中。
使用哪个纹理通道,因平台而异,由UNITY_ATTEN_CHANNEL宏进行定义。
sampler2D _LightTexture0, _LightTextureB0;
attenuation *= tex2D(_LightTextureB0,(dot(lightVec, lightVec) * _LightPos.w).rr).UNITY_ATTEN_CHANNEL;
6.阴影
当聚光光源有阴影的时候,会定义SHADOWS_DEPTH关键字。
#if defined(SHADOWS_DEPTH)
shadowed = true;
#endif
shadowAttenuation = UnitySampleShadowmap(mul(unity_WorldToShadow[0], float4(worldPos, 1)));
8.点光源
与聚光灯原理类似
完整的光源衰减
UnityLight CreateLight (float2 uv, float3 worldPos, float viewZ) {
UnityLight light;
float attenuation = 1;
float shadowAttenuation = 1;
bool shadowed = false;
#if defined(DIRECTIONAL) || defined(DIRECTIONAL_COOKIE)
light.dir = -_LightDir;
#if defined(DIRECTIONAL_COOKIE)
float2 uvCookie = mul(unity_WorldToLight, float4(worldPos, 1)).xy;
attenuation *= tex2Dbias(_LightTexture0, float4(uvCookie, 0, -8)).w;
#endif
#if defined(SHADOWS_SCREEN)
shadowed = true;
shadowAttenuation = tex2D(_ShadowMapTexture, uv).r;
#endif
#else
float3 lightVec = _LightPos.xyz - worldPos;
light.dir = normalize(lightVec);
attenuation *= tex2D(
_LightTextureB0,
(dot(lightVec, lightVec) * _LightPos.w).rr
).UNITY_ATTEN_CHANNEL;
#if defined(SPOT)
float4 uvCookie = mul(unity_WorldToLight, float4(worldPos, 1));
uvCookie.xy /= uvCookie.w;
attenuation *=
tex2Dbias(_LightTexture0, float4(uvCookie.xy, 0, -8)).w;
attenuation *= uvCookie.w < 0;
#if defined(SHADOWS_DEPTH)
shadowed = true;
shadowAttenuation = UnitySampleShadowmap(
mul(unity_WorldToShadow[0], float4(worldPos, 1))
);
#endif
#else
#if defined(POINT_COOKIE)
float3 uvCookie =
mul(unity_WorldToLight, float4(worldPos, 1)).xyz;
attenuation *=
texCUBEbias(_LightTexture0, float4(uvCookie, -8)).w;
#endif
#if defined(SHADOWS_CUBE)
shadowed = true;
shadowAttenuation = UnitySampleShadowmap(-lightVec);
#endif
#endif
#endif
if (shadowed) {
float shadowFadeDistance =
UnityComputeShadowFadeDistance(worldPos, viewZ);
float shadowFade = UnityComputeShadowFade(shadowFadeDistance);
shadowAttenuation = saturate(shadowAttenuation + shadowFade);
#if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT)
UNITY_BRANCH
if (shadowFade > 0.99) {
shadowAttenuation = 1;
}
#endif
}
light.color = _LightColor.rgb * (attenuation * shadowAttenuation);
return light;
}
完整光照计算Shader
Shader "Custom/DeferredShading" {
Properties {
}
SubShader {
Pass {
Blend [_SrcBlend] [_DstBlend]
ZWrite Off
CGPROGRAM
#pragma target 3.0
#pragma vertex VertexProgram
#pragma fragment FragmentProgram
#pragma exclude_renderers nomrt
#pragma multi_compile_lightpass
#pragma multi_compile _ UNITY_HDR_ON
#include "MyDeferredShading.cginc"
ENDCG
}
Pass {
Cull Off
ZTest Always
ZWrite Off
Stencil {
Ref [_StencilNonBackground]
ReadMask [_StencilNonBackground]
CompBack Equal
CompFront Equal
}
CGPROGRAM
#pragma target 3.0
#pragma vertex VertexProgram
#pragma fragment FragmentProgram
#pragma exclude_renderers nomrt
#include "UnityCG.cginc"
sampler2D _LightBuffer;
struct VertexData {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct Interpolators {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
Interpolators VertexProgram (VertexData v) {
Interpolators i;
i.pos = UnityObjectToClipPos(v.vertex);
i.uv = v.uv;
return i;
}
float4 FragmentProgram (Interpolators i) : SV_Target {
return -log2(tex2D(_LightBuffer, i.uv));
}
ENDCG
}
}
}
#if !defined(MY_DEFERRED_SHADING)
#define MY_DEFERRED_SHADING
#include "UnityPBSLighting.cginc"
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
sampler2D _CameraGBufferTexture0;
sampler2D _CameraGBufferTexture1;
sampler2D _CameraGBufferTexture2;
#if defined(POINT_COOKIE)
samplerCUBE _LightTexture0;
#else
sampler2D _LightTexture0;
#endif
sampler2D _LightTextureB0;
float4x4 unity_WorldToLight;
#if defined (SHADOWS_SCREEN)
sampler2D _ShadowMapTexture;
#endif
float4 _LightColor, _LightDir, _LightPos;
float _LightAsQuad;
struct VertexData {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct Interpolators {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 ray : TEXCOORD1;
};
UnityLight CreateLight (float2 uv, float3 worldPos, float viewZ) {
UnityLight light;
float attenuation = 1;
float shadowAttenuation = 1;
bool shadowed = false;
#if defined(DIRECTIONAL) || defined(DIRECTIONAL_COOKIE)
light.dir = -_LightDir;
#if defined(DIRECTIONAL_COOKIE)
float2 uvCookie = mul(unity_WorldToLight, float4(worldPos, 1)).xy;
attenuation *= tex2Dbias(_LightTexture0, float4(uvCookie, 0, -8)).w;
#endif
#if defined(SHADOWS_SCREEN)
shadowed = true;
shadowAttenuation = tex2D(_ShadowMapTexture, uv).r;
#endif
#else
float3 lightVec = _LightPos.xyz - worldPos;
light.dir = normalize(lightVec);
attenuation *= tex2D(
_LightTextureB0,
(dot(lightVec, lightVec) * _LightPos.w).rr
).UNITY_ATTEN_CHANNEL;
#if defined(SPOT)
float4 uvCookie = mul(unity_WorldToLight, float4(worldPos, 1));
uvCookie.xy /= uvCookie.w;
attenuation *=
tex2Dbias(_LightTexture0, float4(uvCookie.xy, 0, -8)).w;
attenuation *= uvCookie.w < 0;
#if defined(SHADOWS_DEPTH)
shadowed = true;
shadowAttenuation = UnitySampleShadowmap(
mul(unity_WorldToShadow[0], float4(worldPos, 1))
);
#endif
#else
#if defined(POINT_COOKIE)
float3 uvCookie =
mul(unity_WorldToLight, float4(worldPos, 1)).xyz;
attenuation *=
texCUBEbias(_LightTexture0, float4(uvCookie, -8)).w;
#endif
#if defined(SHADOWS_CUBE)
shadowed = true;
shadowAttenuation = UnitySampleShadowmap(-lightVec);
#endif
#endif
#endif
if (shadowed) {
float shadowFadeDistance =
UnityComputeShadowFadeDistance(worldPos, viewZ);
float shadowFade = UnityComputeShadowFade(shadowFadeDistance);
shadowAttenuation = saturate(shadowAttenuation + shadowFade);
#if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT)
UNITY_BRANCH
if (shadowFade > 0.99) {
shadowAttenuation = 1;
}
#endif
}
light.color = _LightColor.rgb * (attenuation * shadowAttenuation);
return light;
}
Interpolators VertexProgram (VertexData v) {
Interpolators i;
i.pos = UnityObjectToClipPos(v.vertex);
i.uv = ComputeScreenPos(i.pos);
i.ray = lerp(
UnityObjectToViewPos(v.vertex) * float3(-1, -1, 1),
v.normal,
_LightAsQuad
);
return i;
}
float4 FragmentProgram (Interpolators i) : SV_Target {
float2 uv = i.uv.xy / i.uv.w;
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
depth = Linear01Depth(depth);
float3 rayToFarPlane = i.ray * _ProjectionParams.z / i.ray.z;
float3 viewPos = rayToFarPlane * depth;
float3 worldPos = mul(unity_CameraToWorld, float4(viewPos, 1)).xyz;
float3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
float3 albedo = tex2D(_CameraGBufferTexture0, uv).rgb;
float3 specularTint = tex2D(_CameraGBufferTexture1, uv).rgb;
float3 smoothness = tex2D(_CameraGBufferTexture1, uv).a;
float3 normal = tex2D(_CameraGBufferTexture2, uv).rgb * 2 - 1;
float oneMinusReflectivity = 1 - SpecularStrength(specularTint);
UnityLight light = CreateLight(uv, worldPos, viewPos.z);
UnityIndirect indirectLight;
indirectLight.diffuse = 0;
indirectLight.specular = 0;
float4 color = UNITY_BRDF_PBS(
albedo, specularTint, oneMinusReflectivity, smoothness,
normal, viewDir, light, indirectLight
);
#if !defined(UNITY_HDR_ON)
color = exp2(-color);
#endif
return color;
}
#endif