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"//用来指定一个后备方案。
}
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"
}
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"
}
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"
}