高光反射模型:描述光源照射到模型表面时,该表面在完全镜面反射方向散发的光照。
Phong光照模型:
Phong光照模型公式:
cSpecular = (cLight • mSpecular) * Max(0,v • r)^mGloss
r = l - 2(n • l)n
cLight 入射光线颜色和强度。
mSpecular 材质高光反射颜色
v 视角方向
r 光源反射方向
n 法线
在书写shader代码时,顶点着色器和片元着色器都可以实现光照,顶点着色器写的代码执行效率高,片元着色器片效果会更光滑。
在shader渲染时 片元的个数往往是顶点的几倍所以 顶点效率高,但却没有片元细致
逐顶点、逐片元效果图:
逐顶点代码如下:
//
//简单顶点高光反射
//
Shader "Unlit/HRM01"
{
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
//高光反射颜色
_Specular("Specular",Color) = (1,1,1,1)
//高光区域
_Gloss("Gloss",Range(8,255)) = 3
}
SubShader
{
Tags { "LightMode"="ForwardBase" "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct v2f
{
fixed3 color : Color;
float4 vertex : SV_POSITION;
};
v2f vert (appdata_base v)
{
v2f o;
//物体坐标转裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
//物体法线转世界坐标法线
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
//世界坐标光源方向
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射公式
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldLight,worldNormal) * 0.5 + 0.5);
//反射光方向
fixed3 reflectDir = normalize(reflect(-worldLight,worldNormal));
//摄像机方向 摄像机世界坐标 - 顶点世界坐标
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
//高光公式
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(reflectDir,viewDir)),_Gloss);
//最终颜色
o.color = diffuse + ambient + specular;
// o.color = specular;
return o;
}
fixed3 frag (v2f i) : SV_Target
{
return i.color;
}
ENDCG
}
}
Fallback"Specular"
}
逐片元代码如下:
//
//简单高光反射模型
//
Shader "Unlit/HRM02"
{
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)
_Gloss("Gloss",Range(1,255)) = 3
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct v2f
{
float3 worldNormal : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldVertex : TEXCOORD1;
};
v2f vert (appdata_base v)
{
v2f o;
//物体坐标转裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
//物体法线转世界坐标法线
o.worldNormal = UnityObjectToWorldNormal(v.normal);
//物体坐标转世界空间坐标
o.worldVertex = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed3 frag (v2f i) : SV_Target
{
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//世界坐标光源方向
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//漫反射 点积为负为背光面
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldLight,i.worldNormal) * 0.5 + 0.5);
//反射光源方向
fixed3 reflectDir = normalize(reflect(-worldLight,i.worldNormal));
//摄像机方向
//fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldVertex);
//摄像机方向-unity自带计算世界坐标摄像机方向函数:UnityWorldSpaceViewDir
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldVertex));
//fixed3 viewDir = normalize(WorldSpaceViewDir(i.vertex));
//高光反射公式
fixed3 specular = _Specular.rgb * _LightColor0.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);
//最终颜色
fixed3 color = ambient + diffuse + specular;
return color;
}
ENDCG
}
}
}
Blinn-Phong 光照模型:
Blinn模型没有使用反射方向而是应用了一个新的矢量h ,它通过对视角方向和光照方向相加然后归一化得到。
h = ( v + l ) / |v + l|
v 视角方向
l 光照方向
Blinn-Phong光照模型公式:
cSpecular = (cLight • mSpecular) * Max(0,n • h)^mGloss
逐片元效果图
可以看出Blinn-Phong光照模型的高光反射看起来更大一些、更亮一些。在绝大数情况渲染高光会选择Blinn-Phong(UnityShader入门精要 说的)