Deferred路徑中的StandardShader


前向渲染對(duì)每個(gè)物體每個(gè)光源都需要一個(gè)額外的附加渲染通道,這使得如果燈光變多draw call會(huì)急劇的增加。
在每次前向渲染的過(guò)程中,我們都要轉(zhuǎn)換模型數(shù)據(jù),再進(jìn)行fragmentshader求出光照。這么麻煩,我們?yōu)槭裁床粚缀螖?shù)據(jù)緩存起來(lái)。而這對(duì)于多個(gè)光源的場(chǎng)景來(lái)書(shū)會(huì)節(jié)省很多draw call

1.延遲路徑第一步:填充幾何緩沖區(qū)

struct FragmentOutput{
    float4 gBuffer0:SV_TARGET0;
    float4 gBuffer1:SV_TARGET1;
    float4 gBuffer2:SV_TARGET2;
    float4 gBuffer3:SV_TARGET3;
};
1.緩沖區(qū)0

第一個(gè)G緩沖區(qū)用于存儲(chǔ)漫反射率和表面遮擋。這是一個(gè)ARGB32紋理,就像一個(gè)常規(guī)的幀緩沖區(qū)。反射率存儲(chǔ)在RGB通道中,遮擋存儲(chǔ)在A通道中。

finalOutput.gBuffer0.xyz=albedo;
    finalOutput.gBuffer0.a=GetAO(i);
2.緩沖區(qū)1

第二個(gè)G緩沖器用于存儲(chǔ)RGB通道中的鏡面高光顏色,以及A通道中的平滑度值。它也是一個(gè)ARGB32紋理。

finalOutput.gBuffer1.xyz=specular;
finalOutput.gBuffer1.a=smoothness;
3.緩沖區(qū)2

第三個(gè)G緩沖區(qū)包含的是世界空間中的法向量。它們存儲(chǔ)在ARGB2101010紋理的RGB通道中。
因?yàn)槲覀冚敵龅闹涤驗(yàn)?-1,而世界坐標(biāo)中法線方向的向量范圍是-1,1。對(duì)此應(yīng)做映射

finalOutput.gBuffer2=float4(normal*0.5+0.5,1.0);
4.緩沖區(qū)3

用于存儲(chǔ)積累的光照,格式分為兩種一種是儲(chǔ)存低動(dòng)態(tài)對(duì)比度的ARGB2101010,另一種存高動(dòng)態(tài)對(duì)比度顏色ARGBHalf;
對(duì)于積累的光照,在寫(xiě)入GBuffer時(shí),應(yīng)加入SH球諧環(huán)境光、和自發(fā)光;
也可以加入反射,或者是在延遲光照的方法考慮進(jìn)去
當(dāng)關(guān)閉HDR時(shí),要將光照進(jìn)行編碼

#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;            //將直接光照設(shè)置為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

二、延遲光照

目前我們已經(jīng)得到4個(gè)緩沖區(qū),現(xiàn)在我們利用這些緩沖區(qū)在lightingshader中計(jì)算燈光

1.deferredLighting中的兩個(gè)Pass

第一個(gè)pass中用來(lái)計(jì)算光照,第二個(gè)pass是,當(dāng)關(guān)閉HDR時(shí),才會(huì)被調(diào)用,用來(lái)將HDR轉(zhuǎn)換為L(zhǎng)DR

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 
            //用蒙版緩沖區(qū)消除對(duì)背景的影響
            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
        }
    }

燈光計(jì)算(第一個(gè)pass)

1.讀取G緩沖區(qū)的uv坐標(biāo)

    i.pos = UnityObjectToClipPos(v.vertex);
    i.uv = ComputeScreenPos(i.pos);
    float2 uv = i.uv.xy / i.uv.w;

2.世界坐標(biāo)

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緩沖數(shù)據(jù)

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.計(jì)算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.平行光燈光參數(shù)

間接燈光在寫(xiě)入GBuffer中時(shí)已經(jīng)加入了,所以indirLight繼續(xù)填0
燈光方向和顏色是從float4 _LightColor, _LightDir 中讀取,注意LightDir為燈光前進(jìn)方向,應(yīng)取反

float4 _LightColor, _LightDir;
UnityLight CreateLight () {
    UnityLight light;
    light.dir =- _LightDir;
    light.color = _LightColor.rgb;
    return light;
}

6.平行光陰影+COOKIE

1.依靠AutoLight的宏來(lái)確定由陰影引起的光衰減。 不幸的是,該文件沒(méi)有寫(xiě)入延遲光源。 所以我們自己來(lái)進(jìn)行陰影采樣。陰影貼圖可以通過(guò)_ShadowMapTexture變量來(lái)訪問(wèn)。但是,我們不能隨便聲明這個(gè)變量。 它已經(jīng)為UnityShadowLibrary中被定義點(diǎn)光源和聚光光源的陰影,我們間接導(dǎo)入了它們。 所以我們不應(yīng)該自己定義它,除非使用方向光源的陰影。
2.UnityComputeShadowFadeDistance(worldPos, viewZ) 計(jì)算陰影衰減
UnityComputeShadowFade 計(jì)算衰減距離

#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寫(xiě)入時(shí) 一樣

#if !defined(UNITY_HDR_ON)
    color = exp2(-color);
#endif

7.加入聚光燈

1.金字塔區(qū)域被渲染為一個(gè)常規(guī)的3D對(duì)象。

攝像機(jī)可能會(huì)在聚光光源照亮的體積的內(nèi)部。 甚至可能近平面的一部分都在聚光光源照亮的體積的內(nèi)部,而其余部分位于聚光光源照亮的體積的外部。在這些情況下,模板緩沖區(qū)不能用于限制渲染。

Blend [_SrcBlend] [_DstBlend]
//Cull Off
//ZTest Always
ZWrite Off
2.計(jì)算光源方向
float4 _LightColor, _LightDir, _LightPos;
float3 lightVec = _LightPos.xyz - worldPos;
light.dir = normalize(lightVec);
3.再次計(jì)算世界坐標(biāo)

當(dāng)時(shí)平行光的時(shí)候,_LightAsQuad=1

float _LightAsQuad;
i.ray = lerp(UnityObjectToViewPos(v.vertex) * float3(-1, -1, 1),v.normal,_LightAsQuad);
4.Cookie衰減

_LightTexture0存入Cookie的數(shù)值

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.距離衰減

聚光光源的光線也會(huì)根據(jù)距離進(jìn)行衰減。該衰減存儲(chǔ)在查找紋理中,可通過(guò)_LightTextureB0獲得。
光源的范圍存儲(chǔ)在_LightPos的第四個(gè)變量中。
使用哪個(gè)紋理通道,因平臺(tái)而異,由UNITY_ATTEN_CHANNEL宏進(jìn)行定義。

sampler2D _LightTexture0, _LightTextureB0;
attenuation *= tex2D(_LightTextureB0,(dot(lightVec, lightVec) * _LightPos.w).rr).UNITY_ATTEN_CHANNEL;
6.陰影

當(dāng)聚光光源有陰影的時(shí)候,會(huì)定義SHADOWS_DEPTH關(guān)鍵字。

#if defined(SHADOWS_DEPTH)
    shadowed = true;
#endif
shadowAttenuation = UnitySampleShadowmap(mul(unity_WorldToShadow[0], float4(worldPos, 1)));

8.點(diǎn)光源

與聚光燈原理類似
完整的光源衰減

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;
}

完整光照計(jì)算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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容