1、镜面反射模型
光入射的角度L向量与向量N之间的夹角与反射光R向量与向量N之间的夹角是相同的,当向量R与相机向量V重合的时候,就说明光线被全部照进了人眼。入射光线L与反射光线R、向量N之间的交点是最亮的,如果稍微偏离,亮度会衰减。所以要求得镜面反光,不仅要求得R向量,还要求得V向量,相机的向量。求得R和V之间的角度,就可以求得L、V、R、N交界处是否应该高亮。如果使用点积来计算,当R向量远离V向量过后,只要角度不大于90度,数值总是大于0的。实际上,亮度的衰减并不是按住V和R角度的线性变化来进行的。如果角度稍微偏离一点,亮度衰减非常大,角度再稍微大一点,亮度几乎就可以衰减为0了。只有这样,才能得到高光的镜面反射光。下面的向量长度都不一致,真正使用的时候需要将其规范化,将长度都改为1,这样才能正确计算。
2、Cg reflect函数
N:顶点的法向量
I:入射光的向量,从光源指向顶点
R=Reflect(I,N)
Shader "Custom/MySpecular" {
Properties{
_SpecularColor("Specular",color)=(1,1,1,1)
}
SubShader{
pass {
tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
float4 _SpecularColor;
struct v2f {
float4 pos:POSITION;
fixed4 color : COLOR;
};
v2f vert(appdata_base v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
float3 N = normalize(v.normal);
float3 L = normalize(_WorldSpaceLightPos0);
N = mul(float4(N,0), _World2Object).xyz;
N = normalize(N);
//Diffuse Color
float ndotl = saturate(dot(N, L));
o.color = _LightColor0*ndotl;
//Specular Color
//光的位置指向顶点
float3 I = -WorldSpaceLightDir(v.vertex);
float3 R = reflect(I,N);
//摄像机转向顶点
float3 V = WorldSpaceViewDir(v.vertex);
R = normalize(R);
V = normalize(V);
//模拟当物体特别亮,当稍微一转就没有那么亮的物理现象
float specularScale = pow(saturate(dot(R,V)),4);
o.color.rgb += _LightColor0*specularScale;
return o;
}
fixed4 frag(v2f IN) :COLOR{
//环境光照
return IN.color + UNITY_LIGHTMODEL_AMBIENT;
}
ENDCG
}
}
}
3、
衰减变化
修改方向光的强度,让顶点光的变化更强烈一些
将强度作为一个变量,通过调整变量来调节光的强度
Shader "Custom/MySpecular" {
Properties{
_SpecularColor("Specular",color)=(1,1,1,1)
_Shininess("Shininess",range(1,64))=8
}
SubShader{
pass {
tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
float4 _SpecularColor;
float _Shininess;
struct v2f {
float4 pos:POSITION;
fixed4 color : COLOR;
};
v2f vert(appdata_base v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
float3 N = normalize(v.normal);
float3 L = normalize(_WorldSpaceLightPos0);
N = mul(float4(N,0), _World2Object).xyz;
N = normalize(N);
//Diffuse Color
float ndotl = saturate(dot(N, L));
o.color = _LightColor0*ndotl;
//Specular Color
//光的位置指向顶点
float3 I = -WorldSpaceLightDir(v.vertex);
float3 R = reflect(I,N);
//摄像机转向顶点
float3 V = WorldSpaceViewDir(v.vertex);
R = normalize(R);
V = normalize(V);
//模拟当物体特别亮,当稍微一转就没有那么亮的物理现象
float specularScale = pow(saturate(dot(R,V)),4);
o.color.rgb += _SpecularColor*specularScale;
return o;
}
fixed4 frag(v2f IN) :COLOR{
//环境光照
return IN.color + UNITY_LIGHTMODEL_AMBIENT;
}
ENDCG
}
}
}
4、
改变高光的颜色,查看着色的效果
高光不平滑的原因是,所有的代码都放在了顶点级,放在片段级就平滑了