写在前面
由于我还是处于刚刚入门(其实还是小菜鸡...)的阶段,关于渐变纹理目前主要是学习一下如何通过渐变纹理控制漫反射光照。
这种用渐变纹理控制颜色效果的想法,是Valve公司(提出半兰伯特光照技术的公司)他们提出来的,主要想要用来渲染游戏中具有卡通、插画风格的效果。
原理部分真得不想说太多了,其实本来想借着ramp纹理的功夫深扒一扒从Team Fortress 2开始到现在的应用过程,顺藤摸瓜偶遇了Toon Shader,突然醒悟——Ramp纹理原来只是卡通渲染这块大蛋糕上的小小一隅,立刻放弃要深究的念头,打算打牢基础再说!
关于遮罩纹理:遮罩纹理(mask texture)能做的事情有很多,这次仅作纯粹的记录用它来控制高光的使用效果。
存一些发现的比较有意思的帖子,后续再回来看:
Blender Toon Shader教程跟做(通用Shader) - 知乎 (zhihu.com)
Unity Toon Shader 卡通着色器(一):卡通着色_Sorumi的博客-CSDN博客
[译] 实现Unity 后处理特效 (3) _渐变 Ramp - 知乎 (zhihu.com)
Shader "Unity Shaders Book/Chapter 7/Ramp Texture"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
_Specular ("Specular", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
_RampTex ("RampTex", 2D) = "white" {}
}
SubShader
{
Tags { "LightMode" = "ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
sampler2D _RampTex;
float4 _RampTex_ST;
fixed3 _Color;
fixed3 _Specular;
float _Gloss;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
};
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _RampTex); //重点1!
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldlightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldlightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular * pow(saturate(dot(halfDir, worldNormal)), _Gloss);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
//计算半兰伯特的值
fixed halfLambert = dot(worldNormal, worldlightDir) * 0.5 + 0.5;
//用半兰伯特去采样这个一级纹理,y方向上不会改变
fixed3 diffuseColor = tex2D(_RampTex, float2(halfLambert, halfLambert)).rgb * _Color;
fixed3 diffuse = _LightColor0.rgb * diffuseColor * diffuseColor;
return fixed4(diffuse + specular + ambient, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}
渐变纹理分别为:
Game视图中的渲染效果:
Shader "Unity Shaders Book/Chapter 7/Mask Texture2"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
_Specular ("Specular", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
_MainTex ("MainTex", 2D) = "white" {}
_SpecularMask ("SpecularMask", 2D) = "white" {}
_SpecularScale ("SpecualrScale", float) = 1
_NormalTex ("NormalTex", 2D) = "bump" {}
_NormalScale ("NormalScale", Range(-1.0, 1.0)) = 1
}
SubShader
{
Tags { "LightMode" = "ForwardBase" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
fixed4 _Specular;
float _Gloss;
sampler2D _MainTex;
sampler2D _SpecularMask;
float _SpecularScale;
sampler2D _NormalTex;
float _NormalScale;
float4 _MainTex_ST;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
float4 tangent : TANGENT;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float3 lightDir : TEXCOORD1;
float3 viewDir : TEXCOORD2;
};
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
TANGENT_SPACE_ROTATION; //获得rotation
o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 lightDir = normalize(i.lightDir);
fixed3 viewDir = normalize(i.viewDir);
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 tangentNormal = UnpackNormal(tex2D(_NormalTex, i.uv));
tangentNormal.xy *= _NormalScale;
tangentNormal.z = sqrt(1 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
fixed halfLambert = dot(tangentNormal, lightDir) * 0.5 + 0.5;
fixed3 diffuse = _LightColor0.rgb * albedo * halfLambert;
fixed specularMask = tex2D(_SpecularMask, i.uv).r * _SpecularScale;
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(halfDir, tangentNormal)), _Gloss) * specularMask * albedo;
fixed3 specular2 = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(halfDir, tangentNormal)), _Gloss);
return fixed4(diffuse + specular + ambient, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}
需要加入漫反射纹理、法线纹理以及用到的高光遮罩纹理。
左(仅用了半兰伯特)中间(漫反射+高光无遮罩)右边(漫反射+高光有遮罩)
从效果看明显右边更接近实际~中间的高光太水亮、太假,左边直接无高光好像少了点什么。