Unity Shader入门学习(1):基础shader

 1.基础光照shader+贴图

//理解shader代码的最重要一步,就是将渲染流水线的步骤与 代码对应

Shader "01"{//这里指定的路径与名字与文件名名不要求一致

	Properties{//属性
	//格式:属性名(显示出来的属性名,类型)=默认值
		_Color("Color",Color) = (1,1,1,1)//颜色
		_Specular("Specular",Color) = (1,1,1,1)//高光颜色
		_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10

		_MainTex("Main Tex",2D)="write"{}//贴图
	}

	SubShader{
	//子属性,可以有多个。用来控制效果。而不同的子属性用来适配不同的显卡 。
	//显卡运行效果时,从第一个subshader开始,若效果都可以实现(由显卡性能决定),则使用第一个subshader,否则自动运行下一个
	//subshader内至少有一个pass块。(pass相当于方法)shader代码就是在pass块里编写的

	Tags {"RenderType" = "Opaque" }
		
		pass {
			Tags{"LightMode" = "ForwardBase"}

			CGPROGRAM                  //Begin

			#pragma vertex vert  
			//顶点函数。这里声明了顶点函数的函数名
			#pragma fragment frag 
			//片元函数。这里声明了片元函数的函数名
			//顶点函数处理顶点,将顶点坐标,从模型空间转换到剪裁空间(处理位置)
			//片元函数处理像素,决定具体像素显示声明(颜色值)

			#include "Lighting.cginc"
		    //取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)

			fixed4 _Color;
			fixed4 _Specular;
			float _Gloss;
			sampler2D _MainTex;
			float4 _MainTex_ST;//纹理属性。ST意指缩放与平移。此值可以让我们获得纹理的缩放平移值
			//_MainTex_ST.xy存缩放,_MainTex_ST.zw存平移
			//这里声明的变量名不是随意起的。是用  _纹理名_ST 的格式固定声明的。

			struct a2v {
				float4 vertex : POSITION;//语义POSITION指模型空间下的顶点位置
				float3 normal :NORMAL;//语义指模型空间下法线
				float4 texcoord:TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;// SV_POSITION指裁剪空间下定点位置。与f.pos = UnityObjectToClipPos(v.vertex);联系
				float3 WorldNormal:TEXCOORD0;
				float3 WorldPos : TEXCOORD1;
				float2 uv:TEXCOORD2;//用于存储纹理坐标
			};

			//顶点函数。如	#pragma vertex vert 所声明
			//顶点shder最重要的工作就是f.pos = UnityObjectToClipPos(v.vertex);即把顶点坐标从模型空间转化到齐次裁剪空间
			v2f vert(a2v v) {
				v2f f;

				f.WorldNormal= UnityObjectToWorldNormal(v.normal);//法线世界化
				//f.WorldNormal = normalize(mul(unity_ObjectToWorld, v.normal));

				f.WorldPos = mul(unity_ObjectToWorld, v.vertex);//点坐标世界化
				//点坐标世界化,是方便通过世界坐标下的点作为一些内置函数的参数,获取光照方向,视线方向等

				f.pos = UnityObjectToClipPos(v.vertex);//点坐标片元化。从模型空间转换到裁剪空间

				f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
				//f.uv=v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
				//_MainTex_ST.xy对纹理进行缩放,_MainTex_ST.zw对纹理偏移

				return f;
			}

			//片元shader主要的功能就是决定片元的颜色。
			//而片元颜色(姑且理解为像素颜色,实际片元是包含像素,深度等信息的集合)又由光照颜色和贴图决定
			//片元包含了比RGBA更多的信息,比如可能有深度值,法线,纹理坐标等等信息。
			fixed4 frag(v2f f) :SV_TARGET0{
			//在frag方法里实现光照就是逐像素光照。相应的,在vert方法里写就是逐顶点光照。

				fixed3 lightDir = normalize(UnityWorldSpaceLightDir(f.WorldPos));
				//单位化光的方向.求光的方向需要知道点的世界坐标,再利用方法UnityWorldSpaceLightDir求得

				fixed3 worldNormal=normalize(f.WorldNormal);
				//单位化法线的方向

				fixed3 albedo =tex2D(_MainTex,f.uv).rgb* _Color.rgb;//albedo是反照率(非镜面),这里指物体本身颜色?
				//tex2D函数负责对纹理进行采样

				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;	//ambient是环境光.
				//环境光乘以albedo后才能使背光处(但受环境光)的物体也显示出颜色

				fixed3 diffuse = _LightColor0.rgb * albedo *( dot(worldNormal,lightDir)*0.5+0.5);//半兰伯特光照模型
				//fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(f.WorldNormal,lightDir));//兰伯特光照模型
				//取得漫反射颜色:光色*albedo*max(光与法线夹角的cos,0)

				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.WorldPos));//单位化视线方向。需要知道点的世界坐标
				fixed3 halfDir = normalize(lightDir + viewDir);//求视线与光线的中间向量(原理想想计算机图形学)
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);//pow方法指取指数。
				//利用Blinn-Phong光照模型取得高光。此模型的核心是取得了视野方向与入射光中向量与法线向量的夹角。如果运用phong模型,则取出射光与视野方向的夹角

				return fixed4(ambient + diffuse + specular , 1);
			}
			ENDCG              //end
		}
	}


	FallBack "Diffuse"//用来指定一个后备方案。
}

 Unity Shader入门学习(1):基础shader_第1张图片

2.引入法线贴图


Shader "02" { 

    Properties{
        _MainTex("Main Tex", 2D) = "white"{} // 纹理贴图
        _Color("Color", Color) = (1,1,1,1)   // 控制纹理贴图的颜色
		_Specular("Specular",Color) = (1,1,1,1)//高光颜色
		_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
        _NormalMap("Normal Map", 2D) = "bump"{} // 表示当该位置没有指定任何法线贴图时,就使用模型顶点自带的法线
        _BumpScale("Bump Scale", Float) = 1  // 法线贴图的凹凸参数。为0表示使用模型原来的发现,为1表示使用法线贴图中的值。大于1则凹凸程度更大。
    }

    SubShader{
        Pass {
            Tags{"LightMode" = "ForwardBase"}

            CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			//取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
 
            fixed4 _Color;
			fixed4 _Specular;
			float _Gloss;
            sampler2D _MainTex;
            float4 _MainTex_ST; //命名是固定的贴图名+后缀"_ST",4个值前两个xy表示缩放,后两个zw表示偏移
            sampler2D _NormalMap;
            float4 _NormalMap_ST; //命名是固定的贴图名+后缀"_ST",4个值前两个xy表示缩放,后两个zw表示偏移
            float _BumpScale;    

            struct a2v
            {
                float4 vertex : POSITION;   
                float3 normal : NORMAL;       //不再使用模型自带的法线。保留该变量是因为切线空间是通过(模型里的)法线和(模型里的)切线确定的。
                float4 tangent : TANGENT;    //tangent.w用来确定切线空间中坐标轴的方向的。
                float4 texcoord : TEXCOORD0; 
            };

            struct v2f
            {
                float4 pos : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
                //float3 WorldNormal : TEXCOORD0;  // 不再使用世界空间下的法线方向
                //float3 WorldPos: TEXCOORD1;

                float4 uv : TEXCOORD0; // xy存储MainTex的纹理坐标,zw存储NormalMap的纹理坐标
				float3 lightDir : TEXCOORD1;   // 切线空间下,平行光的方向
				float3 viewDir : TEXCOORD2;   // 切线空间下,平行光的方向
            };

            // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
            v2f vert(a2v v)
            {
                v2f f;
                f.pos= UnityObjectToClipPos(v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间             
			    
                f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; // 贴图的纹理坐标,等同于f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
                f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw; // 法线贴图的纹理坐标

                TANGENT_SPACE_ROTATION; // 调用这个宏会得到一个矩阵rotation,该矩阵用来把模型空间下的方向转换为切线空间下。注意不是世界空间
                f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); //切线空间下,平行光的方向。ObjSpaceLightDir(v.vertex); 得到模型空间下的平行光方向
				f.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex));//切线空间下,视线的方向

                return f;
            }

            // 要把所有跟法线方向有关的运算,都放到切线空间下。因为从法线贴图中取得的法线方向是在切线空间下的。
            fixed4 frag(v2f f) : SV_Target 
            {
				fixed3 albedo = tex2D(_MainTex,f.uv.xy).rgb* _Color.rgb;//f.uv.xy存储了普通贴图的信息
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;	
                
                //下面求切线空间的法线。先获取法线贴图的颜色信息,再通过内置函数获取法线
                fixed4 normalColor = tex2D(_NormalMap, f.uv.zw); //f.uv.zw存储了法线贴图的信息
                fixed3 tangentNormal = UnpackNormal(normalColor); // 使用Unity内置的方法,从颜色值得到法线在切线空间的方向
                tangentNormal.xy= tangentNormal.xy* _BumpScale; // 控制凹凸程度。只和法线贴图的xy值有关。
                tangentNormal = normalize(tangentNormal);


                // 光照方向与视线方向的单位化。切线空间的转换完成
                fixed3 tangentLightDir = normalize(f.lightDir); // 切线空间下的光照方向
				fixed3 tangentViewDir = normalize(f.viewDir); // 切线空间下的光照方向
                
				fixed3 diffuse = _LightColor0.rgb * albedo *( dot( tangentNormal,tangentLightDir)*0.5+0.5);//半兰伯特光照模型

				fixed3 halfDir = normalize(tangentViewDir  + tangentLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot (tangentNormal,tangentLightDir)),_Gloss);

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

            ENDCG
        }
        
    }
    FallBack "Diffuse"
}

Unity Shader入门学习(1):基础shader_第2张图片

3.引入渐变纹理+高光遮罩+边缘光

Shader "03" { 

    Properties{
        _MainTex("Main Tex", 2D) = "white"{} // 纹理贴图
        _Color("Color", Color) = (1,1,1,1)   // 控制纹理贴图的颜色
		_Specular("Specular",Color) = (1,1,1,1)//高光颜色
		_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
        _NormalMap("Normal Map", 2D) = "bump"{} // 表示当该位置没有指定任何法线贴图时,就使用模型顶点自带的法线
        _BumpScale("Bump Scale", Float) = 1  // 法线贴图的凹凸参数。为0表示使用模型原来的发现,为1表示使用法线贴图中的值。大于1则凹凸程度更大。

		_RampTex("Ramp Tex",2D)="white"{}//渐变纹理贴图

		_SpecularMask("Specular Mask",2D)="white"{}//高光遮罩贴图
		_SpecularScale("Specular Scale",Range(0,1))=1//控制高光遮罩影响度系数

		_RimColor("RimColor",Color)=(1,1,1,1)//边缘光颜色
		_RimLength("RimLength",Range(0,0.8))=0.3
		_RimPower("RimPower",Range(0.5,3))=1

    }

    SubShader{
        Pass {
            Tags{"LightMode" = "ForwardBase"}

            CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			// 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
 
            fixed4 _Color;
			fixed4 _Specular;
			fixed4 _RimColor;
			float _Gloss;
		    float _BumpScale;    
			float _SpecularScale;
			float _RimLength; 
			float _RimPower; 
            sampler2D _MainTex;
			sampler2D _NormalMap;
			sampler2D _SpecularMask;
			sampler2D _RampTex;
            float4 _MainTex_ST; //让主纹理,高光遮罩纹理共同使用这个纹理属性变量
			float4 _NormalMap_ST;


            struct a2v
            {
                float4 vertex : POSITION;   
                float3 normal : NORMAL;        // 不再使用模型自带的法线。保留该变量是因为切线空间是通过(模型里的)法线和(模型里的)切线确定的。
                float4 texcoord : TEXCOORD0; //第一组纹理坐标。片元着色器会使用uv纹理坐标对其采样。

			    float4 tangent : TANGENT;    // tangent.w用来确定切线空间中坐标轴的方向的。
            };

            struct v2f
            {
                float4 pos : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
                //float3 WorldNormal : TEXCOORD0;  // 不再使用世界空间下的法线方向
                //float3 WorldPos: TEXCOORD1;
                float4 uv : TEXCOORD0; // xy存储MainTex的纹理坐标,zw存储NormalMap的纹理坐标
				float3 lightDir : TEXCOORD1;   // 切线空间下,平行光的方向
				float3 viewDir : TEXCOORD2;   // 切线空间下,平行光的方向

            };

            // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
            v2f vert(a2v v)
            {
                v2f f;
                f.pos= UnityObjectToClipPos(v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间	
                f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; // 贴图的纹理坐标,等同于f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
                f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw; // 法线贴图的纹理坐标

                TANGENT_SPACE_ROTATION; // 调用这个宏会得到一个矩阵rotation,该矩阵用来把模型空间下的方向转换为切线空间下。注意不是世界空间
                f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); //切线空间下,平行光的方向。ObjSpaceLightDir(v.vertex); 得到模型空间下的平行光方向
				f.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex));//切线空间下,视线的方向

                return f;
            }

            // 要把所有跟法线方向有关的运算,都放到切线空间下。因为从法线贴图中取得的法线方向是在切线空间下的。
            fixed4 frag(v2f f) : SV_Target 
            {
				fixed3 albedo =tex2D(_MainTex,f.uv.xy).rgb* _Color.rgb;//f.uv.xy存储了普通贴图的信息
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;	
                
                //下面求切线空间的法线。先获取法线贴图的颜色信息,再通过内置函数获取法线
                fixed4 normalColor = tex2D(_NormalMap, f.uv.zw); //f.uv.zw存储了法线贴图的信息
                fixed3 tangentNormal = UnpackNormal(normalColor); // 使用Unity内置的方法,从颜色值得到法线在切线空间的方向
                tangentNormal.xy = tangentNormal.xy * _BumpScale; // 控制凹凸程度。只和法线贴图的xy值有关。
                tangentNormal = normalize(tangentNormal);

                // 光照方向与视线方向的单位化。切线空间的转换完成
                fixed3 tangentLightDir = normalize(f.lightDir); // 切线空间下的光照方向
				fixed3 tangentViewDir = normalize(f.viewDir); // 切线空间下的光照方向

				//fixed3 diffuse = _LightColor0.rgb * albedo *( dot( tangentNormal,tangentLightDir)*0.5+0.5);//半兰伯特光照模型
                
				//以下是尝试使用渐变纹理的效果。但实际使用后,并不能体现高光(因为渐变贴图绘制时已经考虑高光了),也无法很好体现法线贴图
				fixed halfLambert =dot( tangentNormal,tangentLightDir)*0.5+0.5;//半兰伯特
				fixed3 diffuseColor=tex2D(_RampTex,fixed2(halfLambert,halfLambert)).rgb*_Color.rgb;
				//让半兰伯特的取值范围映射在(0,1),用其数值构建一套纹理坐标,并用这套坐标对渐变纹理采样。
				fixed3 diffuse=diffuseColor*_LightColor0.rgb;

				//下面是边缘光的初步尝试
				if(dot(tangentViewDir,tangentNormal)<_RimLength){
					 diffuse+=_RimPower*(_RimColor.rgb*lerp(1,0,dot(tangentViewDir,tangentNormal)/_RimLength));
				}

				fixed3 halfDir = normalize(tangentViewDir  + tangentLightDir);//求视线与光线的中间向量
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot (tangentNormal,tangentLightDir)),_Gloss);
				fixed specularMask=tex2D(_SpecularMask,f.uv).r*_SpecularScale;//对遮罩纹理采样后,用r分量计算掩码值并与高光参数相乘。黑色的r值为0,白1
				specular=specular*specularMask;

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

            ENDCG
        }
        
    }
    FallBack "Diffuse"
}

Unity Shader入门学习(1):基础shader_第3张图片

Unity Shader入门学习(1):基础shader_第4张图片

4.透明效果

//想要实现透明效果,有两种方式。一种是透明度测试,一种是透明度混合。
//透明度测试简单粗暴,将低于某个值的像素直接剔除。无法实现半透明

//透明度测试的代码需要添加如下内容:
//1.Propertiers{...  _CutOff("Alpha CutOff",Range(0,1))=0.5}  (_CutOff参数范围【0,1】。是进行透明度测试时的判断条件)
//2.SubShader{... Tags{"Queue"="AlphaTest","IgnoreProjector"="True","RenderType"="TransparentCutOut"} ...  } 
//(SubShader的Queue标签决定模型归于哪个序列,见课本提及的五个渲染序列)
//3.fixed _CutOff
//4.fixed4 frag(v2f f):SV_Target{...  fixed4 texColor=tex2D(_MainTex,i.uv);    Clip(texColor.a-_CutOff);}
//(Clip方法会判断其参数即texColor.a-_CutOff是否为负数,是则舍弃该片元的输出)

//下面是透明度混合的代码(下面代码无法双面渲染。双面渲染要开启两个pass。第一个pass渲染背面(Cull Front),第二个渲染前面。其他地方一致)
Shader "07" { 

    Properties{
        _MainTex("Main Tex", 2D) = "white"{} // 纹理贴图
        _Color("Color", Color) = (1,1,1,1)   // 控制纹理贴图的颜色
		_Specular("Specular",Color) = (1,1,1,1)//高光颜色
		_Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
        _NormalMap("Normal Map", 2D) = "bump"{} // 表示当该位置没有指定任何法线贴图时,就使用模型顶点自带的法线
        _BumpScale("Bump Scale", Float) = 1  // 法线贴图的凹凸参数。为0表示使用模型原来的发现,为1表示使用法线贴图中的值。大于1则凹凸程度更大。

		_RampTex("Ramp Tex",2D)="white"{}//渐变纹理贴图

		_SpecularMask("Specular Mask",2D)="white"{}//高光遮罩贴图
		_SpecularScale("Specular Scale",Float)=1//控制高光遮罩影响度系数

		_AlphaScale("Alpha Scale",Range(0,1))=1
    }

    SubShader{
		Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}  

		pass{
			//这个pass块开启深度写入,但不输出颜色,目的仅为把该模型的深度值写入深度缓冲
			//这样可以得到逐像素级别的正确深度信息(否则,模型有交叉结构时无法得到正确效果)
			Zwrite On
			ColorMask 0
		}

        Pass {

            Tags{"LightMode" = "ForwardBase"}
			
			ZWrite Off//关闭深度写入。详见课本
			Blend SrcAlpha OneMinusSrcAlpha//开启并设置pass的混合模式。(有多种模式可以选择)

            CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			// 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
 
            fixed4 _Color;
			fixed4 _Specular;
			float _Gloss;
		    float _BumpScale;    
			float _SpecularScale;
            sampler2D _MainTex;
			sampler2D _NormalMap;
			sampler2D _SpecularMask;
			sampler2D _RampTex;
            float4 _MainTex_ST; //让主纹理,法线纹理,高光遮罩纹理共同使用这个纹理属性变量
			fixed _AlphaScale;


            struct a2v
            {
                float4 vertex : POSITION;   
                float3 normal : NORMAL;        // 不再使用模型自带的法线。保留该变量是因为切线空间是通过(模型里的)法线和(模型里的)切线确定的。
                float4 texcoord : TEXCOORD0; //第一组纹理坐标。片元着色器会使用uv纹理坐标对其采样。

			    float4 tangent : TANGENT;    // tangent.w用来确定切线空间中坐标轴的方向的。
            };

            struct v2f
            {
                float4 pos : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
                //float3 WorldNormal : TEXCOORD0;  // 不再使用世界空间下的法线方向
                //float3 WorldPos: TEXCOORD1;
                float2 uv : TEXCOORD0; // xy存储MainTex的纹理坐标,zw存储NormalMap的纹理坐标
				float3 lightDir : TEXCOORD1;   // 切线空间下,平行光的方向
				float3 viewDir : TEXCOORD2;   // 切线空间下,平行光的方向
            };

            // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
            v2f vert(a2v v)
            {
                v2f f;
                f.pos= UnityObjectToClipPos(v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间	
                f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; // 贴图的纹理坐标,等同于f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);


                TANGENT_SPACE_ROTATION; // 调用这个宏会得到一个矩阵rotation,该矩阵用来把模型空间下的方向转换为切线空间下。注意不是世界空间
                f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); //切线空间下,平行光的方向。ObjSpaceLightDir(v.vertex); 得到模型空间下的平行光方向
				f.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex));//切线空间下,视线的方向

                return f;
            }

            // 要把所有跟法线方向有关的运算,都放到切线空间下。因为从法线贴图中取得的法线方向是在切线空间下的。
            fixed4 frag(v2f f) : SV_Target 
            {
			    fixed4 texColor=tex2D(_MainTex,f.uv);
				fixed3 albedo =texColor.rgb* _Color.rgb;//f.uv.xy存储了普通贴图的信息
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;	
                
                //下面求切线空间的法线。先获取法线贴图的颜色信息,再通过内置函数获取法线
                fixed4 normalColor = tex2D(_NormalMap, f.uv); //f.uv.zw存储了法线贴图的信息
                fixed3 tangentNormal = UnpackNormal(normalColor); // 使用Unity内置的方法,从颜色值得到法线在切线空间的方向
                tangentNormal.xy = tangentNormal.xy * _BumpScale; // 控制凹凸程度。只和法线贴图的xy值有关。
                tangentNormal = normalize(tangentNormal);


                // 光照方向与视线方向的单位化。切线空间的转换完成
                fixed3 tangentLightDir = normalize(f.lightDir); // 切线空间下的光照方向
				fixed3 tangentViewDir = normalize(f.viewDir); // 切线空间下的光照方向


				fixed3 diffuse = _LightColor0.rgb * albedo *( dot( tangentNormal,tangentLightDir)*0.5+0.5);//半兰伯特光照模型
                


				fixed3 halfDir = normalize(tangentViewDir  + tangentLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot (tangentNormal,tangentLightDir)),_Gloss);
				fixed specularMask=tex2D(_SpecularMask,f.uv).r*_SpecularScale;//对遮罩纹理采样后,用r分量计算掩码值并与高光参数相乘。黑色的r值为0,白1
				specular=specular*specularMask;

				return fixed4(ambient + diffuse + specular , texColor.a*_AlphaScale);//设置着色器返回值的透明通道
            }

            ENDCG
        }
        
    }
    FallBack "Diffuse"
}

Unity Shader入门学习(1):基础shader_第5张图片

Unity Shader入门学习(1):基础shader_第6张图片

你可能感兴趣的:(unity,游戏引擎,贴图)