///逐顶点高光反射
shader"Unity Shader Book/Chapter 6/Specular Vertex_Leve1"{
//设置了三个属性,漫反射颜色,高光反射颜色,高光区域的大小
properties{
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8.0,256)) = 20
}
SubShader{
//顶点/片元着色器的代码需要写在pass语义块内
Pass{
//指明光照模式
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//引用内置的变量
#include "Lighting.cginc"
//定义和属性相匹配变量
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
//顶点着色器的输入结构体
struct a2v {
float4 vertex :POSITION;
float3 normal :NORMAL;
};
//顶点着色器的输出结构体,同时也是片元着色器的输入结构体
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR;
};
//顶点着色器
v2f vert(a2v v) {
//定义返回值o;
v2f o;
// Transform the vertex from object space to projection space 顶点位置从模型空间转化到裁剪空间
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//get ambient term 得到环境光部分
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//transform the normal fram object space to world space 转换法线从模型到世界坐标
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)_World2Object));
//get the light direction in world space 获得世界空间中的光照方向
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//compute diffuse term 计算漫反射项
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal, worldLightDir));
//get the reflect direction in world space 获得世界空间中的反射方向
fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
//get the view direction in world space 获得世界空间中的观察方向(相机位置)
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(_Object2World, v.vertex).xyz);
//computer specular term 计算高光反射项
fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(reflectDir, viewDir)), _Gloss);
//环境光+漫反射+高光反射 得到最终光照
o.color = ambient + diffuse + specular;
return o;
}
fixed4 frag(v2f i) :SV_Target{
return fixed4(i.color,1.0);
}
ENDCG
}
}
Fallback"Specular"
}
对于高光反射部分:
先计算入射光线关于表面法线的反射方向【reflectDir】。由于CG的reflect函数的入射方向要求是由光源指向交点处的,因此我们需要对【worldLightDir】取反再传给reflect函数。
然后通过【_WorldSpaceCameraPos】得到世界空间中的摄像机位置,再把顶点从 模型空间变换到世界空间下,再通过和_WorldSpaceCameraPos相减得到世界空间下的视角方向
逐顶点高光反射部分很不光滑,因为高光反射部分的计算是非线性的,而在顶点着色器中计算光照再进行插值的过程是线性的,破坏了原计算的非线性关系。(有待理解)
高光反射计算公式:
=
:入射光线的颜色和强度
:材质的高光反射系数
:视角方向
:反射方向
=
-2(
)
:光源方向
reflect(i,n):函数,由CG提供,通过 入射方向 和 法线方向 计算 反射方向
pow(x,y):函数 用来求 x 的 y 次幂(次方)