10.Phong式高光反射逐顶点光照

10.光照模型-高光反射光照模型-Phong式高光反射模型-逐顶点光照


10.1 知识点

关键知识点回顾

公式

  • 高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后观察方向向量· 标准化后的反射方向)幂

相关变量和函数

  1. 观察者的位置(摄像机的位置)_WorldSpaceCameraPos

  2. 相对于法向量的反射向量 方法:reflect(入射向量, 顶点法向量) 返回反射向量

  3. 指数幂 方法:pow(底数,指数) 返回计算结果

利用Phong式高光反射光照模型实现光照效果(逐顶点光照)

创建着色器并简化初始代码

Shader "Unlit/Lesson10_Phong_Specular_Vertex"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            v2f vert (appdata appdata)
            {

            }

            fixed4 frag (v2f v2f) : SV_Target
            {

            }
            ENDCG
        }
    }
}

属性声明(材质高光反射颜色、光泽度)

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

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

渲染标签Tags设置

将LightMode光照模式 设置为ForwardBase向前渲染(通常用于不透明物体的基本渲染)

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

引用内置文件 UnityCG.cgincLighting.cginc

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

结构体声明

要传裁剪空间下的顶点坐标信息和对应顶点的漫反射光照颜色

// 顶点着色器传递给片元着色器的内容
struct v2f
{
    // 裁剪空间下的顶点坐标信息
    float4 pos:SV_POSITION;
    // 对应顶点的漫反射光照颜色
    fixed3 color:COLOR;
};

获得属性

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

顶点着色器逻辑

在顶点函数中,获得需要的变量并套用基本公式实现逻辑

v2f vert(appdata_base appdata_base)
{
    v2f v2f;

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


    //2.计算颜色相关
    //高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后观察方向向量· 标准化后的反射方向)幂
    //光源的颜色 _LightColor.rgb
    //材质高光反射颜色 _SpecularColor.rgb
    //幂(光泽度) _SpecularNum


    //2.1 标准化后观察方向向量
    //将模型空间下的顶点位置 转换到 世界空间下

    //由于没有提供直接转换的api 所以要使用内置矩阵运算进行转换
    // UNITY_MATRIX_M : 从模型空间下 转到 世界空间下的转换矩阵
    float3 worldPos = mul(UNITY_MATRIX_M, appdata_base.vertex);

    //用观察者的位置(摄像机的位置)减去世界空间下顶点坐标 得到的就是视角方向
    float3 viewDir = _WorldSpaceCameraPos.xyz - worldPos;

    //单位化(归一化)
    viewDir = normalize(viewDir);


    //2.2 标准化后的反射方向
    
    //世界空间下的光位置的方向向量
    float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
    
    //世界空间下的法线向量
    float3 normal = UnityObjectToWorldNormal(appdata_base.normal);
    
    //reflect(入射向量,顶点法向量) 返回反射向量 反射光线向量
    float3 reflectDir = reflect(-lightDir, normal);

    //3.套公式
    //高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后观察方向向量· 标准化后的反射方向)幂
    fixed3 color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(viewDir, reflectDir)), _SpecularNum);

    //记录颜色 传递给片元着色器
    v2f.color = color;

    return v2f;
}

片元着色器

把计算好的光照的颜色传递出去

fixed4 frag(v2f v2f) : SV_Target
{
    // 返回计算好的光照颜色,透明度为1
    return fixed4(v2f.color.rgb, 1);
}

调整光泽度和颜色,查看效果并对比


通过调整材质的 SpecularColorSpecularNum,可以观察光泽度的变化以及光照的高光反射效果。


10.2 知识点代码

Lesson10_光照模型_高光反射光照模型_Phong式高光反射模型_逐顶点光照

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

public class Lesson10_光照模型_高光反射光照模型_Phong式高光反射模型_逐顶点光照 : MonoBehaviour
{
    void Start()
    {
        #region 关键知识点回顾

        //高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后观察方向向量· 标准化后的反射方向)幂

        //1.观察者的位置(摄像机的位置)
        //  _WorldSpaceCameraPos
        //2.相对于法向量的反射向量 方法
        //  reflect(入射向量,顶点法向量) 返回反射向量
        //3.指数幂 方法
        //  pow(底数,指数) 返回计算结果

        #endregion

        #region 知识点 利用Phong式高光反射光照模型实现光照效果(逐顶点光照)

        //关键步骤
        //1.属性声明(材质高光反射颜色、光泽度)
        //2.渲染标签Tags设置 将LightMode光照模式 设置为ForwardBase向前渲染(通常用于不透明物体的基本渲染)
        //3.引用内置文件UnityCG.cginc和Lighting.cginc
        //4.结构体声明
        //5.基本公式实现逻辑

        #endregion
    }
}

Lesson10_Phong_Specular_Vertex.shader

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

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

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

            //顶点着色器传递给片元着色器的内容
            struct v2f
            {
                //裁剪空间下的顶点坐标信息
                float4 pos:SV_POSITION;
                //对应顶点的漫反射光照颜色
                fixed3 color:COLOR;
            };

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


            v2f vert(appdata_base appdata_base)
            {
                v2f v2f;

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


                //2.计算颜色相关
                //高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后观察方向向量· 标准化后的反射方向)幂
                //光源的颜色 _LightColor.rgb
                //材质高光反射颜色 _SpecularColor.rgb
                //幂(光泽度) _SpecularNum


                //2.1 标准化后观察方向向量
                //将模型空间下的顶点位置 转换到 世界空间下

                //由于没有提供直接转换的api 所以要使用内置矩阵运算进行转换
                // UNITY_MATRIX_M : 从模型空间下 转到 世界空间下的转换矩阵
                float3 worldPos = mul(UNITY_MATRIX_M, appdata_base.vertex);

                //用观察者的位置(摄像机的位置)减去世界空间下顶点坐标 得到的就是视角方向
                float3 viewDir = _WorldSpaceCameraPos.xyz - worldPos;

                //单位化(归一化)
                viewDir = normalize(viewDir);


                //2.2 标准化后的反射方向
                
                //世界空间下的光位置的方向向量
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                
                //世界空间下的法线向量
                float3 normal = UnityObjectToWorldNormal(appdata_base.normal);
                
                //reflect(入射向量,顶点法向量) 返回反射向量 反射光线向量
                float3 reflectDir = reflect(-lightDir, normal);

                //3.套公式
                //高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后观察方向向量· 标准化后的反射方向)幂
                fixed3 color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(viewDir, reflectDir)), _SpecularNum);

                //记录颜色 传递给片元着色器
                v2f.color = color;

                return v2f;
            }

            fixed4 frag(v2f v2f) : SV_Target
            {
                //把计算好的光照的颜色 传递出去就可以了
                //返回v2f中的颜色 透明度传1
                return fixed4(v2f.color.rgb, 1);
            }
            ENDCG
        }
    }
}


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

×

喜欢就点赞,疼爱就打赏