渐变纹理——一维纹理
使用渐变纹理来控制漫反射光照,采用半兰伯特模型得到halflambert(代表了法线和光线的夹角,夹角越接近90°,则更靠近纹理的左边颜色)。
Shader "Custom/渐变纹理"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_RampTex ("RampTex", 2D) = "white" {}
_Specular("Specular",Color)=(1,1,1,1)
_Gloss("Gloss",Range(8.0,256))=20
}
SubShader
{
Pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _RampTex;
float4 _RampTex_ST;
fixed4 _Specular;
float _Gloss;
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD;
};
struct v2f{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float3 worldPos:TEXCOORD1;
float2 uv:TEXCOORD2;
};
v2f vert(a2v v){
v2f o;
//计算裁剪空间下的顶点坐标
o.pos= UnityObjectToClipPos(v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
//使用内置的TRANSFORM_TEX计算经过平铺和偏移后的纹理的uv值
o.uv = TRANSFORM_TEX(v.texcoord,_RampTex);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal=normalize(i.worldNormal);
fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
//计算环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//计算漫反射部分
fixed halflambert=0.5*dot(worldNormal,worldLightDir)+0.5;//半兰伯特模型
fixed3 diffuseColor=tex2D(_RampTex,fixed2(halflambert,halflambert)).rgb*_Color.rgb;
fixed3 diffuse = _LightColor0.rgb * diffuseColor;
//采用Blinn模型计算高光反射部分
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
//得出最终的颜色
return fixed4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
效果:
需要注意将渐变纹理的WrapMode设置成为Clamp,以防止对纹理采样时由于浮点数精度造成的问题:
黑点的出现:halflambert可能会得到1.00001这样的值,采用repeat会导致截断后选取到了左边的黑色点0.00001,而不是右边的白色,所以在高光的地方出现了黑点,采用clamp模式则不会有这样的问题。