16.不透明物体接受阴影

  1. 16.阴影-不透明物体阴影-让不透明物体接受阴影
    1. 16.1 知识点
      1. 让物体接收阴影的思路
      2. 实现物体接收阴影效果
        1. 主要步骤
        2. 创建一个新的Shader,复制之前编写的多种光源综合实现Shader Lesson11_ForwardLighting.shader,取名为 Lesson16_OpaqueObjectReceiveShadows.shader,在此基础上实现接收阴影的效果。添加 Fallback "Specular",就不用自己处理投射阴影了
        3. 注意:本次只修改 Base Pass 中的代码,感受接收阴影的流程。
        4. 在BasePass当中引用包含内置文件#include “AutoLight.cginc”,这个文件有计算阴影时要用到的宏
        5. 在v2f结构体声明SHADOW_COORDS宏,本质上就是声明了一个用于对阴影纹理进行采样的坐标
        6. 在顶点函数中声明TRANSFER_SHADOW宏,传入对应的v2f结构体对象。该宏会判断应该使用哪种阴影映射技术(SM、SSSM),将顶点进行坐标转换并存储到_ShadowCoord阴影纹理坐标变量中。注意顶点函数参数结构体中顶点的命名必须是vertex(appdata_base.vertex),顶点函数结构体返回值中顶点位置命名必须是pos(v2f.pos)。
        7. 在片元函数中声明SHADOW_ATTENUATION,传入对应的v2f结构体对象。该宏会在内部利用v2f中的 阴影纹理坐标变量(ShadowCoord)对相关纹理进行采样。将采样得到的深度值进行比较,以计算出一个fixed3的阴影衰减值。我们使用返回的阴影衰减值和 (漫反射+高光反射) 的结果相乘。
        8. 注意:目前处理的方式只是让大家大致了解接受阴影的流程,还没有对 Additional Pass 附加渲染通道进行处理,在下节课中统一处理光照衰减和阴影得到最终效果
        9. 创建材质赋值给cube,和Lesson15投放阴影进对比。可以看到Lesson16是可以接受阴影的,但是效果有点怪怪的,因为没有处理AdditionalPass
    2. 16.2 知识点代码
      1. Lesson16_阴影_不透明物体阴影_让不透明物体接收阴影.cs
      2. Lesson16_OpaqueObjectReceiveShadows.shader

16.阴影-不透明物体阴影-让不透明物体接受阴影


16.1 知识点

让物体接收阴影的思路

我们已经能够让物体投射阴影了。所谓的投射阴影,其实就是让物体参与到光源的阴影映射纹理计算中,最终才能影响其他物体在接收阴影时的采样结果。

由此可见,让物体接收阴影的主要思路其实就是要从阴影映射纹理中进行采样,然后将采样结果用于最终的颜色计算中。

总体的流程如下:

  1. 在顶点着色器中进行顶点坐标转换,将顶点坐标转换为阴影映射纹理坐标。
  2. 在片元着色器中使用阴影映射纹理坐标在阴影映射纹理中进行采样,通过得到的深度值判断片元(像素)是否在阴影中,以计算出阴影衰减值。
  3. 将采样结果参与到最终的颜色计算中。

实现物体接收阴影效果

主要步骤

  1. 创建一个新的Shader,复制之前编写的多种光源综合实现Shader Lesson11_ForwardLighting.shader,在此基础上实现接收阴影的效果。
  2. 接受阴影的三剑客(三个宏)。我们只修改Base Pass中的代码来感受下接受阴影的流程。
    • 在Base Pass当中引用包含内置文件:

      #include "AutoLight.cginc"
      
    • 该内置文件中,有用于计算阴影时需要使用的三剑客。

      • SHADOW_COORDS (阴影坐标宏):该宏在v2f结构体(顶点着色器返回值)中使用,本质上就是声明了一个用于对阴影纹理进行采样的坐标。需要注意的是,在使用时 SHADOW_COORDS(2) 传入参数2,表示需要使用下一个可用的插值寄存器的索引值。

      • TRANSFER_SHADOW (转移阴影宏):该宏在顶点着色器函数中调用,传入对应的v2f结构体对象。该宏会在内部判断应该使用哪种阴影映射技术(SM、SSSM),最终的目的就是将顶点进行坐标转换并存储到 _ShadowCoord 阴影纹理坐标变量中。需要注意:

        1. 该宏会在内部使用顶点着色器中传入的结构体,该结构体中顶点的命名必须是 vertex
        2. 该宏会在内部使用顶点着色器的返回结构体,其中的顶点位置命名必须是 pos
      • SHADOW_ATTENUATION (阴影衰减宏):该宏在片元着色器中调用,传入对应的v2f结构体对象。该宏会在内部利用v2f中的阴影纹理坐标变量 (ShadowCoord) 对相关纹理进行采样,将采样得到的深度值进行比较,以计算出一个 fixed3 的阴影衰减值。我们只需要使用它返回的结果和(漫反射 + 高光反射)的结果相乘即可。

创建一个新的Shader,复制之前编写的多种光源综合实现Shader Lesson11_ForwardLighting.shader,取名为 Lesson16_OpaqueObjectReceiveShadows.shader,在此基础上实现接收阴影的效果。添加 Fallback "Specular",就不用自己处理投射阴影了

Shader "Unlit/Lesson16_OpaqueObjectReceiveShadows"
{
    Properties
    {
        //...
    }
    SubShader
    {
        //...
    }

    //找不到LightMode为ShaderCaster的Pass 使用Specular的shader
    Fallback "Specular"
}

注意:本次只修改 Base Pass 中的代码,感受接收阴影的流程。

在BasePass当中引用包含内置文件#include “AutoLight.cginc”,这个文件有计算阴影时要用到的宏

//引用包含该内置文件 其中有计算阴影会用到的三个宏(阴影三剑客)
#include "AutoLight.cginc"

在v2f结构体声明SHADOW_COORDS宏,本质上就是声明了一个用于对阴影纹理进行采样的坐标

//顶点着色器传递给片元着色器的内容
struct v2f
{
    //裁剪空间的位置
    float4 pos:SV_POSITION;
    //基于世界坐标系下的顶点位置
    float3 wPos:TEXCOORD0;
    //基于世界坐标系下的法线
    float3 wNormal:NORMAL;

    //      该宏在v2f结构体(顶点着色器返回值)中使用
    //      本质上就是声明了一个用于对阴影纹理进行采样的坐标
    //      在内部实际上就是声明了一个名为_ShadowCoord的阴影纹理坐标变量
    //      需要注意的是:
    //      在使用时 SHADOW_COORDS(2) 传入参数2
    //      表示需要时下一个可用的插值寄存器的索引值   
    //阴影坐标宏 主要用于存储阴影纹理坐标
    SHADOW_COORDS(2)
};

在顶点函数中声明TRANSFER_SHADOW宏,传入对应的v2f结构体对象。该宏会判断应该使用哪种阴影映射技术(SM、SSSM),将顶点进行坐标转换并存储到_ShadowCoord阴影纹理坐标变量中。注意顶点函数参数结构体中顶点的命名必须是vertex(appdata_base.vertex),顶点函数结构体返回值中顶点位置命名必须是pos(v2f.pos)。

v2f vert(appdata_base appdata_base)
{
    v2f v2f;

    //转换模型空间下的顶点到裁剪空间中
    v2f.pos = UnityObjectToClipPos(appdata_base.vertex);

    //转换模型空间下的法线到世界空间下
    v2f.wNormal = UnityObjectToWorldNormal(appdata_base.normal);

    //转换模型空间下的顶点到世界空间
    v2f.wPos = mul(unity_ObjectToWorld, appdata_base.vertex).xyz;

    //      该宏在顶点着色器函数中调用,传入对应的v2f结构体对象
    //      该宏会在内部自己判断应该使用哪种阴影映射技术(SM、SSSM)
    //      最终的目的就是将顶点进行坐标转换并存储到_ShadowCoord阴影纹理坐标变量中
    //      需要注意的是:
    //      1.该宏会在内部使用顶点着色器中传入的结构体
    //        该结构体中顶点的命名必须是vertex
    //      2.该宏会在内部使用顶点着色器的返回结构体
    //        其中的顶点位置命名必须是pos
    //计算阴影映射纹理坐标 它会在内部去进行计算 然后将其存入 v2f中的SHADOW_COORDS中
    TRANSFER_SHADOW(v2f);

    return v2f;
}

在片元函数中声明SHADOW_ATTENUATION,传入对应的v2f结构体对象。该宏会在内部利用v2f中的 阴影纹理坐标变量(ShadowCoord)对相关纹理进行采样。将采样得到的深度值进行比较,以计算出一个fixed3的阴影衰减值。我们使用返回的阴影衰减值和 (漫反射+高光反射) 的结果相乘。

fixed4 frag(v2f v2f) : SV_Target
{
    //计算兰伯特光照颜色
    fixed3 lambertColor = getLambertColor(v2f.wNormal);

    //计算BlinnPhong式高光反射颜色
    fixed3 specularColor = getSpecularColor(v2f.wPos, v2f.wNormal);

    //得到阴影衰减值
    //      该宏在片元着色器中调用,传入对应的v2f结构体对象
    //      该宏会在内部利用v2f中的 阴影纹理坐标变量(ShadowCoord)对相关纹理进行采样
    //      将采样得到的深度值进行比较,以计算出一个fixed3的阴影衰减值
    //      我们只需要使用它返回的结果和 (漫反射+高光反射) 的结果相乘即可
    fixed3 shadow = SHADOW_ATTENUATION(v2f);
    
    //衰减值
    //因为我们这是基础Pass 一般是处理场景中最亮的平行光 所以可以认为不存在衰减值的 衰减值默认是1
    //但是之后附加Pass的衰减值就会变化了
    fixed atten = 1;

    //物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + 布林Phong式高光反射光照模型所得颜色
    //衰减值 会和 漫反射颜色 + 高光反射颜色 后 再进行乘法运算   
    fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT.rgb + (lambertColor + specularColor) * atten*shadow;

    return fixed4(blinnPhongColor.rgb, 1);
}

注意:目前处理的方式只是让大家大致了解接受阴影的流程,还没有对 Additional Pass 附加渲染通道进行处理,在下节课中统一处理光照衰减和阴影得到最终效果

创建材质赋值给cube,和Lesson15投放阴影进对比。可以看到Lesson16是可以接受阴影的,但是效果有点怪怪的,因为没有处理AdditionalPass


16.2 知识点代码

Lesson16_阴影_不透明物体阴影_让不透明物体接收阴影.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson16_阴影_不透明物体阴影_让不透明物体接收阴影 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 让物体接收阴影的思路

        //上节课我们已经能够让物体投射阴影了
        //所谓的投射阴影,其实就是让物体参与到光源的阴影映射纹理计算中
        //最终才能影响其他物体在接收阴影时的采样结果

        //由此可见让物体接收阴影的主要思路
        //其实就是要从阴影隐射纹理中进行采样
        //然后将采样结果用于最终的颜色计算中

        //总体的流程就是:
        //1.在顶点着色器中进行顶点坐标转换(将顶点坐标 转换为 阴影映射纹理坐标)
        //2.在片元着色器中使用阴影映射纹理坐标在阴影映射纹理中进行采样
        //  通过得到的深度值判断片元(像素)是否在阴影中,以计算出阴影衰减值
        //3.将采样结果参与到最终的颜色计算中

        #endregion

        #region 知识点二 实现物体接收阴影效果

        //1.创建一个新的Shader,复制之前编写的多种光源综合实现Shader Lesson11_ForwardLighting.shader
        //  在此基础上实现接受阴影的效果

        //2.接受阴影的三剑客(三个宏)
        //  我们这节课只修改Bass Pass中的代码
        //  来感受下接受阴影的流程

        //  首先我们需要在Base Pass当中引用包含内置文件
        //  #include "AutoLight.cginc"
        //  该内置文件中,有用于计算阴影时需要使用的三剑客

        //  2-1.SHADOW_COORDS      (阴影坐标宏)
        //      该宏在v2f结构体(顶点着色器返回值)中使用
        //      本质上就是声明了一个用于对阴影纹理进行采样的坐标
        //      在内部实际上就是声明了一个名为_ShadowCoord的阴影纹理坐标变量
        //      需要注意的是:
        //      在使用时 SHADOW_COORDS(2) 传入参数2
        //      表示需要时下一个可用的插值寄存器的索引值   

        //  2-2.TRANSFER_SHADOW    (转移阴影宏)
        //      该宏在顶点着色器函数中调用,传入对应的v2f结构体对象
        //      该宏会在内部自己判断应该使用哪种阴影映射技术(SM、SSSM)
        //      最终的目的就是将顶点进行坐标转换并存储到_ShadowCoord阴影纹理坐标变量中
        //      需要注意的是:
        //      1.该宏会在内部使用顶点着色器中传入的结构体
        //        该结构体中顶点的命名必须是vertex
        //      2.该宏会在内部使用顶点着色器的返回结构体
        //        其中的顶点位置命名必须是pos

        //  2-3.SHADOW_ATTENUATION (阴影衰减宏)
        //      该宏在片元着色器中调用,传入对应的v2f结构体对象
        //      该宏会在内部利用v2f中的 阴影纹理坐标变量(ShadowCoord)对相关纹理进行采样
        //      将采样得到的深度值进行比较,以计算出一个fixed3的阴影衰减值
        //      我们只需要使用它返回的结果和 (漫反射+高光反射) 的结果相乘即可

        //3.注意
        //  我们目前处理的方式只是让大家大致了解接受阴影的流程
        //  我们还没有对 Additional Pass 附加渲染通道进行处理
        //  我们将在下节课中统一处理光照衰减和阴影 得到最终效果

        #endregion
    }
}

Lesson16_OpaqueObjectReceiveShadows.shader

Shader "Unlit/Lesson16_OpaqueObjectReceiveShadows"
{
    Properties
    {
        //材质的漫反射光照颜色
        _MainColor("MainColor", Color) = (1,1,1,1)
        //高光反射颜色
        _SpecularColor("SpecularColor", Color) = (1,1,1,1)
        //光泽度
        _SpecularNum("SpecularNum", Range(0, 20)) = 0.5
    }
    SubShader
    {
        //Bass Pass 基础渲染通道
        Pass
        {
            //设置我们的光照模式 ForwardBase这种向前渲染模式 主要是用来处理 不透明物体的 光照渲染的
            Tags
            {
                "LightMode"="ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            //用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
            #pragma multi_compile_fwdbase

            //引用对应的内置文件 
            //主要是为了之后 的 比如内置结构体使用,内置变量使用
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            //引用包含该内置文件 其中有计算阴影会用到的三个宏(阴影三剑客)
            #include "AutoLight.cginc"

            //材质的漫反射颜色
            fixed4 _MainColor;
            //对应属性当中的颜色和光泽度
            fixed4 _SpecularColor;
            float _SpecularNum;

            //顶点着色器传递给片元着色器的内容
            struct v2f
            {
                //裁剪空间的位置
                float4 pos:SV_POSITION;
                //基于世界坐标系下的顶点位置
                float3 wPos:TEXCOORD0;
                //基于世界坐标系下的法线
                float3 wNormal:NORMAL;

                //      该宏在v2f结构体(顶点着色器返回值)中使用
                //      本质上就是声明了一个用于对阴影纹理进行采样的坐标
                //      在内部实际上就是声明了一个名为_ShadowCoord的阴影纹理坐标变量
                //      需要注意的是:
                //      在使用时 SHADOW_COORDS(2) 传入参数2
                //      表示需要时下一个可用的插值寄存器的索引值   
                //阴影坐标宏 主要用于存储阴影纹理坐标
                SHADOW_COORDS(2)
            };


            //得到兰伯特光照模型计算的颜色 (逐片元)
            fixed3 getLambertColor(in float3 wNormal)
            {
                //_WorldSpaceLightPos0.xyz 世界坐标系下光源方向 _WorldSpaceLightPos0是四维向量 只需要xyz即可
                //normalize 把向量归一化
                //lightDir 得到光源单位向量
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);

                //_LightColor0光 照颜色
                //.rgb 代表只使用颜色进行计算 透明度不考虑 
                //color 计算出了兰伯特光照的漫反射颜色
                fixed3 color = _LightColor0.rgb * _MainColor.rgb * max(0, dot(wNormal, lightDir));

                return color;
            }

            //得到Blinn Phong式高光反射模型计算的颜色(逐片元)
            fixed3 getSpecularColor(in float3 wPos, in float3 wNormal)
            {
                //1.视角单位向量
                //用观察者的位置(摄像机的位置)减去世界空间下顶点坐标 得到的就是视角方向 并且进行单位化
                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - wPos);

                //2.光的反射单位向量
                //光的方向
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);

                //半角方向向量
                float3 halfA = normalize(viewDir + lightDir);

                //color = 光源颜色 * 材质高光反射颜色 * pow( max(0, dot(视角单位向量, 光的反射单位向量)), 光泽度 )
                fixed3 color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(wNormal, halfA)), _SpecularNum);

                return color;
            }

            v2f vert(appdata_base appdata_base)
            {
                v2f v2f;

                //转换模型空间下的顶点到裁剪空间中
                v2f.pos = UnityObjectToClipPos(appdata_base.vertex);

                //转换模型空间下的法线到世界空间下
                v2f.wNormal = UnityObjectToWorldNormal(appdata_base.normal);

                //转换模型空间下的顶点到世界空间
                v2f.wPos = mul(unity_ObjectToWorld, appdata_base.vertex).xyz;

                //      该宏在顶点着色器函数中调用,传入对应的v2f结构体对象
                //      该宏会在内部自己判断应该使用哪种阴影映射技术(SM、SSSM)
                //      最终的目的就是将顶点进行坐标转换并存储到_ShadowCoord阴影纹理坐标变量中
                //      需要注意的是:
                //      1.该宏会在内部使用顶点着色器中传入的结构体
                //        该结构体中顶点的命名必须是vertex
                //      2.该宏会在内部使用顶点着色器的返回结构体
                //        其中的顶点位置命名必须是pos
                //计算阴影映射纹理坐标 它会在内部去进行计算 然后将其存入 v2f中的SHADOW_COORDS中
                TRANSFER_SHADOW(v2f);

                return v2f;
            }

            fixed4 frag(v2f v2f) : SV_Target
            {
                //计算兰伯特光照颜色
                fixed3 lambertColor = getLambertColor(v2f.wNormal);

                //计算BlinnPhong式高光反射颜色
                fixed3 specularColor = getSpecularColor(v2f.wPos, v2f.wNormal);

                //得到阴影衰减值
                //      该宏在片元着色器中调用,传入对应的v2f结构体对象
                //      该宏会在内部利用v2f中的 阴影纹理坐标变量(ShadowCoord)对相关纹理进行采样
                //      将采样得到的深度值进行比较,以计算出一个fixed3的阴影衰减值
                //      我们只需要使用它返回的结果和 (漫反射+高光反射) 的结果相乘即可
                fixed3 shadow = SHADOW_ATTENUATION(v2f);
                
                //衰减值
                //因为我们这是基础Pass 一般是处理场景中最亮的平行光 所以可以认为不存在衰减值的 衰减值默认是1
                //但是之后附加Pass的衰减值就会变化了
                fixed atten = 1;

                //物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + 布林Phong式高光反射光照模型所得颜色
                //衰减值 会和 漫反射颜色 + 高光反射颜色 后 再进行乘法运算   
                fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT.rgb + (lambertColor + specularColor) * atten*shadow;

                return fixed4(blinnPhongColor.rgb, 1);
            }
            ENDCG
        }


        //Additional Pass 附加渲染通道
        Pass
        {
            //设置我们的光照模式 ForwardAdd这种向前渲染模式 主要是用来处理 附加光照渲染的
            Tags
            {
                "LightMode"="ForwardAdd"
            }

            //线性减淡的效果 进行 光照颜色混合
            Blend One One


            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            //用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
            #pragma multi_compile_fwdadd

            //引用对应的内置文件 
            //主要是为了之后 的 比如内置结构体使用,内置变量使用
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #include "AutoLight.cginc"


            //材质的漫反射颜色
            fixed4 _MainColor;
            //对应属性当中的颜色和光泽度
            fixed4 _SpecularColor;
            float _SpecularNum;

            //顶点着色器传递给片元着色器的内容
            struct v2f
            {
                //裁剪空间的位置
                float4 pos:SV_POSITION;
                //基于世界坐标系下的顶点位置
                float3 wPos:TEXCOORD0;
                //基于世界坐标系下的法线
                float3 wNormal:NORMAL;
            };


            v2f vert(appdata_base appdata_base)
            {
                v2f v2f;

                //转换模型空间下的顶点到裁剪空间中
                v2f.pos = UnityObjectToClipPos(appdata_base.vertex);

                //转换模型空间下的法线到世界空间下
                v2f.wNormal = UnityObjectToWorldNormal(appdata_base.normal);

                //转换模型空间下的顶点到世界空间
                v2f.wPos = mul(unity_ObjectToWorld, appdata_base.vertex).xyz;

                return v2f;
            }

            fixed4 frag (v2f v2f) : SV_Target
            {
                //兰伯特漫反射
                //公式:漫反射颜色 = 光颜色 * 属性中颜色 * max(0, dot(世界坐标系下的法线, 世界坐标系下的光方向));
                
                //世界标准法线
                fixed3 worldNormal = normalize(v2f.wNormal);
                
                #if defined(_DIRECTIONAL_LIGHT)
                    //平行光 光的方向 其实就是它的位置
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                #else
                    //点光源和聚光灯 光的方向 是 光的位置 - 顶点位置
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - v2f.wPos);
                #endif
                
                // 漫反射颜色 = 光颜色 * 属性中颜色 * max(0, dot(世界坐标系下的法线, 世界坐标系下的光方向));
                fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb * max(0, dot(worldNormal, worldLightDir));

                
                //BlinnPhong高光反射
                //公式:高光颜色 = 光颜色 * 属性中的高光颜色 * pow(max(0, dot(世界坐标系法线, 世界坐标系半角向量)), 光泽度);
                
                //视角方向 摄像机位置 - 顶点位置
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - v2f.wPos.xyz);
                
                //半角方向向量 光方向 + 视角方向 平行四边形法则
                fixed3 halfDir = normalize(worldLightDir + viewDir);
                
                // 高光颜色 = 光颜色 * 属性中的高光颜色 * pow(max(0, dot(世界坐标系法线, 世界坐标系半角向量)), 光泽度);
                fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(worldNormal, halfDir)), _SpecularNum);

                
                //衰减值
                #ifdef USING_DIRECTIONAL_LIGHT
                    //平行光
                    fixed atten = 1;
                #else
                    #if defined(POINT)
                        //点光源
                        //将世界坐标系下顶点转到光源空间下
                        float3 lightCoord = mul(unity_WorldToLight, float4(v2f.wPos, 1)).xyz;
                        //利用这个坐标得到距离的平方 然后再再光源纹理中映射得到衰减值
                        fixed atten = tex2D(_LightTexture0, dot(lightCoord,lightCoord).xx).UNITY_ATTEN_CHANNEL;
                    #elif defined(SPOT)
                        //聚光灯   
                        //将世界坐标系下顶点转到光源空间下 聚光灯需要用w参与后续计算
                        float4 lightCoord = mul(unity_WorldToLight, float4(v2f.wPos, 1));
                        fixed atten = (lightCoord.z > 0) * //判断在聚光灯前面吗
                                      tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * //映射到大图中进行采样
                                      tex2D(_LightTextureB0, dot(lightCoord,lightCoord).xx).UNITY_ATTEN_CHANNEL; //距离的平方采样
                    #else
                        fixed atten = 1;
                    #endif
                #endif

                // 衰减值 不准确的判断
                // #if defined(_DIRECTIONAL_LIGHT)
                //     //平行光
                //     fixed atten = 1;
                // #elif defined(_POINT_LIGHT)
                //     //点光源
                //     //将世界坐标系下顶点转到光源空间下
                //     float3 lightCoord = mul(unity_WorldToLight, float4(v2f.wPos, 1)).xyz;
                //     //利用这个坐标得到距离的平方 然后再再光源纹理中映射得到衰减值
                //     fixed atten = tex2D(_LightTexture0, dot(lightCoord,lightCoord).xx).UNITY_ATTEN_CHANNEL;
                // #elif defined(_SPOT_LIGHT)
                //     //聚光灯   
                //     //将世界坐标系下顶点转到光源空间下 聚光灯需要用w参与后续计算
                //     float4 lightCoord = mul(unity_WorldToLight, float4(v2f.wPos, 1));
                //     fixed atten = (lightCoord.z > 0) * //判断在聚光灯前面吗
                //                   tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * //映射到大图中进行采样
                //                   tex2D(_LightTextureB0, dot(lightCoord,lightCoord).xx).UNITY_ATTEN_CHANNEL; //距离的平方采样
                // #else
                //     fixed atten = 1;
                // #endif

                //在附加渲染通道中不需要在加上环境光UNITY_LIGHTMODEL_AMBIENT.rgb颜色了
                //因为它只需要计算一次 在基础渲染通道中已经计算了
                return fixed4((diffuse + specular)*atten, 1);
            }
            ENDCG
        }
    }

    //找不到LightMode为ShaderCaster的Pass 使用Specular的shader
    Fallback "Specular"
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏