0评论

Unity3D游戏开发(九):Shader案例分享

文章来自CSDN博客 2017-09-13 135浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

提要

接着继续讲Unity3D游戏开发,下面给大家介绍的是一些Shader 的例子,从简单到难,让大家了解shader的使用。


一大波例子来袭

还是用上一篇用到的工程。点我下载


红色的螃蟹

Test1.shader

  1. Shader "Custom/Test1" {  
  2.     SubShader {  
  3.       Tags { "RenderType" = "Opaque" }  
  4.       CGPROGRAM  
  5.       #pragma surface surf Lambert  
  6.       struct Input {  
  7.           float4 color : COLOR;  
  8.       };  
  9.       void surf (Input IN, inout SurfaceOutput o) {  
  10.           o.Albedo = 1;  
  11.       }  
  12.       ENDCG  
  13.     }  
  14.     Fallback "Diffuse"  
  15.   }  

o.Albedo = 1;表示输出颜色是白色,将方向光调成红色,最后经过lambert光照模型计算后,得到




带法线贴图的螃蟹

  1. Shader "Custom/Test2" {  
  2.    Properties {  
  3.      _MainTex ("Texture", 2D) = "white" {}  
  4.      _BumpMap ("Bumpmap", 2D) = "bump" {}  
  5.    }  
  6.    SubShader {  
  7.      Tags { "RenderType" = "Opaque" }  
  8.      CGPROGRAM  
  9.      #pragma surface surf Lambert  
  10.      struct Input {  
  11.        float2 uv_MainTex;  
  12.        float2 uv_BumpMap;  
  13.      };  
  14.      sampler2D _MainTex;  
  15.      sampler2D _BumpMap;  
  16.      void surf (Input IN, inout SurfaceOutput o) {  
  17.        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
  18.        o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));  
  19.      }  
  20.      ENDCG  
  21.    }   
  22.    Fallback "Diffuse"  
  23.  }  


对比感受一下,左边是不带法线贴图的,右边是带法线贴图的。




从剑灵里面跑出来的螃蟹

先看下啥是剑灵风




感觉就是很多高光有木有(不要瞎瞅,喂!),这还有个专业名词,叫Rim Lighting。我们的螃蟹也可以,哼~

  1. Shader "Custom/Test3" {  
  2.   Properties {  
  3.     _MainTex ("Texture", 2D) = "white" {}  
  4.     _BumpMap ("Bumpmap", 2D) = "bump" {}  
  5.     _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)  
  6.     _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0  
  7.   }  
  8.   SubShader {  
  9.     Tags { "RenderType" = "Opaque" }  
  10.     CGPROGRAM  
  11.     #pragma surface surf Lambert  
  12.     struct Input {  
  13.         float2 uv_MainTex;  
  14.         float2 uv_BumpMap;  
  15.         float3 viewDir;  
  16.     };  
  17.     sampler2D _MainTex;  
  18.     sampler2D _BumpMap;  
  19.     float4 _RimColor;  
  20.     float _RimPower;  
  21.     void surf (Input IN, inout SurfaceOutput o) {  
  22.         o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
  23.         o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));  
  24.         half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));  
  25.         o.Emission = _RimColor.rgb * pow (rim, _RimPower);  
  26.     }  
  27.     ENDCG  
  28.   }   
  29.   Fallback "Diffuse"  
  30. }  

渲染结果,(模型精度有点低,凑合着看吧)



原理简单说一下,主要是用来计算边缘光照的,首先通过视线与法线的夹角来找到模型的边缘,然后再根据距离的远近来控制发射光的强度。

  1. half rim = 1.0 - saturate(dot (normalize(IN.viewDir), IN.worldNormal));  
  2. o.Emission = _RimColor.rgb * pow (rim, _RimPower);  


IN.viewDir是当前视角向量,IN.worldNormal是物体的法线。dot是计算视角和法线的点积,等于视角和法线夹角的cos值,Cos的值域是1-0,1-cos就成了0-1,在夹角90度时达到最大值,正好用来模拟侧光的强度(与视角成90度的部分光线最强,就是边缘光了)
把这个值的变化率用一个pow函数(rim的_rimPower次方)进行放大,就能强化边缘发亮的效果。


胖胖的螃蟹

这个效果原理很简单,就是将顶点位置沿着法线方向移动一定的距离。

  1. Shader "Custom/Test4" {  
  2.     Properties {  
  3.       _MainTex ("Texture", 2D) = "white" {}  
  4.       _Amount ("Extrusion Amount", Range(-1,1)) = 0.5  
  5.     }  
  6.     SubShader {  
  7.       Tags { "RenderType" = "Opaque" }  
  8.       CGPROGRAM  
  9.       #pragma surface surf Lambert vertex:vert  
  10.       struct Input {  
  11.           float2 uv_MainTex;  
  12.       };  
  13.       float _Amount;  
  14.       void vert (inout appdata_full v) {  
  15.           v.vertex.xyz  = v.normal * _Amount;  
  16.       }  
  17.       sampler2D _MainTex;  
  18.       void surf (Input IN, inout SurfaceOutput o) {  
  19.           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
  20.       }  
  21.       ENDCG  
  22.     }   
  23.     Fallback "Diffuse"  
  24.   }  


确实胖了,但是..怎么画框框的地方怎么有点怪怪的? 其实是mesh的问题,这个从游戏里面提取的模型,三角面可能并不好,比如这个提取的mesh网格九没有封闭。那就换一个好了!

从Dota2的官网下一个旱地神牛的模型下来,导入进来,给他同样的shader,结果如下。



高富帅瞬间变蠢萌娃有木有!0成本把写实风格的模型变成Q版风格。


Vertex modifier function

在surface shader中也可以加入 vetex shader.

方法就是在声明的时候添加一个字段 vertex:xxx,比如

  1. #pragma surface surf Lambert vertex:vert  


然后定义好vert函数就可以了。vertex shading的过程会在surface函数之前进行。下面的例子是将法线渲染出来(叠加在原来的颜色上)。

  1. Shader "Custom/test5" {  
  2.     Properties {  
  3.       _MainTex ("Texture", 2D) = "white" {}  
  4.     }  
  5.     SubShader {  
  6.       Tags { "RenderType" = "Opaque" }  
  7.       CGPROGRAM  
  8.       #pragma surface surf Lambert vertex:vert  
  9.       struct Input {  
  10.           float2 uv_MainTex;  
  11.           float3 customColor;  
  12.       };  
  13.       void vert (inout appdata_full v, out Input o) {  
  14.           UNITY_INITIALIZE_OUTPUT(Input,o);  
  15.           o.customColor = abs(v.normal);  
  16.       }  
  17.       sampler2D _MainTex;  
  18.       void surf (Input IN, inout SurfaceOutput o) {  
  19.           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
  20.           o.Albedo *= IN.customColor;  
  21.       }  
  22.       ENDCG  
  23.     }   
  24.     Fallback "Diffuse"  
  25.   }  

渲染结果


之前的Rim lighting在可以在vertex shading中计算。


Final Color Modifier

这个就很像fregment shader了,属于pipeline的最后一个阶段。

定义的方式和vertex 的类似,

  1. #pragma surface surf Lambert finalcolor:mycolor  

接着定义mycolor函数就可以了。mycolor函数会在surf函数执行之后再执行。
  1. Shader "Custom/test6" {  
  2.    Properties {  
  3.      _MainTex ("Texture", 2D) = "white" {}  
  4.      _ColorTint ("Tint", Color) = (1.0, 0.6, 0.6, 1.0)  
  5.    }  
  6.    SubShader {  
  7.      Tags { "RenderType" = "Opaque" }  
  8.      CGPROGRAM  
  9.      #pragma surface surf Lambert finalcolor:mycolor  
  10.      struct Input {  
  11.          float2 uv_MainTex;  
  12.      };  
  13.      fixed4 _ColorTint;  
  14.      void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)  
  15.      {  
  16.          color *= _ColorTint;  
  17.      }  
  18.      sampler2D _MainTex;  
  19.      void surf (Input IN, inout SurfaceOutput o) {  
  20.           o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
  21.      }  
  22.      ENDCG  
  23.    }   
  24.    Fallback "Diffuse"  
  25.  }  

渲染效果