14.BlinnPhong式高光反射逐片元光照

14.光照模型-高光反射光照模型-BlinnPhong式高光反射模型-逐片元光照


14.1 知识点

利用Blinn-Phong式高光反射光照模型实现光照效果(逐片元光照)

公式

高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂

关键步骤

与逐顶点光照类似,逐片元光照模型的基本逻辑一致,主要区别如下:

  1. 在顶点着色器中计算顶点和法线相关数据。
  2. 在片元着色器中计算Blinn-Phong式高光反射光照。

重置骨架并声明一些光照常用的信息

Shader "Unlit/Lesson14_Blinn_Phong_Specular_Pixel"
{
    Properties
    {
        // 高光反射颜色
        _SpecularColor("SpecularColor", Color) = (1,1,1,1)

        // 光泽度
        _SpecularNum("SpecularNum", Range(0, 20)) = 0.5
    }

    SubShader
    {
        Pass
        {
            // 设置我们的光照模式,ForwardBase主要用于处理不透明物体的光照渲染
            Tags
            {
                "LightMode"="ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

            // 对应属性中的颜色和光泽度
            fixed4 _SpecularColor;
            float _SpecularNum;

            v2f vert(appdata_base appdata_base)
            {
            }

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

声明顶点传给片元的结构体

在片元着色器中进行Blinn-Phong高光反射光照计算时,需要裁剪顶点坐标、世界法线和世界顶点坐标:

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

在顶点函数中计算裁剪顶点、世界法线、世界顶点

在顶点函数中,我们计算裁剪空间下的顶点位置、世界空间下的法线信息,以及顶点在世界空间的坐标,以便片元函数能够使用这些数据:

v2f vert(appdata_base appdata_base)
{
    v2f v2f;

    // 1. 顶点裁剪空间变换:将模型空间下的顶点转换为裁剪空间下的顶点信息
    v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
                
    // 2. 法线空间变换:将模型空间下的法线转换为世界空间下的法线信息
    v2f.wNormal = UnityObjectToWorldNormal(appdata_base.normal);

    // 3. 顶点转到世界空间:将模型空间下的顶点转换为世界空间下的顶点坐标
    // 这有三种方法将模型空间坐标转换为世界空间坐标(有些可能已经过时了)
    // v2f.wPos = mul(UNITY_MATRIX_M, appdata_base.vertex).xyz;
    // v2f.wPos = mul(_Object2World, appdata_base.vertex).xyz;
    v2f.wPos = mul(unity_ObjectToWorld, appdata_base.vertex);

    return v2f;
}

在片元函数中进行具体计算

在片元函数中计算Blinn-Phong高光反射光照,具体步骤如下:

fixed4 frag(v2f v2f) : SV_Target
{
    // 公式:高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
    //观察公式缺什么
    
    // 1. 视角单位向量
    // 用观察者的位置(摄像机的位置)减去世界空间下的顶点坐标,得到视角方向并进行单位化
    float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - v2f.wPos);
                
    // 2. 光线方向 转换成单位向量
    float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                
    // 3. 半角方向向量 转换成单位向量
    float3 halfA = normalize(viewDir + lightDir);

    // 4. 套公式计算
    // 高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
    fixed3 color = _LightColor0.rgb * _SpecularColor.rgb * pow( max(0, dot(v2f.wNormal, halfA)), _SpecularNum);

    return fixed4(color.rgb, 1);
}

进行效果对比

将生成的着色器应用到场景中,与逐顶点光照相比,逐片元光照计算更加细腻,尤其在高光反射的处理上


14.2 知识点代码

Lesson14_光照模型_高光反射光照模型_BlinnPhong式高光反射模型_逐片元光照

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

public class Lesson14_光照模型_高光反射光照模型_BlinnPhong式高光反射模型_逐片元光照 : MonoBehaviour
{
    void Start()
    {
        #region 知识点 利用Blinn-Phong式高光反射光照模型实现光照效果(逐片元光照)

        //公式
        //高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂

        //关键步骤
        //基本和逐顶点一致
        //区别:
        //1.在顶点着色器中计算顶点和法线相关数据
        //2.在片元着色器中计算Blinn Phong式高光反射光照

        #endregion
    }
}

Lesson14_Blinn_Phong_Specular_Pixel.shader

Shader "Unlit/Lesson14_Blinn_Phong_Specular_Pixel"
{
    Properties
    {
        //高光反射颜色
        _SpecularColor("SpecularColor", Color) = (1,1,1,1)

        //光泽度
        _SpecularNum("SpecularNum", Range(0, 20)) = 0.5
    }

    SubShader
    {
        Pass
        {
            //设置我们的光照模式 ForwardBase这种向前渲染模式 主要是用来处理 不透明物体的 光照渲染的
            Tags
            {
                "LightMode"="ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

            //对应属性当中的颜色和光泽度
            fixed4 _SpecularColor;
            float _SpecularNum;

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


            v2f vert(appdata_base appdata_base)
            {
                v2f v2f;

                //1.顶点裁剪空间变换 把模型空间下的顶点转成裁剪空间下的顶点信息
                v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
                
                //2.进行法线空间变换 把模型空间下的法线转成世界空间下的法线信息
                v2f.wNormal = UnityObjectToWorldNormal(appdata_base.normal);

                //3.顶点转到世界空间 把模型空间下的顶点变成世界空间下的顶点坐标 
                //以下是三种把模型空间坐标转换成世界空间坐标的方法 但是有些可能已经过时了
                //data.wPos = mul(UNITY_MATRIX_M, appdata_base.vertex).xyz;
                //data.wPos = mul(_Object2World, appdata_base.vertex).xyz;
                v2f.wPos = mul(unity_ObjectToWorld, appdata_base.vertex);

                return v2f;
            }

            fixed4 frag(v2f v2f) : SV_Target
            {
                //公式:高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
                //观察公式缺什么

                //1.视角单位向量
                //用观察者的位置(摄像机的位置)减去世界空间下顶点坐标 得到的就是视角方向 并且进行单位化
                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - v2f.wPos);
                
                //2.光线方向 转换成单位向量
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                
                //3.半角方向向量 转换成单位向量
                float3 halfA = normalize(viewDir + lightDir);

                //4.套公式计算
                //高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
                fixed3 color = _LightColor0.rgb * _SpecularColor.rgb * pow( max(0, dot(v2f.wNormal, halfA)), _SpecularNum);

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


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

×

喜欢就点赞,疼爱就打赏