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、
改变高光的颜色,查看着色的效果
高光不平滑的原因是,所有的代码都放在了顶点级,放在片段级就平滑了