当前位置:   article > 正文

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

unity shader

 1.基础光照shader+贴图

  1. //理解shader代码的最重要一步,就是将渲染流水线的步骤与 代码对应
  2. Shader "01"{//这里指定的路径与名字与文件名名不要求一致
  3. Properties{//属性
  4. //格式:属性名(显示出来的属性名,类型)=默认值
  5. _Color("Color",Color) = (1,1,1,1)//颜色
  6. _Specular("Specular",Color) = (1,1,1,1)//高光颜色
  7. _Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
  8. _MainTex("Main Tex",2D)="write"{}//贴图
  9. }
  10. SubShader{
  11. //子属性,可以有多个。用来控制效果。而不同的子属性用来适配不同的显卡 。
  12. //显卡运行效果时,从第一个subshader开始,若效果都可以实现(由显卡性能决定),则使用第一个subshader,否则自动运行下一个
  13. //subshader内至少有一个pass块。(pass相当于方法)shader代码就是在pass块里编写的
  14. Tags {"RenderType" = "Opaque" }
  15. pass {
  16. Tags{"LightMode" = "ForwardBase"}
  17. CGPROGRAM //Begin
  18. #pragma vertex vert
  19. //顶点函数。这里声明了顶点函数的函数名
  20. #pragma fragment frag
  21. //片元函数。这里声明了片元函数的函数名
  22. //顶点函数处理顶点,将顶点坐标,从模型空间转换到剪裁空间(处理位置)
  23. //片元函数处理像素,决定具体像素显示声明(颜色值)
  24. #include "Lighting.cginc"
  25. //取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
  26. fixed4 _Color;
  27. fixed4 _Specular;
  28. float _Gloss;
  29. sampler2D _MainTex;
  30. float4 _MainTex_ST;//纹理属性。ST意指缩放与平移。此值可以让我们获得纹理的缩放平移值
  31. //_MainTex_ST.xy存缩放,_MainTex_ST.zw存平移
  32. //这里声明的变量名不是随意起的。是用 _纹理名_ST 的格式固定声明的。
  33. struct a2v {
  34. float4 vertex : POSITION;//语义POSITION指模型空间下的顶点位置
  35. float3 normal :NORMAL;//语义指模型空间下法线
  36. float4 texcoord:TEXCOORD0;
  37. };
  38. struct v2f {
  39. float4 pos : SV_POSITION;// SV_POSITION指裁剪空间下定点位置。与f.pos = UnityObjectToClipPos(v.vertex);联系
  40. float3 WorldNormal:TEXCOORD0;
  41. float3 WorldPos : TEXCOORD1;
  42. float2 uv:TEXCOORD2;//用于存储纹理坐标
  43. };
  44. //顶点函数。如 #pragma vertex vert 所声明
  45. //顶点shder最重要的工作就是f.pos = UnityObjectToClipPos(v.vertex);即把顶点坐标从模型空间转化到齐次裁剪空间
  46. v2f vert(a2v v) {
  47. v2f f;
  48. f.WorldNormal= UnityObjectToWorldNormal(v.normal);//法线世界化
  49. //f.WorldNormal = normalize(mul(unity_ObjectToWorld, v.normal));
  50. f.WorldPos = mul(unity_ObjectToWorld, v.vertex);//点坐标世界化
  51. //点坐标世界化,是方便通过世界坐标下的点作为一些内置函数的参数,获取光照方向,视线方向等
  52. f.pos = UnityObjectToClipPos(v.vertex);//点坐标片元化。从模型空间转换到裁剪空间
  53. f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
  54. //f.uv=v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
  55. //_MainTex_ST.xy对纹理进行缩放,_MainTex_ST.zw对纹理偏移
  56. return f;
  57. }
  58. //片元shader主要的功能就是决定片元的颜色。
  59. //而片元颜色(姑且理解为像素颜色,实际片元是包含像素,深度等信息的集合)又由光照颜色和贴图决定
  60. //片元包含了比RGBA更多的信息,比如可能有深度值,法线,纹理坐标等等信息。
  61. fixed4 frag(v2f f) :SV_TARGET0{
  62. //在frag方法里实现光照就是逐像素光照。相应的,在vert方法里写就是逐顶点光照。
  63. fixed3 lightDir = normalize(UnityWorldSpaceLightDir(f.WorldPos));
  64. //单位化光的方向.求光的方向需要知道点的世界坐标,再利用方法UnityWorldSpaceLightDir求得
  65. fixed3 worldNormal=normalize(f.WorldNormal);
  66. //单位化法线的方向
  67. fixed3 albedo =tex2D(_MainTex,f.uv).rgb* _Color.rgb;//albedo是反照率(非镜面),这里指物体本身颜色?
  68. //tex2D函数负责对纹理进行采样
  69. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo; //ambient是环境光.
  70. //环境光乘以albedo后才能使背光处(但受环境光)的物体也显示出颜色
  71. fixed3 diffuse = _LightColor0.rgb * albedo *( dot(worldNormal,lightDir)*0.5+0.5);//半兰伯特光照模型
  72. //fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(f.WorldNormal,lightDir));//兰伯特光照模型
  73. //取得漫反射颜色:光色*albedo*max(光与法线夹角的cos,0)
  74. fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.WorldPos));//单位化视线方向。需要知道点的世界坐标
  75. fixed3 halfDir = normalize(lightDir + viewDir);//求视线与光线的中间向量(原理想想计算机图形学)
  76. fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);//pow方法指取指数。
  77. //利用Blinn-Phong光照模型取得高光。此模型的核心是取得了视野方向与入射光中向量与法线向量的夹角。如果运用phong模型,则取出射光与视野方向的夹角
  78. return fixed4(ambient + diffuse + specular , 1);
  79. }
  80. ENDCG //end
  81. }
  82. }
  83. FallBack "Diffuse"//用来指定一个后备方案。
  84. }

 

2.引入法线贴图

  1. Shader "02" {
  2. Properties{
  3. _MainTex("Main Tex", 2D) = "white"{} // 纹理贴图
  4. _Color("Color", Color) = (1,1,1,1) // 控制纹理贴图的颜色
  5. _Specular("Specular",Color) = (1,1,1,1)//高光颜色
  6. _Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
  7. _NormalMap("Normal Map", 2D) = "bump"{} // 表示当该位置没有指定任何法线贴图时,就使用模型顶点自带的法线
  8. _BumpScale("Bump Scale", Float) = 1 // 法线贴图的凹凸参数。为0表示使用模型原来的发现,为1表示使用法线贴图中的值。大于1则凹凸程度更大。
  9. }
  10. SubShader{
  11. Pass {
  12. Tags{"LightMode" = "ForwardBase"}
  13. CGPROGRAM
  14. #pragma vertex vert
  15. #pragma fragment frag
  16. #include "Lighting.cginc"
  17. //取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
  18. fixed4 _Color;
  19. fixed4 _Specular;
  20. float _Gloss;
  21. sampler2D _MainTex;
  22. float4 _MainTex_ST; //命名是固定的贴图名+后缀"_ST",4个值前两个xy表示缩放,后两个zw表示偏移
  23. sampler2D _NormalMap;
  24. float4 _NormalMap_ST; //命名是固定的贴图名+后缀"_ST",4个值前两个xy表示缩放,后两个zw表示偏移
  25. float _BumpScale;
  26. struct a2v
  27. {
  28. float4 vertex : POSITION;
  29. float3 normal : NORMAL; //不再使用模型自带的法线。保留该变量是因为切线空间是通过(模型里的)法线和(模型里的)切线确定的。
  30. float4 tangent : TANGENT; //tangent.w用来确定切线空间中坐标轴的方向的。
  31. float4 texcoord : TEXCOORD0;
  32. };
  33. struct v2f
  34. {
  35. float4 pos : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
  36. //float3 WorldNormal : TEXCOORD0; // 不再使用世界空间下的法线方向
  37. //float3 WorldPos: TEXCOORD1;
  38. float4 uv : TEXCOORD0; // xy存储MainTex的纹理坐标,zw存储NormalMap的纹理坐标
  39. float3 lightDir : TEXCOORD1; // 切线空间下,平行光的方向
  40. float3 viewDir : TEXCOORD2; // 切线空间下,平行光的方向
  41. };
  42. // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
  43. v2f vert(a2v v)
  44. {
  45. v2f f;
  46. f.pos= UnityObjectToClipPos(v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间
  47. f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; // 贴图的纹理坐标,等同于f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
  48. f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw; // 法线贴图的纹理坐标
  49. TANGENT_SPACE_ROTATION; // 调用这个宏会得到一个矩阵rotation,该矩阵用来把模型空间下的方向转换为切线空间下。注意不是世界空间
  50. f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); //切线空间下,平行光的方向。ObjSpaceLightDir(v.vertex); 得到模型空间下的平行光方向
  51. f.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex));//切线空间下,视线的方向
  52. return f;
  53. }
  54. // 要把所有跟法线方向有关的运算,都放到切线空间下。因为从法线贴图中取得的法线方向是在切线空间下的。
  55. fixed4 frag(v2f f) : SV_Target
  56. {
  57. fixed3 albedo = tex2D(_MainTex,f.uv.xy).rgb* _Color.rgb;//f.uv.xy存储了普通贴图的信息
  58. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
  59. //下面求切线空间的法线。先获取法线贴图的颜色信息,再通过内置函数获取法线
  60. fixed4 normalColor = tex2D(_NormalMap, f.uv.zw); //f.uv.zw存储了法线贴图的信息
  61. fixed3 tangentNormal = UnpackNormal(normalColor); // 使用Unity内置的方法,从颜色值得到法线在切线空间的方向
  62. tangentNormal.xy= tangentNormal.xy* _BumpScale; // 控制凹凸程度。只和法线贴图的xy值有关。
  63. tangentNormal = normalize(tangentNormal);
  64. // 光照方向与视线方向的单位化。切线空间的转换完成
  65. fixed3 tangentLightDir = normalize(f.lightDir); // 切线空间下的光照方向
  66. fixed3 tangentViewDir = normalize(f.viewDir); // 切线空间下的光照方向
  67. fixed3 diffuse = _LightColor0.rgb * albedo *( dot( tangentNormal,tangentLightDir)*0.5+0.5);//半兰伯特光照模型
  68. fixed3 halfDir = normalize(tangentViewDir + tangentLightDir);
  69. fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot (tangentNormal,tangentLightDir)),_Gloss);
  70. return fixed4(ambient + diffuse + specular , 1.0);
  71. }
  72. ENDCG
  73. }
  74. }
  75. FallBack "Diffuse"
  76. }

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

  1. Shader "03" {
  2. Properties{
  3. _MainTex("Main Tex", 2D) = "white"{} // 纹理贴图
  4. _Color("Color", Color) = (1,1,1,1) // 控制纹理贴图的颜色
  5. _Specular("Specular",Color) = (1,1,1,1)//高光颜色
  6. _Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
  7. _NormalMap("Normal Map", 2D) = "bump"{} // 表示当该位置没有指定任何法线贴图时,就使用模型顶点自带的法线
  8. _BumpScale("Bump Scale", Float) = 1 // 法线贴图的凹凸参数。为0表示使用模型原来的发现,为1表示使用法线贴图中的值。大于1则凹凸程度更大。
  9. _RampTex("Ramp Tex",2D)="white"{}//渐变纹理贴图
  10. _SpecularMask("Specular Mask",2D)="white"{}//高光遮罩贴图
  11. _SpecularScale("Specular Scale",Range(0,1))=1//控制高光遮罩影响度系数
  12. _RimColor("RimColor",Color)=(1,1,1,1)//边缘光颜色
  13. _RimLength("RimLength",Range(0,0.8))=0.3
  14. _RimPower("RimPower",Range(0.5,3))=1
  15. }
  16. SubShader{
  17. Pass {
  18. Tags{"LightMode" = "ForwardBase"}
  19. CGPROGRAM
  20. #pragma vertex vert
  21. #pragma fragment frag
  22. #include "Lighting.cginc"
  23. // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
  24. fixed4 _Color;
  25. fixed4 _Specular;
  26. fixed4 _RimColor;
  27. float _Gloss;
  28. float _BumpScale;
  29. float _SpecularScale;
  30. float _RimLength;
  31. float _RimPower;
  32. sampler2D _MainTex;
  33. sampler2D _NormalMap;
  34. sampler2D _SpecularMask;
  35. sampler2D _RampTex;
  36. float4 _MainTex_ST; //让主纹理,高光遮罩纹理共同使用这个纹理属性变量
  37. float4 _NormalMap_ST;
  38. struct a2v
  39. {
  40. float4 vertex : POSITION;
  41. float3 normal : NORMAL; // 不再使用模型自带的法线。保留该变量是因为切线空间是通过(模型里的)法线和(模型里的)切线确定的。
  42. float4 texcoord : TEXCOORD0; //第一组纹理坐标。片元着色器会使用uv纹理坐标对其采样。
  43. float4 tangent : TANGENT; // tangent.w用来确定切线空间中坐标轴的方向的。
  44. };
  45. struct v2f
  46. {
  47. float4 pos : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
  48. //float3 WorldNormal : TEXCOORD0; // 不再使用世界空间下的法线方向
  49. //float3 WorldPos: TEXCOORD1;
  50. float4 uv : TEXCOORD0; // xy存储MainTex的纹理坐标,zw存储NormalMap的纹理坐标
  51. float3 lightDir : TEXCOORD1; // 切线空间下,平行光的方向
  52. float3 viewDir : TEXCOORD2; // 切线空间下,平行光的方向
  53. };
  54. // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
  55. v2f vert(a2v v)
  56. {
  57. v2f f;
  58. f.pos= UnityObjectToClipPos(v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间
  59. f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; // 贴图的纹理坐标,等同于f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
  60. f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw; // 法线贴图的纹理坐标
  61. TANGENT_SPACE_ROTATION; // 调用这个宏会得到一个矩阵rotation,该矩阵用来把模型空间下的方向转换为切线空间下。注意不是世界空间
  62. f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); //切线空间下,平行光的方向。ObjSpaceLightDir(v.vertex); 得到模型空间下的平行光方向
  63. f.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex));//切线空间下,视线的方向
  64. return f;
  65. }
  66. // 要把所有跟法线方向有关的运算,都放到切线空间下。因为从法线贴图中取得的法线方向是在切线空间下的。
  67. fixed4 frag(v2f f) : SV_Target
  68. {
  69. fixed3 albedo =tex2D(_MainTex,f.uv.xy).rgb* _Color.rgb;//f.uv.xy存储了普通贴图的信息
  70. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
  71. //下面求切线空间的法线。先获取法线贴图的颜色信息,再通过内置函数获取法线
  72. fixed4 normalColor = tex2D(_NormalMap, f.uv.zw); //f.uv.zw存储了法线贴图的信息
  73. fixed3 tangentNormal = UnpackNormal(normalColor); // 使用Unity内置的方法,从颜色值得到法线在切线空间的方向
  74. tangentNormal.xy = tangentNormal.xy * _BumpScale; // 控制凹凸程度。只和法线贴图的xy值有关。
  75. tangentNormal = normalize(tangentNormal);
  76. // 光照方向与视线方向的单位化。切线空间的转换完成
  77. fixed3 tangentLightDir = normalize(f.lightDir); // 切线空间下的光照方向
  78. fixed3 tangentViewDir = normalize(f.viewDir); // 切线空间下的光照方向
  79. //fixed3 diffuse = _LightColor0.rgb * albedo *( dot( tangentNormal,tangentLightDir)*0.5+0.5);//半兰伯特光照模型
  80. //以下是尝试使用渐变纹理的效果。但实际使用后,并不能体现高光(因为渐变贴图绘制时已经考虑高光了),也无法很好体现法线贴图
  81. fixed halfLambert =dot( tangentNormal,tangentLightDir)*0.5+0.5;//半兰伯特
  82. fixed3 diffuseColor=tex2D(_RampTex,fixed2(halfLambert,halfLambert)).rgb*_Color.rgb;
  83. //让半兰伯特的取值范围映射在(0,1),用其数值构建一套纹理坐标,并用这套坐标对渐变纹理采样。
  84. fixed3 diffuse=diffuseColor*_LightColor0.rgb;
  85. //下面是边缘光的初步尝试
  86. if(dot(tangentViewDir,tangentNormal)<_RimLength){
  87. diffuse+=_RimPower*(_RimColor.rgb*lerp(1,0,dot(tangentViewDir,tangentNormal)/_RimLength));
  88. }
  89. fixed3 halfDir = normalize(tangentViewDir + tangentLightDir);//求视线与光线的中间向量
  90. fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot (tangentNormal,tangentLightDir)),_Gloss);
  91. fixed specularMask=tex2D(_SpecularMask,f.uv).r*_SpecularScale;//对遮罩纹理采样后,用r分量计算掩码值并与高光参数相乘。黑色的r值为0,白1
  92. specular=specular*specularMask;
  93. return fixed4(ambient + diffuse + specular , 1.0);
  94. }
  95. ENDCG
  96. }
  97. }
  98. FallBack "Diffuse"
  99. }

4.透明效果

  1. //想要实现透明效果,有两种方式。一种是透明度测试,一种是透明度混合。
  2. //透明度测试简单粗暴,将低于某个值的像素直接剔除。无法实现半透明
  3. //透明度测试的代码需要添加如下内容:
  4. //1.Propertiers{... _CutOff("Alpha CutOff",Range(0,1))=0.5} (_CutOff参数范围【0,1】。是进行透明度测试时的判断条件)
  5. //2.SubShader{... Tags{"Queue"="AlphaTest","IgnoreProjector"="True","RenderType"="TransparentCutOut"} ... }
  6. //(SubShader的Queue标签决定模型归于哪个序列,见课本提及的五个渲染序列)
  7. //3.fixed _CutOff
  8. //4.fixed4 frag(v2f f):SV_Target{... fixed4 texColor=tex2D(_MainTex,i.uv); Clip(texColor.a-_CutOff);}
  9. //(Clip方法会判断其参数即texColor.a-_CutOff是否为负数,是则舍弃该片元的输出)
  10. //下面是透明度混合的代码(下面代码无法双面渲染。双面渲染要开启两个pass。第一个pass渲染背面(Cull Front),第二个渲染前面。其他地方一致)
  11. Shader "07" {
  12. Properties{
  13. _MainTex("Main Tex", 2D) = "white"{} // 纹理贴图
  14. _Color("Color", Color) = (1,1,1,1) // 控制纹理贴图的颜色
  15. _Specular("Specular",Color) = (1,1,1,1)//高光颜色
  16. _Gloss("Gloss",Range(8.0,256)) = 20//光泽度。(cos角的指数)。一般大于10
  17. _NormalMap("Normal Map", 2D) = "bump"{} // 表示当该位置没有指定任何法线贴图时,就使用模型顶点自带的法线
  18. _BumpScale("Bump Scale", Float) = 1 // 法线贴图的凹凸参数。为0表示使用模型原来的发现,为1表示使用法线贴图中的值。大于1则凹凸程度更大。
  19. _RampTex("Ramp Tex",2D)="white"{}//渐变纹理贴图
  20. _SpecularMask("Specular Mask",2D)="white"{}//高光遮罩贴图
  21. _SpecularScale("Specular Scale",Float)=1//控制高光遮罩影响度系数
  22. _AlphaScale("Alpha Scale",Range(0,1))=1
  23. }
  24. SubShader{
  25. Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
  26. pass{
  27. //这个pass块开启深度写入,但不输出颜色,目的仅为把该模型的深度值写入深度缓冲
  28. //这样可以得到逐像素级别的正确深度信息(否则,模型有交叉结构时无法得到正确效果)
  29. Zwrite On
  30. ColorMask 0
  31. }
  32. Pass {
  33. Tags{"LightMode" = "ForwardBase"}
  34. ZWrite Off//关闭深度写入。详见课本
  35. Blend SrcAlpha OneMinusSrcAlpha//开启并设置pass的混合模式。(有多种模式可以选择)
  36. CGPROGRAM
  37. #pragma vertex vert
  38. #pragma fragment frag
  39. #include "Lighting.cginc"
  40. // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
  41. fixed4 _Color;
  42. fixed4 _Specular;
  43. float _Gloss;
  44. float _BumpScale;
  45. float _SpecularScale;
  46. sampler2D _MainTex;
  47. sampler2D _NormalMap;
  48. sampler2D _SpecularMask;
  49. sampler2D _RampTex;
  50. float4 _MainTex_ST; //让主纹理,法线纹理,高光遮罩纹理共同使用这个纹理属性变量
  51. fixed _AlphaScale;
  52. struct a2v
  53. {
  54. float4 vertex : POSITION;
  55. float3 normal : NORMAL; // 不再使用模型自带的法线。保留该变量是因为切线空间是通过(模型里的)法线和(模型里的)切线确定的。
  56. float4 texcoord : TEXCOORD0; //第一组纹理坐标。片元着色器会使用uv纹理坐标对其采样。
  57. float4 tangent : TANGENT; // tangent.w用来确定切线空间中坐标轴的方向的。
  58. };
  59. struct v2f
  60. {
  61. float4 pos : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
  62. //float3 WorldNormal : TEXCOORD0; // 不再使用世界空间下的法线方向
  63. //float3 WorldPos: TEXCOORD1;
  64. float2 uv : TEXCOORD0; // xy存储MainTex的纹理坐标,zw存储NormalMap的纹理坐标
  65. float3 lightDir : TEXCOORD1; // 切线空间下,平行光的方向
  66. float3 viewDir : TEXCOORD2; // 切线空间下,平行光的方向
  67. };
  68. // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
  69. v2f vert(a2v v)
  70. {
  71. v2f f;
  72. f.pos= UnityObjectToClipPos(v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间
  73. f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; // 贴图的纹理坐标,等同于f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
  74. TANGENT_SPACE_ROTATION; // 调用这个宏会得到一个矩阵rotation,该矩阵用来把模型空间下的方向转换为切线空间下。注意不是世界空间
  75. f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); //切线空间下,平行光的方向。ObjSpaceLightDir(v.vertex); 得到模型空间下的平行光方向
  76. f.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex));//切线空间下,视线的方向
  77. return f;
  78. }
  79. // 要把所有跟法线方向有关的运算,都放到切线空间下。因为从法线贴图中取得的法线方向是在切线空间下的。
  80. fixed4 frag(v2f f) : SV_Target
  81. {
  82. fixed4 texColor=tex2D(_MainTex,f.uv);
  83. fixed3 albedo =texColor.rgb* _Color.rgb;//f.uv.xy存储了普通贴图的信息
  84. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
  85. //下面求切线空间的法线。先获取法线贴图的颜色信息,再通过内置函数获取法线
  86. fixed4 normalColor = tex2D(_NormalMap, f.uv); //f.uv.zw存储了法线贴图的信息
  87. fixed3 tangentNormal = UnpackNormal(normalColor); // 使用Unity内置的方法,从颜色值得到法线在切线空间的方向
  88. tangentNormal.xy = tangentNormal.xy * _BumpScale; // 控制凹凸程度。只和法线贴图的xy值有关。
  89. tangentNormal = normalize(tangentNormal);
  90. // 光照方向与视线方向的单位化。切线空间的转换完成
  91. fixed3 tangentLightDir = normalize(f.lightDir); // 切线空间下的光照方向
  92. fixed3 tangentViewDir = normalize(f.viewDir); // 切线空间下的光照方向
  93. fixed3 diffuse = _LightColor0.rgb * albedo *( dot( tangentNormal,tangentLightDir)*0.5+0.5);//半兰伯特光照模型
  94. fixed3 halfDir = normalize(tangentViewDir + tangentLightDir);
  95. fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot (tangentNormal,tangentLightDir)),_Gloss);
  96. fixed specularMask=tex2D(_SpecularMask,f.uv).r*_SpecularScale;//对遮罩纹理采样后,用r分量计算掩码值并与高光参数相乘。黑色的r值为0,白1
  97. specular=specular*specularMask;
  98. return fixed4(ambient + diffuse + specular , texColor.a*_AlphaScale);//设置着色器返回值的透明通道
  99. }
  100. ENDCG
  101. }
  102. }
  103. FallBack "Diffuse"
  104. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/107632
推荐阅读
相关标签
  

闽ICP备14008679号