13.光照模型-高光反射光照模型-BlinnPhong式高光反射模型-逐顶点光照
13.1 知识点
关键知识点回顾

- 公式
- 高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
- 标准化后顶点法线方向向量 · 标准化后半角向量方向向量 得到的结果就是 cosθ
- 半角向量方向向量 = 视角单位向量 + 入射光单位向量
- 幂 代表的是光泽度 余弦值取n次幂
利用 Blinn-Phong 式高光反射光照模型实现光照效果(逐顶点光照)
关键步骤
- 属性声明(材质高光反射颜色、光泽度)
- 渲染标签Tags设置 将LightMode光照模式 设置为ForwardBase向前渲染(通常用于不透明物体的基本渲染)
- 引用内置文件UnityCG.cginc和Lighting.cginc
- 结构体声明
- 基本公式实现逻辑
删除默认代码,保留骨架
Shader "Unlit/Lesson13_Blinn_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
}
}
}
声明颜色和光泽度属性,声明光照模式,内置文件,结构体等
Shader "Unlit/Lesson13_Blinn_Phong_Specular_Vertex"
{
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;
// 对应顶点的漫反射光照颜色
fixed3 color:COLOR;
};
v2f vert(appdata v)
{
}
fixed4 frag(v2f i) : SV_Target
{
}
ENDCG
}
}
}
顶点函数,观察公式缺什么,进行转换后返回颜色
v2f vert(appdata_base appdata_base)
{
// 公式:高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
// 观察公式缺什么
v2f v2f;
// 1. 将顶点坐标转换到裁剪空间当中
// UnityObjectToClipPos 把模型空间下的顶点转换到裁剪空间下
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
// 2. 求出标准化后顶点法线方向向量
// 求出世界空间下的单位法线向量
float3 worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
// 3. 标准化后半角向量方向向量
// 使用矩阵变换求出世界坐标下的顶点位置
float3 worldPos = mul(unity_ObjectToWorld, appdata_base.vertex);
// 用摄像机位置减顶点位置 得到在世界坐标下视角方向向量 并转换成单位向量
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - worldPos);
// 光线方向 转换成单位向量
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
// 半角方向向量 转换成单位向量
float3 halfA = normalize(viewDir + lightDir);
// 4. 套公式
// 高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
v2f.color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(worldNormal, halfA)), _SpecularNum);
return v2f;
}
片元函数直接返回颜色出去
fixed4 frag(v2f v2f) : SV_Target
{
return fixed4(v2f.color.rgb, 1);
}
查看效果进行对比

可以看到 Blinn-Phong 式的平滑一些。
13.2 知识点代码
Lesson13_光照模型_高光反射光照模型_BlinnPhong式高光反射模型_逐顶点光照
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson13_光照模型_高光反射光照模型_BlinnPhong式高光反射模型_逐顶点光照 : MonoBehaviour
{
void Start()
{
#region 关键知识点回顾
//公式:
//高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
//1.标准化后顶点法线方向向量 · 标准化后半角向量方向向量 得到的结果就是 cosθ
//2.半角向量方向向量 = 视角单位向量 + 入射光单位向量
//3.幂 代表的是光泽度 余弦值取n次幂
#endregion
#region 知识点 利用Blinn-Phong式高光反射光照模型实现光照效果(逐顶点光照)
//关键步骤
//1.属性声明(材质高光反射颜色、光泽度)
//2.渲染标签Tags设置 将LightMode光照模式 设置为ForwardBase向前渲染(通常用于不透明物体的基本渲染)
//3.引用内置文件UnityCG.cginc和Lighting.cginc
//4.结构体声明
//5.基本公式实现逻辑
#endregion
}
}
Lesson13_Blinn_Phong_Specular_Vertex.shader
Shader "Unlit/Lesson13_Blinn_Phong_Specular_Vertex"
{
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;
//对应顶点的漫反射光照颜色
fixed3 color:COLOR;
};
v2f vert(appdata_base appdata_base)
{
//公式:高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
//观察公式缺什么
v2f v2f;
//1.将顶点坐标转换到裁剪空间当中
//UnityObjectToClipPos 把模型空间下的顶点转换到裁剪空间下
v2f.pos = UnityObjectToClipPos(appdata_base.vertex);
//2.求出标准化后顶点法线方向向量
//求出世界空间下的单位法线向量
float3 worldNormal = UnityObjectToWorldNormal(appdata_base.normal);
//3.标准化后半角向量方向向量
//使用矩阵变换求出世界坐标下的顶点位置
float3 worldPos = mul(unity_ObjectToWorld, appdata_base.vertex);
//用摄像机位置减顶点位置 得到在世界坐标下视角方向向量 并转换成单位向量
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - worldPos);
//光线方向 转换成单位向量
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//半角方向向量 转换成单位向量
float3 halfA = normalize(viewDir + lightDir);
//4.套公式
//高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, 标准化后顶点法线方向向量 · 标准化后半角向量方向向量)幂
v2f.color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(worldNormal, halfA)), _SpecularNum);
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
return fixed4(v2f.color.rgb, 1);
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com