Unity Shader入门精要笔记(十五):遮罩纹理

本系列文章由Aimar_Johnny编写,欢迎转载,转载请标明出处,谢谢。

http://blog.csdn.net/lzhq1982/article/details/78588206


1、遮罩纹理在游戏里应用很广,前几日我们的美术还让我写了个遮罩纹理的shader,用遮罩纹理的rgb通道分别显示草,石和土地的叠加效果。何为遮罩纹理呢,还拿我刚说的那个举例,为了实现土地上有石头和草的效果,如果简单处理,那就是美术自己画,麻烦不说,而且没办法灵活控制,所以遮罩纹理就大显神威了,草,石头和土地是三张普通纹理,如果我把土地放最下面,上面叠加上草的纹理,草的纹理上扣几个洞,这样下面的土就漏出来了,草上面再叠加上石头纹理,同样石头纹理再扣几个洞,那下面的草和土地也漏出来一部分,这样三者就能呈现出混合的效果了,那个这个扣洞的效果,我们就可以交给一个特殊的纹理来做,比如我拿一张纹理,分别用rgb通道来显示草,石头和土地,那这rgb就是三个洞,这个纹理就是遮罩纹理。


2、书上介绍使用遮罩纹理的流程说的非常好:通过采样得到遮罩纹理的纹素值,然后使用其中某个(或某几个)通道的值(rgb)来与某种表面属性进行相乘,这样,当该通道的值为0时,可以保护表面不受该属性的影响。可以让美术人员更加精准的控制模型表面的各种性质。


3、书上的例子是使用一张高光遮罩纹理,逐像素的控制模型表面的高光反射强度。先上图:


可以看出,遮罩纹理可以更加精细的控制光照细节。


4、直接上代码:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "CustomShader/Texture/MaskShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_BumpTex ("BumpTex", 2D) = "white" {}
		_MaskTex ("MaskTex", 2D) = "white" {}
		_BumpScale ("BumpScale", Float) = 1.0
		_MaskScale ("MaskScale", Float) = 1.0
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_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"

			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpTex;
			float4 _BumpTex_ST;
			sampler2D _MaskTex;
			float4 _MaskTex_ST;
			float _BumpScale;
			float _MaskScale;
			fixed4 _Color;
			fixed4 _Specular;
			float _Gloss;

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
				float3 lightDir : TEXCOORD1;
				float3 viewDir : TEXCOORD2;
			};

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);

				TANGENT_SPACE_ROTATION;
				o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
				o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;

				return o;
			}

			fixed4 frag (v2f i) : SV_Target
			{
				fixed3 lightDir = normalize(i.lightDir);
				fixed3 viewDir = normalize(i.viewDir);

				fixed4 bumpColor = tex2D(_BumpTex, i.uv);
				fixed3 tangentNormal = UnpackNormal(bumpColor);
				tangentNormal.xy *= _BumpScale;
				tangentNormal.z = sqrt(1 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));

				fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;

				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, lightDir));

				fixed mask = tex2D(_MaskTex, i.uv).r * _MaskScale;
				fixed3 halfDir = normalize(viewDir + lightDir);
				fixed3 specular = _LightColor0.rgb * _Specular * pow(max(0, dot(tangentNormal, halfDir)), _Gloss) * mask;

				return fixed4(ambient + diffuse + specular, 1.0);
			}
			ENDCG
		}
	}

	FallBack "Specular"
}
5、我们看看上面的代码,其实去掉光照部分,剩下的代码很少。
首先代码的大部分是用法线纹理实现凹凸效果的部分,这部分不了解的可以看前面有关法线纹理的文章。这里用了在切线空间计算的方法,实则不可取,应该用世界空间计算的方法,但这里不是重点,我们剥离出法线纹理和光照传递计算的部分,重点看遮罩纹理的部分:

fixed mask = tex2D(_MaskTex, i.uv).r * _MaskScale;

遮罩纹理的变量是_MaskTex,上面代码就是从遮罩纹理中采样,并只利用了r通道,然后用_MaskScale对该值进行缩放。我们再看用到mask的地方:

fixed3 specular = _LightColor0.rgb * _Specular * pow(max(0dot(tangentNormal, halfDir)), _Gloss) * mask;

这是处理高光的代码,与以往高光处理的唯一区别是后面乘了这个mask,你可以想想,如果mask是0,则相乘结果是0,也就是无高光,mask越大,高光越强,而这个mask是由遮罩纹理的r决定的,美术人员只需要控制这个遮罩纹理的r通道,就可以控制该物体各个部分的高光效果了,当然_MaskScale也可以间接影响。


5、遮罩纹理虽然叫遮罩,但其实是用纹理的rgba通道间接影响其他纹理的显示效果的一种手段,这点很重要。只要你想得到,遮罩纹理将会发生很大的作用。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值