20.BlinnPhong光照模型逐片元光照

20.光照模型-综合光照模型-BlinnPhong光照模型-逐片元光照


20.1 知识点

利用Blinn Phong光照模型实现光照效果(逐片元光照)

Blinn Phong光照模型的公式如下:

物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + Blinn Phong式高光反射光照模型所得颜色

关键步骤包括:

  1. 计算兰伯特光照模型。
  2. 计算Blinn Phong式高光反射光照模型。

基础骨架复用Phong式光照模型

在这里,我们可以复用Phong光照模型逐片元实现的基础骨架,主要需要修改 getSpecularColor 函数,将其改为Blinn Phong的高光反射计算。以下是修改后的代码片段:

//得到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;
}

进行对比

Blinn Phong式高光反射模型与传统Phong模型的主要区别在于高光反射的计算方式。Blinn Phong通过半角向量来优化光照效果,减少了高光区域的大小,使得反射效果更符合现实光照。通过在逐片元中进行这些计算,可以获得更精细和逼真的高光效果。相比逐顶点也更加细致,没有锯齿感。


20.2 知识点代码

Lesson20_光照模型_综合光照模型_BlinnPhong光照模型_逐片元光照

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

public class Lesson20_光照模型_综合光照模型_BlinnPhong光照模型_逐片元光照 : MonoBehaviour
{
    void Start()
    {
        #region 知识点 利用Blinn Phong光照模型实现光照效果(逐片元光照)

        //公式
        //物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + Blinn Phong式高光反射光照模型所得颜色

        //关键步骤:
        //1.计算兰伯特光照模型
        //2.计算Blinn Phong式高光反射光照模型

        #endregion
    }
}

Lesson20_BlinnPhong_Pixel.shader

Shader "Unlit/Lesson20_BlinnPhong_Pixel"
{
    Properties
    {
        //材质的漫反射光照颜色
        _MainColor("MainColor", Color) = (1,1,1,1)
        //高光反射颜色
        _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 _MainColor;
            //对应属性当中的颜色和光泽度
            fixed4 _SpecularColor;
            float _SpecularNum;

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


            //得到兰伯特光照模型计算的颜色 (逐片元)
            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;

                return v2f;
            }

            fixed4 frag(v2f v2f) : SV_Target
            {
                //计算兰伯特光照颜色
                fixed3 lambertColor = getLambertColor(v2f.wNormal);
                
                //计算BlinnPhong式高光反射颜色
                fixed3 specularColor = getSpecularColor(v2f.wPos, v2f.wNormal);
                
                //物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + 布林Phong式高光反射光照模型所得颜色
                fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT.rgb + lambertColor + specularColor;

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


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

×

喜欢就点赞,疼爱就打赏