1. 程式人生 > >描邊shader(法線外拓)

描邊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" }

 效果如下:

 法線外拓有些缺陷,在稜角分明的模型中表現較差,銳利的部分,描邊會有斷裂。