实现Unity对象的描边特效

我整理的一些关于【2d,#pragma,#include】的项目学习资料(附讲解~~)和大家一起分享、学习一下:

https://d.51cto.com/eDOcp1


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

unity描边效果_屏幕特效


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

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

登录后复制

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"}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.


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

unity描边效果_#pragma_02

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

unity描边效果_屏幕特效_03


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

  1. 创建一个UnlitShader,命名为NormalUnlitShader
  2. 登录后复制
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 "UnityCG.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(UNITY_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  }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.


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

unity描边效果_#include_04

unity描边效果_#pragma_05

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

unity描边效果_#pragma_06


三、屏幕特效,描边效果

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

unity描边效果_#pragma_07

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

登录后复制

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


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

登录后复制

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}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.


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

登录后复制

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"}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.


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

登录后复制

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}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.


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

登录后复制

using UnityEngine;using System.Collections;[ExecuteInEditMode]public class outline : MonoBehaviour {    /// <summary>    /// 辅助摄像机    /// </summary>    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    /// <summary>    /// 辅助摄像机渲染的RenderTexture    /// </summary>    private RenderTexture outlineRenderTex;    /// <summary>    /// 模糊扩大次数    /// </summary>    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)                               );    }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.


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

unity描边效果_#include_08

免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空