Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

How to make my post effect shader campatible with Unity Post-Processing package?

Discussion in 'Shaders' started by Ice_MJ, Sep 3, 2019.

  1. Ice_MJ

    Ice_MJ

    Joined:
    Jul 26, 2016
    Posts:
    15
    First, please forgive my poor english :) .
    I wrote OutlineBlur post effect shader, along with OutlineBlur.cs script to make the choosen objects rendered with outline, and that works well,



    Then, I add Post-Processing package, active it, then the outline disappear,


    I play for a while with these two post effects, only one effect can work each time, is there a way to make them works together?

    My outline blur script like this:

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.Profiling;
    4. using System.Collections.Generic;
    5. using UnityEngine.Rendering;
    6.  
    7. /// <summary>
    8. /// 轮廓线渲染(游戏中物体的高亮显示)
    9. /// 单例
    10. /// 添加轮廓线:OutlineBlur.Instance.AddTargetRenderer(renderer)
    11. /// 删除轮廓线:OutlineBlur.Instance.RemoveTargetRenderer(renderer)
    12. /// </summary>
    13. [ExecuteInEditMode]
    14. [RequireComponent(typeof(Camera))]
    15. public class OutlineBlur : MonoBehaviour
    16. {
    17.    public static OutlineBlur Instance
    18.     {
    19.         get
    20.         {
    21.             return m_Instance;
    22.         }
    23.     }
    24.     private static OutlineBlur m_Instance;
    25.  
    26.     /// <summary>
    27.     /// 添加要描边的物体(传入该物体的Renderer)
    28.     /// </summary>
    29.     public void AddTargetRenderer(Renderer renderer)
    30.     {
    31.         Debug.Log("AddTargetRenderer::instanceid = " + renderer.GetInstanceID());
    32.         m_TargetsRendererDict[renderer.GetInstanceID()] = renderer;
    33.         SetRenderSolidColorCmdBuf();
    34.     }
    35.  
    36.     /// <summary>
    37.     /// 移除不需要描边的物体(传入该物体的Renderer)
    38.     /// </summary>
    39.     public void RemoveTargetRenderer(Renderer renderer)
    40.     {
    41.         Debug.Log("RemoveTargetRenderer::instanceid = " + renderer.GetInstanceID());
    42.         m_TargetsRendererDict.Remove(renderer.GetInstanceID());
    43.         SetRenderSolidColorCmdBuf();
    44.     }
    45.  
    46.     // Step 1. 用单色渲染目标物体到RT1上
    47.     CommandBuffer m_RenderSolidColorCmdBuf;
    48.     public Shader m_SolidColorShader;
    49.     private Dictionary<int, Renderer> m_TargetsRendererDict = new Dictionary<int, Renderer>();  // instance id -> Renderer
    50.     public Color m_OutlineColor = Color.red;
    51.     private Material m_SolidColorMaterial = null;
    52.     protected Material SolidColorMaterial
    53.     {
    54.         get
    55.         {
    56.             m_SolidColorMaterial = CheckShaderAndCreateMaterial(m_SolidColorShader, m_SolidColorMaterial);
    57.             m_SolidColorMaterial.hideFlags = HideFlags.DontSave;
    58.             return m_SolidColorMaterial;
    59.         }
    60.     }
    61.  
    62.     // Step 2. 对该RT1进行模糊处理得到RT2
    63.  
    64.     /// Blur iterations - larger number means more blur.
    65.     [Range(1, 10)]
    66.     public int m_Iterations = 1;
    67.  
    68.     /// Blur spread for each iteration. Lower values
    69.     /// give better looking blur, but require more iterations to
    70.     /// get large blurs. Value is usually between 0.5 and 1.0.
    71.     [Range(0.0f, 1.0f)]
    72.     public float m_BlurSpread = 0.4f;
    73.  
    74.     // 降采样
    75.     [Range(1, 4)]
    76.     public int m_DownSample = 2;
    77.  
    78.     // 轮廓线强度
    79.     [Range(0, 4)]
    80.     public float m_OutlineStrength = 1.0f;
    81.  
    82.     // --------------------------------------------------------
    83.     // The blur iteration shader.
    84.     // Basically it just takes 4 texture samples and averages them.
    85.     // By applying it repeatedly and spreading out sample locations
    86.     // we get a Gaussian blur approximation.
    87.  
    88.     public Shader m_BlurShader = null;
    89.     private Material m_BlurMaterial = null;
    90.     protected Material BlurMaterial
    91.     {
    92.         get
    93.         {
    94.             m_BlurMaterial = CheckShaderAndCreateMaterial(m_BlurShader, m_BlurMaterial);
    95.             m_BlurMaterial.hideFlags = HideFlags.DontSave;
    96.             return m_BlurMaterial;
    97.         }
    98.     }
    99.  
    100.     // Step 3. 将RT2中与RT1重合的像素抠掉,形成的外轮廓
    101.     public Shader cutoffShader;
    102.     private Material m_CutoffMaterial = null;
    103.     protected Material CutoffMaterial
    104.     {
    105.         get
    106.         {
    107.             m_CutoffMaterial = CheckShaderAndCreateMaterial(cutoffShader, m_CutoffMaterial);
    108.             m_CutoffMaterial.hideFlags = HideFlags.DontSave;
    109.             return m_CutoffMaterial;
    110.         }
    111.     }
    112.  
    113.     // Step 4. 形成的外轮廓与原始图叠加,最终在原图上绘制出了目标物体的外轮廓(注:可以与 Step3 合并)
    114.     public Shader m_CompositeShader;
    115.     Material m_CompositeMaterial = null;
    116.     protected Material CompositeMaterial
    117.     {
    118.         get
    119.         {
    120.             m_CompositeMaterial = CheckShaderAndCreateMaterial(m_CompositeShader, m_CompositeMaterial);
    121.             m_CompositeMaterial.hideFlags = HideFlags.DontSave;
    122.             return m_CompositeMaterial;
    123.         }
    124.     }
    125.  
    126.     // Debug, render alpha channel to r channel
    127.     public Shader m_RenderAlphaShader;
    128.     private Material m_RenderAlphaMaterial = null;
    129.     protected Material RenderAlphaMaterial
    130.     {
    131.         get
    132.         {
    133.             m_RenderAlphaMaterial = CheckShaderAndCreateMaterial(m_RenderAlphaShader, m_RenderAlphaMaterial);
    134.             m_RenderAlphaMaterial.hideFlags = HideFlags.DontSave;
    135.             return m_RenderAlphaMaterial;
    136.         }
    137.     }
    138.  
    139.     // 设置在 Step 1 中渲染的 Renderer
    140.  
    141.     /// <summary>
    142.     /// 此函数,不通用,因为涉及到自动设置 outlineTargetsRenderer
    143.     /// </summary>
    144.     private void Awake()
    145.     {
    146.         m_Instance = this;
    147.         // 创建一个 CommandBuffer,用来渲染纯色目标物体
    148.         m_RenderSolidColorCmdBuf = new CommandBuffer
    149.         {
    150.             name = "Render Solid Color Target"
    151.         };
    152.     }
    153.  
    154.     // 声明 3 个 RenderTexture,在第一次用到时 GetTemporary,在 Disable 时 ReleaseTemporary。导致 downSample 无法在运行时更改
    155.     RenderTexture m_SolidColorRT = null;
    156.     RenderTexture m_Buffer2 = null;
    157.     RenderTexture m_Buffer3 = null;
    158.     RenderTexture m_Buffer4 = null;
    159.     // Called by the camera to apply the image effect
    160.     void OnRenderImage(RenderTexture source, RenderTexture destination)
    161.     {
    162.         if(m_RenderSolidColorCmdBuf != null && SolidColorMaterial && CutoffMaterial && CompositeMaterial)
    163.         {
    164.             int rtW = source.width / m_DownSample;
    165.             int rtH = source.height / m_DownSample;
    166.  
    167.             // Step 1. Draw Solid Color Target Object(使用 Command Buffer 代替之前的那个附加相机)
    168.             SolidColorMaterial.SetColor("_Color", m_OutlineColor);
    169.             if (m_SolidColorRT == null)
    170.             {
    171.                 m_SolidColorRT = RenderTexture.GetTemporary(rtW, rtH, 0);
    172.                 m_SolidColorRT.filterMode = FilterMode.Bilinear;
    173.             }
    174.             Graphics.SetRenderTarget(m_SolidColorRT);
    175.             Graphics.ExecuteCommandBuffer(m_RenderSolidColorCmdBuf);
    176.  
    177.             // Step 2. Copy to buffer2
    178.             if (m_Buffer2 == null)
    179.             {
    180.                 m_Buffer2 = RenderTexture.GetTemporary(rtW, rtH, 0);
    181.                 m_Buffer2.filterMode = FilterMode.Bilinear;
    182.             }
    183.             Graphics.Blit(m_SolidColorRT, m_Buffer2);
    184.  
    185.             // Step 3. Blur
    186.             if(m_Buffer3 == null)
    187.             {
    188.                 m_Buffer3 = RenderTexture.GetTemporary(rtW, rtH, 0);
    189.                 m_Buffer3.filterMode = FilterMode.Bilinear;
    190.             }
    191.             bool oddEven = true;
    192.             for(int i = 0; i < m_Iterations; i++)
    193.             {
    194.                 if(oddEven)
    195.                     FourTapCone(m_Buffer2, m_Buffer3, i);
    196.                 else
    197.                     FourTapCone(m_Buffer3, m_Buffer2, i);
    198.                 oddEven = !oddEven;
    199.             }
    200.             RenderTexture blurBuffer = null;    // 引用,指向 blur 的结果 buffer
    201.             if (!oddEven)
    202.             {
    203.                 blurBuffer = m_Buffer3;
    204.             }
    205.             else
    206.             {
    207.                 blurBuffer = m_Buffer2;
    208.             }
    209.  
    210.             // Step 4. 用 cutoffMaterial 进行 blurBuffer - solidColorRT 操作,得到线框
    211.             CutoffMaterial.SetTexture("_BlurredTex", blurBuffer);
    212.             if (m_Buffer4 == null)
    213.             {
    214.                 m_Buffer4 = RenderTexture.GetTemporary(rtW, rtH, 0);
    215.                 m_Buffer4.filterMode = FilterMode.Bilinear;
    216.             }
    217.             Graphics.Blit(m_SolidColorRT, m_Buffer4, CutoffMaterial);
    218.  
    219.             // Step 5.用 compositeMaterial 进行 原图 + 线框操作
    220.             CompositeMaterial.SetTexture("_SrcTex", source);
    221.             CompositeMaterial.SetFloat("_OutlineStrength", m_OutlineStrength);
    222.             Graphics.Blit(m_Buffer4, destination, CompositeMaterial);
    223.         }
    224.         else
    225.         {
    226.             Graphics.Blit(source, destination);
    227.         }
    228.     }
    229.  
    230.     private void OnEnable()
    231.     {
    232.         // Disable if we don't support image effects
    233.         if(!SystemInfo.supportsImageEffects)
    234.         {
    235.             enabled = false;
    236.             return;
    237.         }
    238.         // Disable if the shader can't run on the users graphics card
    239.         if(!BlurMaterial)
    240.         {
    241.             enabled = false;
    242.             return;
    243.         }
    244.         if(!CutoffMaterial)
    245.         {
    246.             enabled = false;
    247.             return;
    248.         }
    249.         if(!CompositeMaterial)
    250.         {
    251.             enabled = false;
    252.             return;
    253.         }
    254.  
    255.         // 设置 Command Buffer
    256.         SetRenderSolidColorCmdBuf();
    257.     }
    258.  
    259.     private void SetRenderSolidColorCmdBuf()
    260.     {
    261.         if (m_RenderSolidColorCmdBuf == null)
    262.             return;
    263.         m_RenderSolidColorCmdBuf.Clear();
    264.         // 顺序将渲染任务加入 renderCmdBuf 中
    265.         Color clearColor = Color.black;
    266.         m_RenderSolidColorCmdBuf.ClearRenderTarget(true, true, clearColor);
    267.  
    268.         foreach(KeyValuePair<int, Renderer> kvp in m_TargetsRendererDict)
    269.         {
    270.             m_RenderSolidColorCmdBuf.DrawRenderer(kvp.Value, SolidColorMaterial);
    271.         }
    272.     }
    273.  
    274.     private void OnDisable()
    275.     {
    276.         CleanMaterial();
    277.  
    278.         CleanRenderRenderTexture();
    279.  
    280.         if(m_RenderSolidColorCmdBuf != null)
    281.             m_RenderSolidColorCmdBuf.Clear();
    282.     }
    283.  
    284.     private void CleanMaterial()
    285.     {
    286.         if (m_BlurMaterial)
    287.         {
    288.             DestroyImmediate(m_BlurMaterial);
    289.         }
    290.         if (m_CutoffMaterial)
    291.         {
    292.             DestroyImmediate(m_CutoffMaterial);
    293.         }
    294.         if (m_CompositeMaterial)
    295.         {
    296.             DestroyImmediate(m_CompositeMaterial);
    297.         }
    298.         if (m_RenderAlphaMaterial)
    299.         {
    300.             DestroyImmediate(m_RenderAlphaMaterial);
    301.         }
    302.     }
    303.  
    304.     private void CleanRenderRenderTexture()
    305.     {
    306.         if (m_SolidColorRT)
    307.         {
    308.             RenderTexture.ReleaseTemporary(m_SolidColorRT);
    309.         }
    310.         if (m_Buffer2)
    311.         {
    312.             RenderTexture.ReleaseTemporary(m_Buffer2);
    313.         }
    314.         if (m_Buffer3)
    315.         {
    316.             RenderTexture.ReleaseTemporary(m_Buffer3);
    317.         }
    318.         if(m_Buffer4)
    319.         {
    320.             RenderTexture.ReleaseTemporary(m_Buffer4);
    321.         }
    322.     }
    323.  
    324.     // Call when need to create the material used by this effect
    325.     protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
    326.     {
    327.         if(shader == null)
    328.             return null;
    329.         if(shader.isSupported && material && material.shader == shader)
    330.             return material;
    331.         else
    332.         {
    333.             material = new Material(shader);
    334.             material.hideFlags = HideFlags.DontSave;
    335.             if(material)
    336.                 return material;
    337.             else
    338.                 return null;
    339.         }
    340.     }
    341.  
    342.     // Performs one blur iteration.
    343.     private void FourTapCone(RenderTexture source, RenderTexture dest, int iteration)
    344.     {
    345.         float off = 0.5f + iteration * m_BlurSpread;
    346.         Graphics.BlitMultiTap(source, dest, BlurMaterial,
    347.                                new Vector2(-off, -off),
    348.                                new Vector2(-off, off),
    349.                                new Vector2(off, off),
    350.                                new Vector2(off, -off)
    351.             );
    352.     }
    353. }
    And relative shader file like this:

    Code (CSharp):
    1. Shader "OutlineBlur/Outline Color"
    2. {
    3.     Properties{
    4.         _Color("Outline Color", Color) = (1, 1, 1, 1)
    5.     }
    6.  
    7.     SubShader {
    8.  
    9.         ZTest Always Cull Off ZWrite Off
    10.  
    11.         Pass {
    12.             CGPROGRAM
    13.          
    14.             #pragma vertex vert
    15.             #pragma fragment frag
    16.             #pragma fragmentoption ARB_precision_hint_fastest
    17.  
    18.             fixed4 _Color;
    19.          
    20.             struct v2f {
    21.                 float4 pos : SV_POSITION;
    22.             };
    23.  
    24.          
    25.             v2f vert(float4 v : POSITION)
    26.             {
    27.                 v2f o;
    28.                 // Transform the vertex from object space to projection space
    29.                 o.pos = UnityObjectToClipPos(v);
    30.                 return o;
    31.             }
    32.          
    33.             fixed4 frag() : SV_Target {
    34.                 // outline color
    35.                 return fixed4(_Color.rgb, 1);
    36.             }
    37.          
    38.             ENDCG
    39.         }
    40.     }
    41.     Fallback off
    42. }
    Code (CSharp):
    1. Shader "OutlineBlur/BlurEffectConeTap" {
    2.     Properties {
    3.         _MainTex("", 2D) = "white" {}
    4.     }
    5.  
    6.     CGINCLUDE
    7.     #include "UnityCG.cginc"
    8.  
    9.     sampler2D _MainTex;
    10.     half4 _MainTex_TexelSize;
    11.     half4 _MainTex_ST;
    12.     half4 _BlurOffsets;
    13.  
    14.     struct v2f {
    15.         float4 pos : SV_POSITION;
    16.         half2 uv : TEXCOORD0;
    17.         half2 taps[4] : TEXCOORD1;
    18.     };
    19.  
    20.     v2f vert( appdata_img v ) {
    21.         v2f o;
    22.         o.pos = UnityObjectToClipPos(v.vertex);
    23.  
    24.         o.uv = v.texcoord - _BlurOffsets.xy * _MainTex_TexelSize.xy; // hack, see BlurEffect.cs for the reason for this. let's make a new blur effect soon
    25.         #ifdef UNITY_SINGLE_PASS_STEREO
    26.         // we need to keep texel size correct after the uv adjustment.
    27.         o.taps[0] = UnityStereoScreenSpaceUVAdjust(o.uv + _MainTex_TexelSize * _BlurOffsets.xy * (1.0f / _MainTex_ST.xy), _MainTex_ST);
    28.         o.taps[1] = UnityStereoScreenSpaceUVAdjust(o.uv - _MainTex_TexelSize * _BlurOffsets.xy * (1.0f / _MainTex_ST.xy), _MainTex_ST);
    29.         o.taps[2] = UnityStereoScreenSpaceUVAdjust(o.uv + _MainTex_TexelSize * _BlurOffsets.xy * half2(1, -1) * (1.0f / _MainTex_ST.xy), _MainTex_ST);
    30.         o.taps[3] = UnityStereoScreenSpaceUVAdjust(o.uv - _MainTex_TexelSize * _BlurOffsets.xy * half2(1, -1) * (1.0f / _MainTex_ST.xy), _MainTex_ST);
    31.         #else
    32.         o.taps[0] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy;
    33.         o.taps[1] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy;
    34.         o.taps[2] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);
    35.         o.taps[3] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);
    36.         #endif
    37.         return o;
    38.     }
    39.  
    40.     half4 frag(v2f i) : SV_Target {
    41.         half4 color = tex2D(_MainTex, i.taps[0]);
    42.         color += tex2D(_MainTex, i.taps[1]);
    43.         color += tex2D(_MainTex, i.taps[2]);
    44.         color += tex2D(_MainTex, i.taps[3]);
    45.         return (color * 0.25);
    46.  
    47.     }
    48.     ENDCG
    49.  
    50.     SubShader {
    51.          Pass {
    52.               ZTest Always Cull Off ZWrite Off
    53.  
    54.               CGPROGRAM
    55.               #pragma vertex vert
    56.               #pragma fragment frag
    57.               #pragma fragmentoption ARB_precision_hint_fastest
    58.               ENDCG
    59.           }
    60.     }
    61.     Fallback off
    62. }
    63.  
    Code (CSharp):
    1. Shader "OutlineBlur/CutoffBody" {
    2.     Properties {
    3.         _MainTex("Main Tex", 2D) = "white" {}
    4.         _BlurredTex ("Blurred Tex", 2D) = "white" {}
    5.     }  
    6.  
    7.     CGINCLUDE
    8.  
    9.     sampler2D _MainTex;
    10.     sampler2D _BlurredTex;
    11.     sampler2D _SrcTex;
    12.     half _OutlineStrength;
    13.  
    14.     struct a2v
    15.     {
    16.         float4 vertex : POSITION;
    17.         float4 texcoord : TEXCOORD0;
    18.     };
    19.  
    20.     struct v2f
    21.     {
    22.         float4 pos : SV_POSITION;
    23.         float2 uv : TEXCOORD0;
    24.     };
    25.  
    26.     v2f vert(a2v v)
    27.     {
    28.         v2f o;
    29.         o.pos = UnityObjectToClipPos(v.vertex);
    30.         o.uv = v.texcoord.xy;
    31.         return o;
    32.     }
    33.  
    34.     fixed4 frag(v2f i) : SV_Target
    35.     {
    36.         fixed4 c0 = tex2D(_MainTex, i.uv);
    37.         fixed4 c1 = tex2D(_BlurredTex, i.uv);
    38.         return c1 - c0;
    39.     }
    40.     ENDCG
    41.  
    42.     Subshader {
    43.         Pass {
    44.             ZTest Always Cull Off ZWrite Off Fog{ Mode Off }
    45.  
    46.             CGPROGRAM
    47.             #pragma vertex vert
    48.             #pragma fragment frag
    49.             #pragma fragmentoption ARB_precision_hint_fastest
    50.             ENDCG
    51.         }
    52.     }
    53.     FallBack off
    54. }
    Code (CSharp):
    1. Shader "OutlineBlur/Composite" {
    2.     Properties {
    3.         _MainTex ("Main Tex", 2D) = "white" {}                          
    4.         _SrcTex ("Src Tex", 2D) = "white" {}                          
    5.         _OutlineStrength("Outline Strength", Float) = 1.0
    6.     }
    7.  
    8.     Subshader {
    9.         Pass {
    10.             ZTest Always Cull Off ZWrite Off Fog { Mode Off }
    11.          
    12.             CGPROGRAM
    13.             #pragma vertex vert
    14.             #pragma fragment frag
    15.             #pragma fragmentoption ARB_precision_hint_fastest
    16.  
    17.             #include "UnityCG.cginc"
    18.  
    19.             sampler2D _MainTex;
    20.             sampler2D _SrcTex;
    21.             half _OutlineStrength;
    22.  
    23.             struct v2f {
    24.                 float4 pos : POSITION;
    25.                 half2 uv : TEXCOORD0;
    26.             };
    27.  
    28.             v2f vert (appdata_img v)
    29.             {
    30.                 v2f o;
    31.                 o.pos = UnityObjectToClipPos (v.vertex);
    32.                 o.uv = v.texcoord.xy;
    33.                 return o;
    34.             }
    35.  
    36.  
    37.             fixed4 frag( v2f i ) : SV_Target
    38.             {
    39.                 fixed4 c0 = tex2D( _MainTex, i.uv );
    40.                 fixed4 c1 = tex2D( _SrcTex, i.uv );
    41.                 return c0 * _OutlineStrength + c1;
    42.             }
    43.             ENDCG
    44.         }
    45.     }
    46.     Fallback off
    47. }
    48.  
     
    Last edited: Sep 3, 2019
  2. Ice_MJ

    Ice_MJ

    Joined:
    Jul 26, 2016
    Posts:
    15
    I got it, just check one toggle, :) use my whole afternoon...