線框Shader的渲染在游戲應用上還是有一定的需求,這次分享一個偽的線框渲染Shader。之所以稱之為偽線框,是因為真正的線框應該渲染的是線,這在常規上是使用幾何體着色器輸出線段圖元來實現。但是幾何體着色器是DirectX 10的特性,所以針對移動平台,如果有少量線框渲染需求的,這個實現方法的門檻更低。
先說一下實現的原理:通過模型UV的邊界來實現線框的渲染,也就是要求渲染的每個線段都要位於UV的邊界上。
Mesh操作:
在建模軟件中,將需要線框顯示的邊,作為UV的拆分邊。將UV塊的每條邊放置在UV的四個邊界位置上,因此需要盡量避免三角形的UV。將UV的邊打直,所有UV塊的邊重合並距離UV貼圖的邊界長度一致,來保證渲染線框的粗細一致。三角形的UV,需要插入點使之成為四邊形。為了不影響正常渲染,可以把線框渲染用的UV保存為第二套或第三套UV。
Shader:
EdgeColor——線框邊的顏色。
Color——模型覆蓋的顏色。
Width——線框的寬度(跟UV邊接近UV貼圖邊界的程度有關)。
需要實現只顯示線框但不現實模型覆蓋色的效果:將Color的Alpha通道設置為0。
代碼如下:

1 Shader "JaffHan/Wireframe" { 2 Properties { 3 _Color("Color",Color)=(1.0,1.0,1.0,1.0) 4 _EdgeColor("Edge Color",Color)=(1.0,1.0,1.0,1.0) 5 _Width("Width",Range(0,1))=0.2 6 } 7 SubShader { 8 Tags { 9 "Queue"="Transparent" 10 "IgnoreProjector"="True" 11 "RenderType"="Transparent" 12 } 13 Blend SrcAlpha OneMinusSrcAlpha 14 LOD 200 15 Cull Front 16 zWrite off 17 Pass { 18 CGPROGRAM 19 #pragma vertex vert 20 #pragma fragment frag 21 #pragma target 3.0 22 #include "UnityCG.cginc" 23 24 struct a2v { 25 half4 uv : TEXCOORD0 ; 26 half4 vertex : POSITION ; 27 }; 28 29 struct v2f{ 30 half4 pos : SV_POSITION ; 31 half4 uv : TEXCOORD0 ; 32 }; 33 fixed4 _Color; 34 fixed4 _EdgeColor; 35 float _Width; 36 37 v2f vert(a2v v) 38 { 39 v2f o; 40 o.uv = v.uv; 41 o.pos=mul(UNITY_MATRIX_MVP,v.vertex); 42 return o; 43 } 44 45 46 fixed4 frag(v2f i) : COLOR 47 { 48 fixed4 col; 49 float lx = step(_Width, i.uv.x); 50 float ly = step(_Width, i.uv.y); 51 float hx = step(i.uv.x, 1.0 - _Width); 52 float hy = step(i.uv.y, 1.0 - _Width); 53 col = lerp(_EdgeColor, _Color, lx*ly*hx*hy); 54 return col; 55 } 56 ENDCG 57 } 58 Blend SrcAlpha OneMinusSrcAlpha 59 LOD 200 60 Cull Back 61 zWrite off 62 Pass { 63 CGPROGRAM 64 #pragma vertex vert 65 #pragma fragment frag 66 #pragma target 3.0 67 #include "UnityCG.cginc" 68 69 struct a2v { 70 half4 uv : TEXCOORD0 ; 71 half4 vertex : POSITION ; 72 }; 73 74 struct v2f{ 75 half4 pos : SV_POSITION ; 76 half4 uv : TEXCOORD0 ; 77 }; 78 fixed4 _Color; 79 fixed4 _EdgeColor; 80 float _Width; 81 82 v2f vert(a2v v) 83 { 84 v2f o; 85 o.uv = v.uv; 86 o.pos=mul(UNITY_MATRIX_MVP,v.vertex); 87 return o; 88 } 89 90 91 fixed4 frag(v2f i) : COLOR 92 { 93 fixed4 col; 94 float lx = step(_Width, i.uv.x); 95 float ly = step(_Width, i.uv.y); 96 float hx = step(i.uv.x, 1.0 - _Width); 97 float hy = step(i.uv.y, 1.0 - _Width); 98 col = lerp(_EdgeColor, _Color, lx*ly*hx*hy); 99 return col; 100 } 101 ENDCG 102 } 103 } 104 FallBack "Diffuse" 105 }
Shader使用來兩個Pass渲染,來避免產生透明混合出現的深度問題。第一個Pass渲染背面,第二個Pass渲染正面。
step是一個比較大小的操作,實現如下:
step step(a, x) Returns (x >= a) ? 1 : 0
lx/ly/hx/hy用於判斷渲染像素是否位於中心和UV中心一致,變長為1-_Width*2的正方形內,如果不在,即為線條。