Unity shader學(xué)習(xí)---基礎(chǔ)紋理

一.Unity的紋理概念

紋理最基礎(chǔ)的目的:用一張圖片控制模型的外觀(guān)搞乏。使用紋理映射(texture mapping)技術(shù)慢哈,我們可以把一張圖“粘”在模型表面匣砖,逐紋素(texel)(名字是為了和逐像素進(jìn)行區(qū)分)的控制模型的顏色布朦。
建模軟件中利用紋理展開(kāi)技術(shù)把紋理映射坐標(biāo)存儲(chǔ)在每個(gè)頂點(diǎn)上。如下圖

紋理映射坐標(biāo)(UV坐標(biāo)纯出,u為橫向坐標(biāo)蚯妇,v為縱向坐標(biāo))定義了該頂點(diǎn)在紋理中對(duì)應(yīng)的2D坐標(biāo)

UV坐標(biāo)會(huì)被歸一化到[0, 1]范圍內(nèi)。
OpenGL和DirectX在二維紋理空間的坐標(biāo)有差異暂筝。OpenGL原點(diǎn)位于左下角箩言,DirectX位于左上角,Unity默認(rèn)OpenGL模式焕襟。

二.單張紋理.FilterMode屬性

A.單張紋理應(yīng)用

通常使用一張紋理來(lái)代替物體的漫反射顏色
紋理名_ST表示聲明某個(gè)紋理的屬性陨收,name##_ST.xy 存儲(chǔ)縮放值,name##_ST.zw存儲(chǔ)偏移值鸵赖。
結(jié)合之前的光照模型的單張紋理應(yīng)用:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Single Texture" {
    Properties {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Main Tex", 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 _MainTex;
            float4 _MainTex_ST;
            fixed4 _Specular;
            float _Gloss;
            
            struct a2v {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };
            
            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;
                
                o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                // Or just call the built-in function
//              o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                
                return o;
            }
            
            fixed4 frag(v2f i) : SV_Target {
                fixed3 worldNormal = normalize(i.worldNormal);
                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                
                // Use the texture to sample the diffuse color
                fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
                
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
                
                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 "Specular"
}

要點(diǎn)1:tex2D函數(shù)表示對(duì)紋理進(jìn)行采樣务漩,param1是需要被采樣的紋理,param2是float2類(lèi)型的紋理坐標(biāo)它褪,返回計(jì)算得到的紋素值饵骨。
要點(diǎn)2:TRASFORM_TEX實(shí)在UnityCG.cginc中定義的:

//Transform 2D UV by scale/bias property
//param1是頂點(diǎn)的紋理坐標(biāo)
//param2是紋理的名稱(chēng)
#define TRANSFORM_TEX(tex,name)(tex.xy * name##_ST.xy + name##_ST.zw)

效果如下圖:


B.紋理的屬性

為了闡釋紋理的屬性,編寫(xiě)一個(gè)更為純粹的紋理屬性應(yīng)用shader

Shader "TextureProperties" {
    Properties {
        _MainTex ("Main Tex", 2D) = "white" {}
    }
    SubShader {
        Pass { 
            Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;

            struct a2v {
                float4 vertex : POSITION;
                float4 texcoord : TEXCOORD0;
            };
            
            struct v2f {
                float4 position : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
            
            v2f vert(a2v v) {
                v2f o;
                // Transform the vertex from object space to projection space
                o.position = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }
            fixed4 frag(v2f i) : SV_Target {
                fixed4 c = tex2D(_MainTex, i.uv);
                return fixed4(c.rgb, 1.0);
            }
            ENDCG
        }
    } 
    FallBack "Diffuse"
}

用這個(gè)shader生成一個(gè)紋理圖如下:


1.Wrap Mode屬性

決定紋理坐標(biāo)超過(guò)[0,1]范圍后使用哪種平鋪方式列赎。
a.Repeat——重復(fù)紋理采樣宏悦。
這種模式下镐确,如果紋理的坐標(biāo)超過(guò)了1包吝,那么整數(shù)部分將會(huì)被舍棄,而直接使用小數(shù)部分進(jìn)行采用源葫。
b.Clamp模式時(shí)诗越,超過(guò)的部分將會(huì)截取到邊界值,從而形成一個(gè)條形結(jié)構(gòu)息堂。如下圖:


2.FilterMode屬性

決定了當(dāng)紋理由于變換而產(chǎn)生拉伸時(shí)會(huì)使用哪種濾波模式嚷狞。
三種模式:Point模式块促、Bilinear濾波Trilinear濾波
a.Point模式使用了最近鄰濾波床未,在放大或縮小時(shí)竭翠,它的采樣像素?cái)?shù)目通常只有一個(gè),因此圖像看起來(lái)有種像素風(fēng)格的效果薇搁。
b.Bilinear濾波采用了線(xiàn)性濾波斋扰,對(duì)于每個(gè)目標(biāo)像素,它會(huì)找4個(gè)鄰近的像素啃洋,然后對(duì)他們進(jìn)行線(xiàn)性插值混合后得到最終的像素传货,因此圖像看起來(lái)像被模糊了。
c.Trilinear濾波幾乎和Bilinear是一樣的宏娄,只是Trilinear還會(huì)在多級(jí)漸遠(yuǎn)紋理(mipmapping)之間進(jìn)行混合问裕。
效果如下:

三.凹凸映射

目的:使用一張紋理來(lái)修改模型表面的發(fā)現(xiàn)。
方法:1.高度映射 : 使用高度紋理來(lái)模擬表面位移,后得到修改后的法線(xiàn)值孵坚。
2.法線(xiàn)映射:使用一張法線(xiàn)紋理直接存儲(chǔ)表面法線(xiàn)粮宛。

1.法線(xiàn)映射

法線(xiàn)紋理中存儲(chǔ)的就是表面的法線(xiàn)方向,由于法線(xiàn)的方向的分量范圍在[-1,1]卖宠,而像素的分量范圍為[0,1]窟勃,因此我們需要做一個(gè)映射:
pixel =0.5*normal + 0.5
實(shí)際使用:normal = pixel * 2 - 1

模型空間法線(xiàn)紋理:對(duì)于模型自帶的表面法線(xiàn),修改后存儲(chǔ)在此紋理中逗堵。
切線(xiàn)空間法線(xiàn)紋理:對(duì)于模型的每個(gè)定點(diǎn)都有一個(gè)屬于自己的切線(xiàn)空間秉氧,這個(gè)切線(xiàn)空間的原點(diǎn)就是該定點(diǎn)的本身,而z軸是定點(diǎn)的法線(xiàn)方向蜒秤,x軸是切線(xiàn)方向汁咏,而y軸有法線(xiàn)和切線(xiàn)的叉積得到,也被稱(chēng)為是副切線(xiàn)或副法線(xiàn)作媚。

模型頂點(diǎn)的切線(xiàn)空間攘滩。原點(diǎn)對(duì)應(yīng)了頂點(diǎn)坐標(biāo),x軸:切線(xiàn)空間(t),y軸是副切線(xiàn)方向(b),z軸是法線(xiàn)方向(n)

左邊:模型空間下的法線(xiàn)紋理纸泡,右邊:切線(xiàn)空間下的法線(xiàn)紋理

左邊的模型空間法線(xiàn)之所以是五顏六色的漂问,因?yàn)樗蟹ň€(xiàn)所在坐標(biāo)空間是在模型空間,x/y/z區(qū)間都在0到1之間女揭,所以能顯示彩色蚤假。
切線(xiàn)空間下的法線(xiàn)紋理幾乎是淺藍(lán)色,因?yàn)榘赏茫總€(gè)法線(xiàn)方向所在的坐標(biāo)空間是不一樣的磷仰,即是表面各點(diǎn)各自的切線(xiàn)空間。這種法線(xiàn)紋理其實(shí)就是存儲(chǔ)了每個(gè)點(diǎn)在各自的切線(xiàn)空間中的法線(xiàn)擾動(dòng)方向境蔼。

2.實(shí)踐代碼

由于法線(xiàn)紋理存儲(chǔ)的法線(xiàn)是切線(xiàn)空間下的方向灶平,有兩種選擇:
1.在切線(xiàn)空間下計(jì)算光照伺通,需要把光照方向、視角方向變換到切線(xiàn)空間逢享。
2.都在世界空間進(jìn)行光照計(jì)算罐监。
下面是選擇世界空間下計(jì)算光照模型的代碼。

Shader "NormalMapWorldSpace" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _BumpMap ("BumpMap",2D) = "white"{}
        _BumpScale("BumpScale",Range(-2.0,2.0)) = 1.0
        _Specular("Specular",Color)=(1,1,1,1)
        _Diffuse("Diffuse",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8,256)) = 40
    }
    SubShader {
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            fixed4 _Color;
            sampler2D _MainTex; float4 _MainTex_ST;
            sampler2D _BumpMap; float4 _BumpMap_ST;
            float _BumpScale;
            fixed4 _Specular;
            fixed4 _Diffuse;
            float _Gloss;
            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
                float4 texcoord:TEXCOORD0;
                float4 tangent:TANGENT;
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 TtoW0:TEXCOORD0;
                float4 TtoW1:TEXCOORD1;
                float4 TtoW2:TEXCOORD2;
                float4 uv:TEXCOORD3;
            };
            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
              
                float3 worldPos = mul(_Object2World,v.vertex).xyz;
                float3 worldNormal = mul(v.normal,(float3x3)_World2Object);
                //這里要怎樣計(jì)算瞒爬?有兩種方式
                float3 worldTangent = UnityObjectToWorldDir(v.tangent);
                //float3 worldTangent = mul((float3x3)_Object2World,v.tagent);
                //這里要怎樣計(jì)算笑诅?
                //叉積求得
                float3 worldBionormal = cross(worldNormal,worldTangent) * v.tangent.w;
                //計(jì)算了世界空間下頂點(diǎn)切線(xiàn)、副切線(xiàn)和法線(xiàn)的表示疮鲫,并把它們按列擺放得到從切線(xiàn)空間到世界空間的變換矩陣
                //把該矩陣的每一行分別存放在TtoW0吆你、TtoW1、TtoW2中
                //最后把世界空間下頂點(diǎn)位置x俊犯、y妇多、z分量分別存儲(chǔ)在這些變量的w分量中
                o.TtoW0 = float4(worldTangent.x,worldBionormal.x,worldNormal.x,worldPos.x);
                o.TtoW1 = float4(worldTangent.y,worldBionormal.y,worldNormal.y,worldPos.y);
                o.TtoW2 = float4(worldTangent.z,worldBionormal.z,worldNormal.z,worldPos.z);
                //o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                //o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
                o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
                o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap);
               
                return o;
            }
           
            fixed4 frag(v2f i):SV_Target
           {
                //i.uv.xy
                fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
                float3 worldPos = float3(i.TtoW0.w,i.TtoW1.w,i.TtoW2.w);
                float3 worldViewDir =normalize( UnityWorldSpaceViewDir(worldPos) );
                float3 worldLightDir =normalize( UnityWorldSpaceLightDir(worldPos) );
                //不需要這個(gè)值了,所有法線(xiàn)信息都是用bumpMap中的Q嘞馈U咦妗!包括漫反射的計(jì)算绢彤!
                float3 worldNormal = normalize( float3(i.TtoW0.z,i.TtoW1.z,i.TtoW2.z) );
                //UnpackNormal對(duì)法線(xiàn)紋理進(jìn)行采樣和解碼(需要把法線(xiàn)紋理標(biāo)識(shí)成Normal map)
                fixed3 bump = UnpackNormal(tex2D(_BumpMap,i.uv.zw));
                //倘若_BumpScale為0七问,那么bump=float3(0,0,1)就相當(dāng)于入射表面沒(méi)有任何擾動(dòng)
                bump.xy *= _BumpScale;
                //需要保證經(jīng)過(guò)處理的法線(xiàn)仍然是歸一化的單位向量
                //dot計(jì)算時(shí),對(duì)應(yīng)的分量相乘然后相加茫舶,dot(bump.xy,bump.xy)=x*x + y*y
                bump.z = sqrt(1.0- saturate( dot(bump.xy,bump.xy) ));
                //將法線(xiàn)從切線(xiàn)空間轉(zhuǎn)換到世界空間械巡,這里是在模擬bump左乘【切線(xiàn)空間到世界空間的轉(zhuǎn)換矩陣】
                //我潛意識(shí)中兩種種錯(cuò)誤的寫(xiě)法
                //bump = normalize(float3(bump.x * i.TtoW0.xyz,bump.y*i.TtoW1.xyz,bump.z*i.TtoW2.xyz));
                //bump = normalize(float3(i.TtoW0.xyz * bump,i.TtoW1.xyz * bump,
                //正確寫(xiě)法,原來(lái),單個(gè)向量默認(rèn)相當(dāng)于列向量
                bump = normalize(half3(dot(i.TtoW0.xyz,bump),dot(i.TtoW1.xyz,bump),dot(i.TtoW2.xyz,bump)));
                //計(jì)算漫發(fā)射時(shí)同樣適用BumpMap中的法線(xiàn)信息饶氏!
                fixed3 diffuse = _LightColor0.rgb * albedo* saturate(dot(bump,worldLightDir));
                float3 halfDir = normalize(worldViewDir + worldLightDir);
                //一定千萬(wàn)要注意讥耗,前面廢了好大的勁,就是為了在這一步計(jì)算高光時(shí)能用上U钇簟9懦獭!
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(bump,halfDir)),_Gloss);
                return fixed4(ambient + diffuse + specular, 1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

基本思路:
由于我們只能在片元著色器中獲得bumpMap的紋素信息喊崖,所以我們需要在片元著色器中使用切線(xiàn)空間到世界空間的轉(zhuǎn)換矩陣挣磨。首先在頂點(diǎn)著色器中獲得切線(xiàn)空間各個(gè)坐標(biāo)軸在世界空間中的表示,副切線(xiàn)副通過(guò)轉(zhuǎn)換好的worldNormal與worldTangent的叉積獲得荤懂,注意方向靠v.tangent的w分量來(lái)確定茁裙。在v2f結(jié)構(gòu)體聲明了TtoW0、TtoW1势誊、TtoW2三個(gè)紋理寄存器呜达,用來(lái)分別將存放轉(zhuǎn)換矩陣的每一行谣蠢。由于需要在片元著色器用到worldPos來(lái)計(jì)算worldViewDir以及worldLightDir粟耻,所以需要向片元著色器傳遞該信息查近,傳遞方式為將該變量的三個(gè)分量分別存放到TtoW0、TtoW1挤忙、TtoW2的w分量中霜威。
效果如下圖


_BumpScale為-0.8

四.漸變紋理

之前計(jì)算漫反射光照,都是使用表面法線(xiàn)和光照方向的點(diǎn)積結(jié)果與材質(zhì)的反射率相乘册烈。漸變紋理是使用一張漸變紋理來(lái)控制漫反射光照戈泼。

Shader "Ramp Texture" {
    Properties {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _RampTex ("Ramp Tex", 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 : TEXCOORD0;
            };
            
            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;
                
                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;
                
                // Use the texture to sample the diffuse color
                fixed halfLambert  = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
                fixed3 diffuseColor = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb * _Color.rgb;
                
                fixed3 diffuse = _LightColor0.rgb * diffuseColor;
                
                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 "Specular"
}

利用半蘭伯特構(gòu)建float2變量,以此對(duì)一張漸變紋理進(jìn)行采樣赏僧。漫反射的顏色靠此方式獲得大猛。
效果圖:


使用不同的漸變紋理來(lái)控制漫反射光照

五.遮罩紋理

使用遮罩紋理的流程:通過(guò)采樣得到的遮罩紋理的紋素值,然后使用其中某個(gè)(或某幾個(gè))通道的值(如texel.r)來(lái)與某種表面屬性進(jìn)行相乘淀零,這樣挽绩,當(dāng)該通道的值為0時(shí),可以保護(hù)表面不受該屬性的影響驾中。
遮罩紋理的使用是對(duì)高光效果進(jìn)行遮罩唉堪,使用同一組uv坐標(biāo),對(duì)同一位置處的遮罩紋理進(jìn)行采樣肩民,這里只使用了r分量唠亚。
世界空間下高光遮罩紋理實(shí)現(xiàn):

Shader "MaskTexWorld" {
    Properties {
        _Color ("ColorTint", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Gloss ("Gloss", Range(8,256)) = 20
        _BumpMap("BumpMap",2D) = "white"{}
        _BumpScale("BumpScale",Range(-1,1)) = 1
        _Specular("Specular",Color) = (1,1,1,1)
        _SpecularMask("SpecularMask",2D) = "white"{}//高光反射遮罩紋理
        _SpecularScale("SpecularScale",float) = 1.0//控制遮罩影響度的系數(shù)
    }
    SubShader {
        Pass
        {
            Tags{"LgihtMode" = "ForwarBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Gloss;
            sampler2D _BumpMap;
            float _BumpScale;
            fixed4 _Specular;
            sampler2D _SpecularMask;
            float _SpecularScale;
            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
               //注意因?yàn)槲覀円褂胻angent的w分量,所以這里的類(lèi)型是float4
                float4 texcoord:TEXCOORD0;
                float4 tangent:TANGENT;
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 TtoW0:TEXCOORD0;
                float4 TtoW1:TEXCOORD1;
                float4 TtoW2:TEXCOORD2;
                float2 uv:TEXCOORD3;
            };
            v2f vert(a2v v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                
                float3 worldNormal = normalize( UnityObjectToWorldNormal(v.normal) );
                float3 worldTangent = normalize( UnityObjectToWorldDir(v.tangent.xyz) );
                float3 worldBionormal = cross(worldNormal,worldTangent)*v.tangent.w;
                float3 worldPos = mul(_Object2World,v.vertex);
                o.TtoW0 = float4(worldTangent.x,worldBionormal.x,worldNormal.x,worldPos.x);
                o.TtoW1 = float4(worldTangent.y,worldBionormal.y,worldNormal.y,worldPos.y);
                o.TtoW2 = float4(worldTangent.z,worldBionormal.z,worldNormal.z,worldPos.z);
                o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                return o;
            }
            fixed4 frag(v2f i):SV_Target
            {
                float3 worldPos = float3(i.TtoW0.w,i.TtoW1.w,i.TtoW2.w);
                
                float3 worldLightDir =normalize(UnityWorldSpaceLightDir(worldPos));
                
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                float3 bump = UnpackNormal(tex2D(_BumpMap,i.uv));
                bump.xy *= _BumpScale;
                bump.z = sqrt(1-saturate(dot(bump.xy,bump.xy)));
                float3 worldNormal = normalize( float3(dot(bump,i.TtoW0.xyz),dot(bump,i.TtoW1.xyz),dot(bump,i.TtoW2.xyz)) );
                fixed3 albedo = tex2D(_MainTex,i.uv).rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
                fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal,worldLightDir));  
                //通過(guò)uv對(duì)MaskTex對(duì)應(yīng)位置進(jìn)行采樣
                //所謂的 specularMask 實(shí)際上只利用采樣紋理的一個(gè)分量通道持痰,這里僅僅利用r
                fixed specularMask = tex2D(_SpecularMask,i.uv).r * _SpecularScale;
                fixed3 halfDir = normalize(worldLightDir + worldViewDir);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal,halfDir)),_Gloss) * specularMask;
                return fixed4(ambient + diffuse + specular,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

效果如下


左邊使用了遮罩紋理灶搜,右邊沒(méi)有
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市工窍,隨后出現(xiàn)的幾起案子占调,更是在濱河造成了極大的恐慌,老刑警劉巖移剪,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件究珊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡纵苛,警方通過(guò)查閱死者的電腦和手機(jī)剿涮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)攻人,“玉大人取试,你說(shuō)我怎么就攤上這事』澄牵” “怎么了瞬浓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)蓬坡。 經(jīng)常有香客問(wèn)我猿棉,道長(zhǎng)磅叛,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任萨赁,我火速辦了婚禮弊琴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杖爽。我一直安慰自己敲董,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布慰安。 她就那樣靜靜地躺著腋寨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪化焕。 梳的紋絲不亂的頭發(fā)上精置,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音锣杂,去河邊找鬼脂倦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛元莫,可吹牛的內(nèi)容都是我干的赖阻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼踱蠢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼火欧!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起茎截,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤苇侵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后企锌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體榆浓,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年撕攒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了陡鹃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抖坪,死狀恐怖萍鲸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情擦俐,我是刑警寧澤脊阴,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響嘿期,放射性物質(zhì)發(fā)生泄漏品擎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一秽五、第九天 我趴在偏房一處隱蔽的房頂上張望孽查。 院中可真熱鬧饥悴,春花似錦坦喘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至贷揽,卻和暖如春棠笑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背禽绪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工蓖救, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人印屁。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓循捺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親雄人。 傳聞我的和親對(duì)象是個(gè)殘疾皇子从橘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 存儲(chǔ)在每個(gè)頂點(diǎn)上。紋理映射坐標(biāo)定義了該頂點(diǎn)在紋理中對(duì)應(yīng)的 2D 坐標(biāo)础钠。通常恰力,這些坐標(biāo)使用一個(gè)二維變量(u, v)來(lái)...
    李偌閑閱讀 814評(píng)論 0 1
  • 轉(zhuǎn)載自VR設(shè)計(jì)云課堂[http://www.reibang.com/u/c7ffdc4b379e]Unity S...
    水月凡閱讀 1,015評(píng)論 0 0
  • 相關(guān)概念 紋理 用一張圖片控制模型的外觀(guān)具體的做法是將一張圖“黏”在模型表面,逐紋素控制模型的顏色 紋理映射坐標(biāo) ...
    全新的飯閱讀 1,260評(píng)論 0 0
  • 一個(gè)三維場(chǎng)景的畫(huà)面的好壞旗吁,百分之四十取決于模型踩萎,百分之六十取決于貼圖,可見(jiàn)貼圖在畫(huà)面中所占的重要性很钓。在這里我將列舉...
    CXYMichael閱讀 1,603評(píng)論 2 5
  • 毛星云網(wǎng)名「淺墨」驻民,微軟MVP,《Windows游戲編程之從零開(kāi)始》作者 本文將總結(jié)提煉“GPU精粹三部曲“11本...
    貓叔WS閱讀 2,504評(píng)論 0 3