【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 }
Wireframe

Shader使用来两个Pass渲染,来避免产生透明混合出现的深度问题。第一个Pass渲染背面,第二个Pass渲染正面。

step是一个比较大小的操作,实现如下:

step step(a, x) Returns (x >= a) ? 1 : 0

lx/ly/hx/hy用于判断渲染像素是否位于中心和UV中心一致,变长为1-_Width*2的正方形内,如果不在,即为线条。

posted @ 2017-08-18 14:26  JaffHan  阅读(5303)  评论(0编辑  收藏  举报