高光反射又叫做镜面反射:用于模拟有光泽物体的上面出现的光点。高光反射的颜色相比于物体的颜色会更倾向与光的颜色。(漫反射:模拟光源对物体的方向性影响。)
首先是Phong光照模型:
公式:
v是视角方向,r是反射方向,Mgloss是高光系数,Mdiffuse是高光反射颜色
逐顶点光照实现Phong代码:
Shader "Custom/Phong"
{
Properties
{
_Color("_Color",Color) = (1,1,1,1) //高光的颜色
_Range("_Range", Range(0.0, 10.0)) = 2.0 //高光的范围
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
float4 _Color;
float _Range;
struct a2v
{
float4 position:POSITION;//将模型空间下的位置坐标填充给position
float3 normal:NORMAL;//将模型空间下的顶点法线填充normal
};
struct v2f
{
float4 position:SV_POSITION;
float3 color:COLOR;
};
v2f vert(a2v v)
{
v2f f;
//将顶点由模型空间转化到裁剪空间
f.position = UnityObjectToClipPos(v.position);
float4 vertexPos = mul(v.position,(float4x4)unity_WorldToObject);
//获取视野方向
float3 cameraDir = normalize(_WorldSpaceCameraPos.xyz - vertexPos);
//获取灯光方向
float3 lightDir = WorldSpaceLightDir(vertexPos);
float3 normalDir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
//获取反射光位置
float3 reflectDir = normalize(reflect(-lightDir,normalDir));
//使用Phong模型
float3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,cameraDir),0),_Range) * _Color;
//半兰布特模型
float3 diffuse = _LightColor0.rgb * max(dot(lightDir,normalDir),0)*_Color * 0.5 + 0.5;
f.color = specular + UNITY_LIGHTMODEL_AMBIENT.rgb + diffuse;
return f;
}
fixed4 frag(v2f f) : SV_Target
{
return fixed4(f.color,1);
}
ENDCG
}
}
Fallback "Diffuse"
}
Blinn-Phong光照模型,没有使用反射方向。引入了h
公式如下:
逐像素光照实现Blinn-Phong代码:
Shader "Custom/Specular Blinn-Phong"
{
Properties
{
_Color("SpecularColor",Color) = (1,1,1,1) //高光的颜色
_Range("Gloss",Range(8.0,256)) = 20 //高光的范围
}
SubShader
{
Tags{"RenderType" = "Opaque"}
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
};
float4 _Color;
float _Range;
v2f vert(a2v v)
{
v2f o;
//将顶点由模型空间转化到裁剪空间
o.vertex = UnityObjectToClipPos(v.vertex);
//将法线从模型空间转化到世界空间
o.worldNormal = UnityObjectToWorldNormal(v.normal);
//用于将当前顶点/方向矢量从模型空间变换到世界空间
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
//得到环境光
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 normalDir = normalize(i.worldNormal);
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//得到漫反射的颜色(半兰布特模型)
float3 diffuseColor = _LightColor0.rgb * _Color.rgb * max(0.0, dot(normalDir, lightDir)) * 0.5 + 0.5;
//得到视线方向
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
//用于替换到Phong中的得到的出射光
float3 halfDir = normalize(lightDir + viewDir);
float3 specularColor = _LightColor0.rgb * _Color.rgb * pow(max(0, dot(halfDir, normalDir)), _Range);
fixed4 col = float4 ((ambient + diffuseColor + specularColor), 1);
return col;
}
ENDCG
}
}
FallBack "Specular"
}
效果图:
结语:Blinn-Phong光照模型它将计算反射向量的过程替换为计算视线和光线的半角向量,提高了运算速度,它的效果比较平滑,运算速度快。