Deferred路径中的StandardShader


前向渲染对每个物体每个光源都需要一个额外的附加渲染通道,这使得如果灯光变多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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容