Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We’re making changes to the Unity Runtime Fee pricing policy that we announced on September 12th. Access our latest thread for more information!
    Dismiss Notice
  3. 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...