5.兰伯特漫反射逐片元光照

5.光照模型-漫反射光照模型-兰伯特光照模型-逐片元光照


5.1 知识点

利用兰伯特光照模型实现光照效果(逐片元光照)

创建顶点片元着色器

我们首先创建一个基本的顶点片元着色器,删除默认代码,保留最基础的顶点片元函数的骨架:

Shader "Unlit/Lesson05_Lambert_Pixel"
{
    Properties {}
    SubShader
    {
        Tags {}

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            v2f vert(appdata appdata)
            {
            }

            fixed4 frag(v2f v2f) : SV_Target
            {
            }
            ENDCG
        }
    }
}

属性、Tag和内置文件引用

接下来,我们设置一些属性、Tag和内置文件引用,这与逐顶点光照基本一致:

Shader "Unlit/Lesson05_Lambert_Pixel"
{
    Properties
    {
        // 材质的漫反射光照颜色
        _MainColor("MainColor", Color) = (1,1,1,1)
    }
    SubShader
    {
        // 设置光照模式为 ForwardBase,主要用于处理不透明物体的光照渲染
        Tags
        {
            "LightMode"="ForwardBase"
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            // 引用内置文件,主要用于内置结构体和变量的使用
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            // 材质漫反射颜色
            fixed4 _MainColor;

            v2f vert(appdata_base appdata_base)
            {
            }

            fixed4 frag(v2f v2f) : SV_Target
            {
            }
            ENDCG
        }
    }
}

声明结构体,在顶点着色器中计算裁剪空间顶点和世界空间法线

在顶点着色器中,我们需要计算顶点和法线。声明结构体 v2f,包括裁剪空间下的顶点位置和世界空间下的法线位置:

//顶点着色器返回出去的内容
struct v2f
{
    //裁剪空间下的顶点位置
    float4 pos:SV_POSITION;
    //世界空间下的法线位置
    float3 normal:NORMAL;
};

//一定注意 顶点着色器回调函数 主要就是用于处理顶点、法线、切线等数据的坐标转换
v2f vert(appdata_base appdata_base)
{
    //声明v2f 要传递给片元函数的
    v2f v2f;

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

    //appdata_base.normal 获取到在模型空间下的法线  
    //UnityObjectToWorldNormal 将法线从模型空间转换成世界空间 获取到相对于世界坐标系下的法线信息 
    v2f.normal = UnityObjectToWorldNormal(appdata_base.normal);

    return v2f;
}

片元着色器中计算兰伯特光照

在片元着色器中,我们将使用兰伯特光照模型进行光照计算:

fixed4 frag(v2f v2f) : SV_Target
{
    //_WorldSpaceLightPos0.xyz 世界坐标系下光源方向 _WorldSpaceLightPos0是四维向量 只需要xyz即可
    //normalize 把向量归一化
    //lightDir 得到光源单位向量
    float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);

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

    //UNITY_LIGHTMODEL_AMBIENT.rgb 兰伯特光照模型环境光变量
    //为了让背光的地方不至于是黑色 所以加上自带的漫反射颜色 看起来更加真实
    color = UNITY_LIGHTMODEL_AMBIENT.rgb + color;

    //返回color中的颜色 透明度传1
    return fixed4(color.rgb, 1);
}

赋值到材质并进行对比

将完成的着色器赋值到材质,再应用到场景中的球体对象上。与逐顶点光照相比,可以看到逐片元光照过渡更加平滑细致,带来了更好的视觉效果。


5.2 知识点代码

Lesson05_光照模型_漫反射光照模型_兰伯特光照模型_逐片元光照

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

public class Lesson05_光照模型_漫反射光照模型_兰伯特光照模型_逐片元光照 : MonoBehaviour
{
    void Start()
    {
        #region 知识点 利用兰伯特光照模型实现光照效果(逐片元光照)

        //关键步骤
        //基本和逐顶点一致
        //区别:
        //1.在顶点着色器中计算顶点和法线
        //2.在片元着色器中计算兰伯特光照

        #endregion
    }
}

Lesson05_Lambert_Pixel.shader

Shader "Unlit/Lesson05_Lambert_Pixel"
{
    Properties
    {
        //材质的漫反射光照颜色
        _MainColor("MainColor", Color) = (1,1,1,1)
    }
    SubShader
    {
        //设置我们的光照模式 ForwardBase这种向前渲染模式 主要是用来处理 不透明物体的 光照渲染的
        Tags
        {
            "LightMode"="ForwardBase"
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

            //材质漫反射颜色
            fixed4 _MainColor;

            //顶点着色器返回出去的内容
            struct v2f
            {
                //裁剪空间下的顶点位置
                float4 pos:SV_POSITION;
                //世界空间下的法线位置
                float3 normal:NORMAL;
            };

            //一定注意 顶点着色器回调函数 主要就是用于处理顶点、法线、切线等数据的坐标转换
            v2f vert(appdata_base appdata_base)
            {
                //声明v2f 要传递给片元函数的
                v2f v2f;

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

                //appdata_base.normal 获取到在模型空间下的法线  
                //UnityObjectToWorldNormal 将法线从模型空间转换成世界空间 获取到相对于世界坐标系下的法线信息 
                v2f.normal = UnityObjectToWorldNormal(appdata_base.normal);

                return v2f;
            }

            fixed4 frag(v2f v2f) : SV_Target
            {
                //_WorldSpaceLightPos0.xyz 世界坐标系下光源方向 _WorldSpaceLightPos0是四维向量 只需要xyz即可
                //normalize 把向量归一化
                //lightDir 得到光源单位向量
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);

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

                //UNITY_LIGHTMODEL_AMBIENT.rgb 兰伯特光照模型环境光变量
                //为了让背光的地方不至于是黑色 所以加上自带的漫反射颜色 看起来更加真实
                color = UNITY_LIGHTMODEL_AMBIENT.rgb + color;

                //返回color中的颜色 透明度传1
                return fixed4(color.rgb, 1);
            }
            ENDCG
        }
    }
}


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

×

喜欢就点赞,疼爱就打赏