C for Graphic:网格边缘特效

      不同于上一篇的“外描边”,这一我们要实现的是“内边缘”,也就是说不是通过对顶点进行扩展操作,也是需要检测“顶点边缘”,并且在“顶点边缘”做一些特效。

       这里就要对什么是“边缘”这个概念来个形象的数学上的解释了。想像一下,在现实世界中,我们围绕一个物体从不同角度观察,视线沿着正对着的顶点向左或者向右移动到物体的边缘,这个过程发生着什么数学上的变化呢?直接来说就是我们观察物体上的每一个顶点的法向量发生着变化,刚开始我们正对物体的那个顶点的法向量也正对着我们,逐渐向一个方向移动的时候,每观察到的顶点的法向量与我们视线方向发生着角度的变化,到最后的“边缘”,视线方向和顶点法向量方向呈现垂直,这就是所谓的“边缘”了,比较形象的示意图如下:

       C for Graphic:网格边缘特效

       够形象吧,需要注意的是,角度的规范是以逆时针来计算的,也就是说视线方向与顶点法向量方向是从180°到90°的过程(当然了我们也可以说顶点法向量方向与顶点到眼睛朝向向量是从0°到90°的过程)。

       考虑到给“边缘”做一些特效,这里我使用一般的颜色混合来实现,混合算法公式也简单,就是weight权重控制,如下:

       color A = mainColor; 

       color B = edgeColor;

       /*float weight = dot(视线方向,法线方向);  值属于[-val,0],因为unityCG.cginc函数的便捷性使用下面的计算*/

       float weight = dot(法线方向,顶点到眼睛朝向); 值属于[val,0]使用saturate函数限制到[1,0];

       color C = mainColor * weight + (1-weight) * edgeColor;

       好,既然我们已经了解其中的数学关系了,那么就CG shader实现,如下:

       

  1. Shader "Unlit/EdgeHLUnlitShader"
  2. {
  3. Properties
  4. {
  5. _MainColor("color",Color) = (1,1,1,1)
  6. _EdgeColor("edge",Color) = (1,1,1,1)
  7. _EdgeOffset("offset",Range(-1,1)) = 0
  8. }
  9. SubShader
  10. {
  11. Tags { "RenderType"="Opaque" }
  12. LOD 100
  13. Pass
  14. {
  15. CGPROGRAM
  16. #pragma vertex vert
  17. #pragma fragment frag
  18. #include "UnityCG.cginc"
  19. struct appdata
  20. {
  21. float4 vertex : POSITION;
  22. float3 normal : NORMAL; /*这里我们需要绑定建模空间定点法向量*/
  23. };
  24. struct v2f
  25. {
  26. float4 vertex : SV_POSITION;
  27. float weight : TEXCOORD1; /*需要绑定一个TEXCOORD1储存一下法向量和视线的点积权重weight*/
  28. };
  29. float4 _MainColor; /*主颜色*/
  30. float4 _EdgeColor; /*边缘叠加色*/
  31. float _EdgeOffset; /*边缘偏移量,只是用来控制边缘的扩展*/
  32. v2f vert (appdata v)
  33. {
  34. v2f o;
  35. o.vertex = UnityObjectToClipPos(v.vertex);
  36. //使用unityCG.cginc的函数获取世界空间点到眼睛朝向向量和顶点法向量
  37. float3 WorldPtoV = WorldSpaceViewDir(v.vertex);
  38. float3 worldNormal = UnityObjectToWorldNormal(v.normal);
  39. //获取weight权重值[1,0],越边缘时weight~0,越中心weight~1
  40. //同时offset[-1,1]得到一个偏移的控制效果
  41. //当offset越大时,weight~1则主颜色权重大,反之edge颜色权重大
  42. o.weight.x = saturate(dot(worldNormal,WorldPtoV) + _EdgeOffset);
  43. return o;
  44. }
  45. fixed4 frag (v2f i) : SV_Target
  46. {
  47. //使用最简单的颜色混合计算方式得到混合后的颜色效果
  48. fixed4 col = i.weight * _MainColor + (1-i.weight) * _EdgeColor;
  49. return col;
  50. }
  51. ENDCG
  52. }
  53. }
  54. }

         下面是实际的运行效果,如图:

    C for Graphic:网格边缘特效

        就是这么简单,但是十分实用的着色效果,唯一需要注意的是常开UnityCG.cginc文件,将其中所有结构体、字段、宏、内联函数多看看并理解。

        so,接下来继续。