1、渐变纹理的使用
通过单张纹理和凹凸纹理相,我们知道图片中存储的数据不仅仅可以是颜色数据,还可以是高度、法线数据。
理论上来说,图片中存储的数据我们可以自定义规则,我们可以往图片中存储任何满足
我们需求的数据用于渲染。
而渐变纹理就是用于控制漫反射光照结果的一种存储数据的方式它的主要作用是让游戏中的对象具有插画卡通风格
渐变纹理的使用可以保证物体的轮廓线相比之前使用的传统漫反射光照更加明显,而且还能提供多种色调的变化,可以让模型更具卡通感
2、渐变纹理的基本原理
渐变纹理的基本原理就是在计算漫反射时利用半兰伯特光照模型公式中后半部分
半兰伯特:漫反射光照颜色 = 光源的颜色 * 材质的漫反射颜色 *((标准化后物体表面法线向量· 标准化后光源方向向量)* 0.5 + 0.5)
得到一个0~1区间的值,将这个值作为uv坐标中的uv值,从渐变纹理中取出颜色与公式中前面部分进行颜色叠加,最终得到漫反射光照颜色。
也就是说决定漫反射明暗的不再是由 0~1这个值决定,而是由渐变纹理中取出的颜色进行叠加达到最终效果
3、基础使用(颜色渲染)
Shader "ShaderProj/2/RampTex"
{
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1)
_RampTex("RampTex", 2D) = ""{}
_SpecularColor("SpecularColor", Color) = (1,1,1,1)
_SpecularNum("SpecularNum", Range(8, 256)) = 18
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _MainColor;
sampler2D _RampTex;
float4 _RampTex_ST;
fixed4 _SpecularColor;
float _SpecularNum;
struct v2f
{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
};
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
data.worldPos = mul(unity_ObjectToWorld, v.vertex);
data.worldNormal = UnityObjectToWorldNormal(v.normal);
return data;
}
fixed4 frag (v2f i) : SV_Target
{
float3 lightDir = normalize(_WorldSpaceLightPos0);
// 漫反射颜色(通过渐变纹理得到的颜色来进行叠加)
fixed halfLamberNum = dot(normalize(i.worldNormal), lightDir) * 0.5 + 0.5;
fixed3 diffuseColor = _LightColor0 * _MainColor * tex2D(_RampTex, fixed2(halfLamberNum, halfLamberNum));
// 高光反射颜色
float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
float3 halfDir = normalize(viewDir + lightDir);
fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0, dot(i.worldNormal, halfDir)), _SpecularNum);
fixed3 color = UNITY_LIGHTMODEL_AMBIENT + diffuseColor + specularColor;
return fixed4(color, 1);
}
ENDCG
}
}
}
4、综合使用(结合法线纹理)
Shader "ShaderProj/2/RampTex_Normal"
{
Properties
{
_MainColor("MainColor", Color) = (1,1,1,1)
_MainTex("MainTex", 2D) = ""{}
_BumpMap("BumpMap", 2D) = ""{}
_BumpScale("BumpScale", Range(0, 1)) = 1
_RampTex("RampTex", 2D) = ""{}
_SpecularColor("SpecularColor", Color) = (1,1,1,1)
_SpecularNum("SpecularNum", Range(0, 20)) = 18
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
float4 _MainColor;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
fixed4 _SpecularColor;
float _SpecularNum;
sampler2D _RampTex;
float4 _RampTex_ST;
struct v2f
{
float4 pos:SV_POSITION;
float4 uv:TEXCOORD0;
float3 lightDir:TEXCOORD1;
float3 viewDir:TEXCOORD2;
};
v2f vert (appdata_full v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
data.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
data.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
float3 binormal = cross(normalize(v.tangent), normalize(v.normal)) * v.tangent.w;
float3x3 transMat = float3x3(v.tangent.xyz,
binormal,
v.normal);
data.lightDir = mul(transMat, ObjSpaceLightDir(v.vertex));
data.viewDir = mul(transMat, ObjSpaceViewDir(v.vertex));
return data;
}
fixed4 frag (v2f i) : SV_Target
{
float4 packedNormal = tex2D(_BumpMap, i.uv.zw);
float3 tangentNormal = UnpackNormal(packedNormal);
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
fixed3 albedo = tex2D(_MainTex, i.uv.xy) * _MainColor;
// 修改为渐变纹理相关的计算方式
fixed halfLambertNum = dot(tangentNormal, normalize(i.lightDir)) * 0.5 + 0.5;
fixed3 lambertColor = _LightColor0 * albedo * tex2D(_RampTex, fixed2(halfLambertNum, halfLambertNum));
float3 halfAngle = normalize(normalize(i.viewDir) + normalize(i.lightDir));
fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0, dot(tangentNormal, halfAngle)), _SpecularNum);
fixed3 color = UNITY_LIGHTMODEL_AMBIENT * albedo + lambertColor + specularColor;
return fixed4(color, 1);
}
ENDCG
}
}
}
5、修改渐变纹理设置避免黑点出现
有时候会发现材质球的两端有黑点/白点出现
这个时候极有可能是纹理的图片格式设置不对,将图片纹理的 Wrap Mode 从 Repeat 改为 Clamp 也许就可以避免这种情况,而产生这个的原因是:
浮点数计算可能存在误差,会出现超过1的值(1.00001),如果使用Repeat(重复模式),会舍弃整数部分,保留小数0.00001,这时对应的颜色会是最左边的值,因此会出现黑色。