镜面高光
上节学习了漫反射,这节我们来探索下镜面反射(高光),镜面反射可以让物体看起来是有光泽的,比如金属材质。
通过上图我们可以清楚的看到,镜面反射和入射光,法向量,反射光方向,视角方向这几个因素有关,
很明显我们可以通过反射光的方向和视角方向的夹角来计算镜面反射强度,如果夹角越小,那么镜面反射光的强度就越大。
计算公式:
:光颜色
:材质颜色
:视角方向
:反射光方向
:光泽强度
在CG中,我们可以通过reflect(I,n)
函数来计算反射光方向,I
代表入射光方向,n
代表法向量。
更多常用函数可以参考这篇文章
shader代码:
//高光反射(Specular)
Shader "lcl/005_Specular_fargment" {
Properties{
//主纹理
_MainTex("Texture", 2D) = "white" {}
//整体颜色
_Color("Diffuse Color",Color) = (1,1,1,1)
// 高光颜色
_Specular("_Specular Color",Color) = (1,1,1,1)
// 高光强度
_Gloss("Gloss",Range(8,200)) = 10
}
SubShader {
Pass{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
// 变量定义
sampler2D _MainTex;
fixed4 _Color;
half _Gloss;
fixed4 _Specular;
//CPU传输到顶点着色器的数据
struct a2v {
// 顶点座标
float4 vertex : POSITION;
// 法向量
float3 normal: NORMAL;
// 纹理座标
float3 texcoord: TEXCOORD0;
};
//顶点传输到片元着色器的数据
struct v2f{
//顶点座标
float4 position:SV_POSITION;
// 世界空间下的法向量
float3 worldNormal: TEXCOORD0;
// 世界空间下座标
float3 worldVertex: TEXCOORD1;
// 纹理座标
float3 texcoord: TEXCOORD2;
};
//顶点着色
v2f vert(a2v v){
v2f f;
f.position = UnityObjectToClipPos(v.vertex);
f.worldNormal = mul(v.normal,(float3x3) unity_WorldToObject);
f.worldVertex = mul(v.vertex,unity_WorldToObject).xyz;
f.texcoord = v.texcoord;
return f;
};
// 片元着色器
fixed4 frag(v2f f):SV_TARGET{
//纹理颜色
float4 texColor = tex2D(_MainTex, f.texcoord);
// 环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
//法向量
fixed3 normalDir = normalize(f.worldNormal);
// 光源方向
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//漫反射
fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir),0) * _Color.rgb;
//反射光计算
fixed3 reflectDir = reflect(-lightDir,normalDir);
//计算视角方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertex );
//计算高光反射
fixed3 specular = _LightColor0.rgb * pow(max(0,dot(viewDir,reflectDir)),_Gloss) *_Specular;
//合并漫反射,环境光,高光反射
fixed3 tempColor = diffuse+ambient+specular;
//融合纹理颜色
return fixed4(tempColor*texColor.rgb,1);
};
ENDCG
}
}
FallBack "VertexLit"
}
效果颜色;