14.光照模型-高光反射光照模型-BlinnPhong式高光反射模型-逐片元光照
14.1 知识点
利用Blinn-Phong式高光反射光照模型实现光照效果(逐片元光照)

公式
高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
关键步骤
与逐顶点光照类似,逐片元光照模型的基本逻辑一致,主要区别如下:
- 在顶点着色器中计算顶点和法线相关数据。
- 在片元着色器中计算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