【Unity】伪线框渲染Shader的实现
线框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的正方形内,如果不在,即为线条。