20.光照模型-综合光照模型-BlinnPhong光照模型-逐片元光照
20.1 知识点
利用Blinn Phong光照模型实现光照效果(逐片元光照)
Blinn Phong光照模型的公式如下:
物体表面光照颜色 = 环境光颜色 + 兰伯特光照模型所得颜色 + Blinn Phong式高光反射光照模型所得颜色
关键步骤包括:
- 计算兰伯特光照模型。
- 计算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