unity实现描边效果

这里总结了几种在unity实现描边效果的方法,首先准备一个模型导入在unity中,使用默认shader,上传一张原始图,以便后面实现功能效果的对比

unity实现描边效果_第1张图片


一、边缘光,这里参照官方的一个SurfaceShader Example,Rim Lighting

1.在unity创建一个SurfaceShader,命名RimLighting

[c#] view plain copy


  • Shader "Custom/RimLighting" {  
  •     Properties {  
  •         _Color ("Color", Color) = (1,1,1,1)  
  •         _MainTex ("Albedo (RGB)", 2D) = "white" {}  
  •         //边缘光颜色  
  •         _RimColor("Rim Color",Color) =(1,1,1,1)  
  •         //边缘光强度  
  •         _RimPower("Rim Power", Range(0.5,8.0)) = 3.0  
  •     }  
  •     SubShader {  
  •         Tags { "RenderType"="Opaque" }  
  •         LOD 200  
  •          
  •         CGPROGRAM  
  •         // Physically based Standard lighting model, and enable shadows on all light types  
  •         #pragma surface surf Standard fullforwardshadows  
  •   
  •         // Use shader model 3.0 target, to get nicer looking lighting  
  •         #pragma target 3.0  
  •   
  •         sampler2D _MainTex;  
  •   
  •         struct Input {  
  •             float2 uv_MainTex;  
  •             //法线  
  •             float3 worldNormal;  
  •             //视角方向  
  •             float3 viewDir;  
  •         };  
  •   
  •         fixed4 _Color;  
  •         fixed4 _RimColor;  
  •         half _RimPower;  
  •   
  •         void surf (Input IN, inout SurfaceOutputStandard o) {  
  •             // Albedo comes from a texture tinted by color  
  •             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;  
  •             o.Albedo = c.rgb;  
  •             o.Alpha = c.a;  
  •               
  •             half rim = 1.0 - saturate(dot(normalize(IN.viewDir), IN.worldNormal));  
  •             o.Emission = _RimColor.rgb * pow(rim, _RimPower);  
  •         }  
  •         ENDCG  
  •     }  
  •     FallBack "Diffuse"  
  • }  

2.将模型材质的shader改为刚才所写的shader,Custom/RimLighting

unity实现描边效果_第2张图片

3.更改后,具体效果如下

unity实现描边效果_第3张图片


二、法线外拓,用一个Pass渲染边框,一个Pass渲染实物

  • 创建一个UnlitShader,命名为NormalUnlitShader

[c#] view plain copy


  • Shader "Custom/NormalUnlitShader"  
  • {  
  •     Properties  
  •     {  
  •         _MainTex ("Texture", 2D) = "white" {}  
  •         _Outline("Out Line",Range(0.001,0.005))=0.002  
  •         _Color("Color",Color)=(1,1,1,1)  
  •     }  
  •   
  •     CGINCLUDE  
  •     #include "CG.cginc"  
  •     struct v2f  
  •     {  
  •         float4 pos:POSITION;  
  •         float4 color:COLOR;  
  •     };  
  •   
  •     sampler2D _MainTex;  
  •     float _Outline;  
  •     fixed4 _Color;  
  •   
  •     v2f vert(appdata_base v)  
  •     {  
  •         v2f o;  
  •         o.pos = mul(_MATRIX_MVP, v.vertex);  
  •         float3 norm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);  
  •         float2 offset = TransformViewToProjection(norm.xy);  
  •         o.pos.xy += offset * o.pos.z * _Outline;  
  •         o.color = _Color;  
  •         return o;  
  •     }  
  •     ENDCG  
  •   
  •     SubShader  
  •     {  
  •         Cull Front  
  •         Pass  
  •         {  
  •             CGPROGRAM  
  •             #pragma vertex vert  
  •             #pragma fragment frag  
  •             fixed4 frag (v2f i) : COLOR  
  •             {  
  •                 return i.color;  
  •             }  
  •             ENDCG  
  •         }  
  •   
  •         CGPROGRAM  
  •         #pragma surface surf Lambert   
  •         struct Input {  
  •             float2 uv_MainTex;  
  •         };  
  •         void surf(Input IN, inout SurfaceOutput o) {  
  •             fixed4 c = tex2D(_MainTex, IN.uv_MainTex);  
  •             o.Albedo = c.rgb;  
  •             o.Alpha = c.a;  
  •         }  
  •         ENDCG  
  •     }  
  • }  

2.这里再换成新建的NormalUnlitShader,就会发现一些问题,他会在一些我们并不像描边的地方也改变了颜色,这就是因为这根据模型法线并不是全部都均匀的向外扩展,才导致这样的情况

unity实现描边效果_第4张图片

unity实现描边效果_第5张图片

3.再换一个Sphere模型应用与怪物同一个材质球,就会发现Sphere模型,是能达到我们的需求的,也能很明显的看出两者的差别,因为球的法线都是均匀的往外扩展的,这个方法的使用就需要以后根据实际的要求来使用

unity实现描边效果_第6张图片


三、屏幕特效,描边效果

  • 新建一个辅助摄像机,设置参数如下,并将模型的Layer设置为Monster,这样辅助摄像机就能单独看见这个怪物模型

unity实现描边效果_第7张图片

2.写一个纯色shader,辅助摄像机用RenderWithShader,纯色渲染一张纹理处理

[c#] view plain copy


  • Shader "Custom/UnlitSolidColor"  
  • {  
  •     SubShader  
  •     {  
  •         Pass  
  •         {  
  •             //返回蓝色  
  •             Color(0,0,1,1)  
  •         }  
  •     }  
  • }  

3.将纯色纹理,可以模糊放大几次,次数越多,边框就越宽,这里需要使用到一个像素偏移函数,Graphics.BlitMultiTap和一个Blur效果shader

[c#] view plain copy


  • Shader "Custom/OutterLineBlur" {  
  •   
  • Properties {  
  •     _MainTex ("", 2D) = "white" {}  
  • }  
  •   
  • Category {  
  •     ZTest Always Cull Off ZWrite Off Fog { Mode Off }  
  •   
  •     Subshader {  
  •         Pass {  
  •             CGPROGRAM  
  •                 #pragma vertex vert  
  •                 #pragma fragment frag  
  •                 #pragma fragmentoption ARB_precision_hint_fastest  
  •                 #include "UnityCG.cginc"  
  •   
  •                 struct v2f {  
  •                     float4 pos : POSITION;  
  •                     half4 uv[2] : TEXCOORD0;  
  •                 };  
  •   
  •                 float4 _MainTex_TexelSize;  
  •                 float4 _BlurOffsets;  
  •   
  •                 v2f vert (appdata_img v)  
  •                 {  
  •                     v2f o;  
  •                     float offX = _MainTex_TexelSize.x * _BlurOffsets.x;  
  •                     float offY = _MainTex_TexelSize.y * _BlurOffsets.y;  
  •   
  •                     o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  •                     float2 uv = MultiplyUV (UNITY_MATRIX_TEXTURE0, v.texcoord.xy-float2(offX, offY));  
  •                   
  •                     o.uv[0].xy = uv + float2( offX, offY);  
  •                     o.uv[0].zw = uv + float2(-offX, offY);  
  •                     o.uv[1].xy = uv + float2( offX,-offY);  
  •                     o.uv[1].zw = uv + float2(-offX,-offY);  
  •                     return o;  
  •                 }  
  •                   
  •                 sampler2D _MainTex;  
  •                 fixed4 _Color;  
  •   
  •                 fixed4 frag( v2f i ) : COLOR  
  •                 {  
  •                     fixed4 c;  
  •                     c  = tex2D( _MainTex, i.uv[0].xy );  
  •                     c += tex2D( _MainTex, i.uv[0].zw );  
  •                     c += tex2D( _MainTex, i.uv[1].xy );  
  •                     c += tex2D( _MainTex, i.uv[1].zw );  
  •                     return c /2 ;  
  •                 }  
  •                 ENDCG  
  •             }  
  •         }  
  •     }  
  •     Fallback off  
  • }  

4.将扩大后的纹理与原来的纹理,做一个对比,并依据原来纹理剔除掉中间部分,就只剩下一个边框纹理,这里需要使用一个剔除shader

[c#] view plain copy


  • Shader "Custom/OutterLineCutoff" {  
  •     Properties {  
  •         _MainTex ("", 2D) = "white" {}  
  •     }     
  •     Category {  
  •     BlendOp RevSub  
  •     Blend One One  
  •     ZTest Always Cull Off ZWrite Off Fog { Mode Off }  
  •       
  •     Subshader {  
  •         Pass {  
  •             CGPROGRAM  
  •             #pragma vertex vert  
  •             #pragma fragment frag  
  •             #pragma fragmentoption ARB_precision_hint_fastest   
  •               
  •             sampler2D _MainTex;  
  •             sampler2D _MainTex1;  
  •             struct appdata  
  •             {  
  •                 float4 vertex : POSITION;  
  •                 float4 texcoord : TEXCOORD0;  
  •             };  
  •             struct v2f  
  •             {  
  •                 float4 pos : SV_POSITION;  
  •                 float2 uv : TEXCOORD0;  
  •             };  
  •             v2f vert (appdata v)  
  •             {  
  •                 v2f o;  
  •                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  •                 o.uv = v.texcoord.xy;  
  •                 return o;  
  •             }  
  •             half4 frag(v2f i) : COLOR  
  •             {  
  •                 fixed4 c =  tex2D(_MainTex, i.uv);  
  •                 return c;  
  •             }  
  •             ENDCG  
  •         }  
  •         }     
  •     }  
  •     FallBack "Diffuse"  
  • }  

5.在主摄像机上,使用OnRenderImage函数,将得到的轮廓纯色纹理与摄像机的图像使用混合shader进行混合

[c#] view plain copy


  • Shader "Custom/OutterLineComposer" {  
  •   
  • Properties {  
  •     _MainTex ("", 2D) = "white" {}  
  • }  
  •   
  • Category {  
  •     ZTest Always Cull Off ZWrite Off Fog { Mode Off }  
  •     Blend SrcAlpha OneMinusSrcAlpha  
  •   
  •     Subshader {  
  •         Pass {  
  •             CGPROGRAM  
  •                 #pragma vertex vert  
  •                 #pragma fragment frag  
  •                 #pragma fragmentoption ARB_precision_hint_fastest  
  •                 #include "UnityCG.cginc"  
  •   
  •                 struct v2f {  
  •                     float4 pos : POSITION;  
  •                     half2 uv : TEXCOORD0;  
  •                 };  
  •   
  •                 v2f vert (appdata_img v)  
  •                 {  
  •                     v2f o;  
  •                     o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  •                     o.uv = v.texcoord.xy;  
  •                     return o;  
  •                 }  
  •   
  •                 sampler2D _MainTex;  
  •   
  •                 fixed4 frag( v2f i ) : COLOR  
  •                 {  
  •                     return tex2D( _MainTex, i.uv );  
  •                 }  
  •                 ENDCG  
  •             }  
  •         }  
  •     }  
  •     Fallback off  
  • }  

6.绑定在主摄像机的脚本

[c#] view plain copy


  • using UnityEngine;  
  • using System.Collections;  
  •   
  • [ExecuteInEditMode]  
  • public class outline : MonoBehaviour {  
  •     ///   
  •     /// 辅助摄像机  
  •     ///   
  •     public Camera outlineCamera;  
  •   
  •     #region 纯红色材质 solidColorMaterail  
  •     public Shader solidColorShader;  
  •     private Material m_solid=null;  
  •     private Material solidMaterail  
  •     {  
  •         get   
  •         {  
  •             if (m_solid == null)  
  •             {  
  •                 m_solid = new Material(solidColorShader);  
  •             }  
  •             return m_solid;  
  •         }  
  •     }  
  •     #endregion  
  •      
  •     #region 合并材质 compositeMaterial  
  •     public Shader compositeShader;  
  •     private Material m_composite=null;  
  •     private Material compositeMaterial  
  •     {  
  •         get  
  •         {  
  •             if (m_composite == null)  
  •                 m_composite = new Material(compositeShader);  
  •             return m_composite;  
  •         }  
  •     }  
  •     #endregion  
  •       
  •     #region 模糊材质 blurMaterial  
  •     public Shader blurShader;  
  •     private Material m_blur=null;  
  •     private Material blurMaterial  
  •     {  
  •         get   
  •         {  
  •             if (m_blur == null)  
  •                 m_blur = new Material(blurShader);  
  •             return m_blur;  
  •         }  
  •     }  
  •     #endregion  
  •       
  •     #region 剔除材质 cutoffShader  
  •     public Shader cutoffShader;  
  •     private Material m_cutoff=null;  
  •     private Material cutoffMaterial  
  •     {  
  •         get  
  •         {  
  •             if (m_cutoff == null)  
  •                 m_cutoff = new Material(cutoffShader);  
  •             return m_cutoff;  
  •         }  
  •     }  
  •     #endregion  
  •     ///   
  •     /// 辅助摄像机渲染的RenderTexture  
  •     ///   
  •     private RenderTexture outlineRenderTex;  
  •     ///   
  •     /// 模糊扩大次数  
  •     ///   
  •     public int Iterations = 2;  
  •     // Use this for initialization  
  •     void Start () {  
  •         outlineRenderTex = new RenderTexture((int)outlineCamera.pixelWidth, (int)outlineCamera.pixelHeight, 16);  
  •     }  
  •   
  •     // Update is called once per frame  
  •     void Update () {  
  •     }  
  •   
  •     void OnPreRender()  
  •     {  
  •         outlineCamera.targetTexture = outlineRenderTex;  
  •         outlineCamera.RenderWithShader(solidMaterail.shader, "");  
  •     }  
  •   
  •     void OnRenderImage(RenderTexture source, RenderTexture desture)  
  •     {  
  •         RenderTexture _renderTexture = RenderTexture.GetTemporary(outlineRenderTex.width, outlineRenderTex.height, 0);  
  •   
  •         MixRender(outlineRenderTex,ref _renderTexture);  
  •          
  •         Graphics.Blit(_renderTexture, desture, compositeMaterial);  
  •         RenderTexture.ReleaseTemporary(_renderTexture);  
  •     }  
  •   
  •       
  •     void MixRender(RenderTexture in_outerTexture, ref RenderTexture _renderTexture)  
  •     {  
  •         RenderTexture buffer = RenderTexture.GetTemporary(in_outerTexture.width, in_outerTexture.height, 0);  
  •         RenderTexture buffer2 = RenderTexture.GetTemporary(in_outerTexture.width, in_outerTexture.height, 0);  
  •   
  •         Graphics.Blit(in_outerTexture, buffer);  
  •   
  •         //多次模糊放大  
  •         for (int i = 0; i < Iterations; i++)  
  •         {  
  •             FourTapCone(buffer, buffer2, i);  
  •             Graphics.Blit(buffer2, buffer);  
  •         }  
  •         Graphics.Blit(in_outerTexture, buffer, cutoffMaterial);  
  •         Graphics.Blit(buffer, _renderTexture);  
  •         
  •         RenderTexture.ReleaseTemporary(buffer);  
  •         RenderTexture.ReleaseTemporary(buffer2);  
  •     }  
  •   
  •     float Spread = 0.8f;  
  •     public void FourTapCone(RenderTexture source, RenderTexture dest, int iteration)  
  •     {  
  •         float off = 0.5f + iteration * Spread;  
  •         Graphics.BlitMultiTap(source, dest, blurMaterial,  
  •                                new Vector2(off, off),  
  •                                new Vector2(-off, off),  
  •                                new Vector2(off, -off),  
  •                                new Vector2(-off, -off)  
  •                                );  
  •     }  
  •   
  • }  

7.具体效果如下,因为这里是在主摄像机设置的屏幕特效,他可以忽略掉所有的遮挡,这是优点也是弊端

unity实现描边效果_第8张图片


你可能感兴趣的:(Unity开发)