Unity Shader入门教程(九):基础纹理之渐变纹理与遮罩纹理
发表于2018-06-06
本篇文章和大家介绍下基础纹理中的渐变纹理与遮罩纹理,让大家了解这两种纹理的使用。
利用半兰伯特构建float2变量,以此对一张渐变纹理进行采样。漫反射的颜色靠此方式获得。
Shader "Custom/Edu/RampTexture" { Properties { _Color ("Color", Color) = (1,1,1,1) //_MainTex ("Albedo (RGB)", 2D) = "white" {} _Specular("Specular",Color) = (1,1,1,1) _RampTex("Ramp Texture",2D) = "white"{} _Gloss("Gloss",Range(9,256)) = 40 } SubShader { Pass { Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" fixed4 _Color; //sampler2D _MainTex; 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 = mul(UNITY_MATRIX_MVP,v.vertex); o.worldNormal = mul(v.normal,(float3x3)_World2Object); o.worldPos = mul((float3x3)_Object2World,v.vertex); //o.uv = TRANSFORM_TEX(v.texcoord,_RampTex); return o; } fixed4 frag(v2f i):SV_Target { fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb; float3 worldNormal = normalize(i.worldNormal); float3 worldLightDir = normalize( UnityWorldSpaceLightDir(i.worldPos) ); float halfLambert = dot(worldNormal,worldLightDir) * 0.5 + 0.5; fixed3 diffuseColor = tex2D(_RampTex,float2(halfLambert,halfLambert)).rgb; fixed3 diffuse = diffuseColor * _LightColor0.rgb; float3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos); float3 halfDir = normalize(worldViewDir + worldLightDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow( saturate(dot(worldNormal,halfDir)), _Gloss); return fixed4(ambient + diffuse + specular, 1.0); } ENDCG } } FallBack "Diffuse" }
效果图:
二、遮罩纹理
这遮罩纹理的使用是对高光效果进行遮罩,使用同一组uv坐标,对同一位置处的遮罩纹理进行采样,这里只使用了r分量。
同样,可以分为切线空间下计算以及世界空间下计算。
1.切线空间下的高光遮罩纹理实现:
Shader "Custom/Edu/MaskTexTangent" { Properties { _MainTex("MainTex",2D) = "white"{} _BumpMap("BumpMap",2D) = "white"{} _BumpScale("BumpScale",float) = 1 _SpecularMask("SpecularMask",2D) = "white"{} _Specular("Specular",Color) = (1,1,1,1) _Color("ColorTint",Color) = (1,1,1,1) _Diffuse("DIffuse",Color) = (1,1,1,1) _SpecularScale("SpecularScale",float) = 1.0 _Gloss("Gloss",Range(8,256)) = 8 } SubShader { Pass { Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" sampler2D _MainTex;float4 _MainTex_ST; sampler2D _SpecularMask;float4 _SpecularMask_ST; sampler2D _BumpMap;float4 _BumpMap_ST; float _BumpScale; fixed4 _Specular; fixed4 _Color; fixed4 _Diffuse; float _Gloss; float _SpecularScale; struct a2v { float4 vertex:POSITION; float3 normal:NORMAL; //注意因为我们要使用tangent的w分量,所以这里的类型是float4 float4 tangent:TANGENT; float4 texcoord:TEXCOORD0; }; struct v2f { float4 pos:SV_POSITION; float2 uv:TEXCOORD0; float3 viewDir:TEXCOORD1; float3 lightDir:TEXCOORD2; }; v2f vert(a2v v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP,v.vertex); float3 bionormal = cross(normalize(v.normal),normalize(v.tangent.xyz))*v.tangent.w; //float3x3是一种类型,不需要类型转换时不用加括号 float3x3 rotation = float3x3(v.tangent.xyz,bionormal,v.normal); //or just use TANGENT_SPACE_ROTATION; //注意,注意取xyz分量 o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex)).xyz; o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz; //o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; //o.uv.zw = v.texcoord.xy * _BumpTex_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 { float3 tangentViewDir = normalize(i.viewDir); float3 tangentLightDir = normalize(i.lightDir); //使用的是fixed3类型 fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap,i.uv)); tangentNormal.xy *= _BumpScale; tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy,tangentNormal.xy))); fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo; //半兰伯特模型 //fixed3 halfLambert = dot(tangentNormal,tangentLightDir) * 0.8 + 0.2; //fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert; fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse * saturate(dot(tangentNormal,tangentLightDir)); //潜意识中的错误写法,误以为和渐变纹理的使用方式一样?! fixed3 halfDir = normalize(tangentViewDir + tangentLightDir); //fixed3 maskColor = tex2D(_MaskTex,float2(halfDir,halfDir)).rgb; //正确写法:通过uv对MaskTex对应位置进行采样!!! //fixed3 specularMask = tex2D(_MaskTex,i.uv.xy).rgb * _SpecularScale; //不好意思上面仍然不是正确的写法 //所谓的 specularMask 实际上只利用采样纹理的一个分量通道,这里仅仅利用r。 fixed specularMask = tex2D(_SpecularMask,i.uv).r * _SpecularScale; fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(tangentNormal,halfDir)),_Gloss) * specularMask; return fixed4(ambient + diffuse + specular,1.0); } ENDCG } } }
2.世界空间下高光遮罩纹理实现:
Shader "Custom/Edu/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 } 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; 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)); 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" }
3.效果图:
两种方式看不出任何差别。