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

来源:互联网 发布:大连网络教育报名 编辑:程序博客网 时间:2024/06/05 10:05

本系列文章由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通道间接影响其他纹理的显示效果的一种手段,这点很重要。只要你想得到,遮罩纹理将会发生很大的作用。


原创粉丝点击