描边shader(法线外拓)
描边的思路是需要两个pass。第一个pass让顶点沿着法线方向延伸出去,使得模型变大一圈。第二个pass正常渲染,让正常渲染的模型挡在第一个pass之上,这样就会露出延伸出去的部分,延伸出去的就是我们要的描边了。代码实现如下:
Shader "Custom/PjOutlineTest" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _OutlineWidth("OutlineWidth",Range(0,1))=0.01 _Diffuse("Diffuse",Color)=(1,1,1,1) } SubShader { //第一个pass沿着法线“膨胀”一点,并且剔除正面 pass{ Cull FRONT Offset 11, 1 CGPROGRAM #include "UnityCG.cginc" float4 _Color; float _OutlineWidth; #pragma vertex vert #pragma fragment frag struct v2f{ float4 pos:POSITION; float4 color:COLOR; }; v2f vert(appdata_full v){ v2f o; o.pos=mul(UNITY_MATRIX_MVP,v.vertex); //法向量转换到view坐标 float3 vNormal=mul((float3x3)UNITY_MATRIX_MV,v.normal); //转换到投影面只需要x和y方向 float2 offsetDir=TransformViewToProjection(vNormal.xy); //顶点坐标沿着法向量偏移“宽度值” o.pos.xy+=offsetDir*_OutlineWidth; o.color=_Color; return o; } float4 frag (v2f i) : COLOR { return i.color; } ENDCG } //正常渲染 Pass { Tags{"LightMode" = "ForwardBase"} CGPROGRAM //引入头文件 #include "Lighting.cginc" #pragma vertex vert #pragma fragment frag fixed4 _Diffuse; sampler2D _MainTex; //使用了TRANSFROM_TEX宏就需要定义XXX_ST float4 _MainTex_ST; struct v2f { float4 pos : SV_POSITION; float lambert : TEXCOORD0; float2 uv : TEXCOORD1; }; v2f vert(appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); float3 worldNormal = normalize(mul(v.normal, (float3x3)_World2Object)); float3 worldPos = mul(_Object2World, o.pos); float3 worldLightDir =normalize(_WorldSpaceLightPos0.xyz); o.lambert = dot(worldNormal, worldLightDir) ; return o; } fixed4 frag(v2f i) : SV_Target { fixed3 diffuse = i.lambert * _Diffuse.xyz * _LightColor0.xyz ; fixed4 color = tex2D(_MainTex, i.uv); color.rgb = color.rgb* diffuse; return fixed4(color); } ENDCG } } FallBack "Diffuse" }
效果如下:
法线外拓有些缺陷,在棱角分明的模型中表现较差,锐利的部分,描边会有断裂。