Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Multi pass shader that uses texture between passes

Discussion in 'Shaders' started by Iron-Warrior, Sep 26, 2018.

  1. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Hi, I apologize if this has been asked before, but I'm having a ton of trouble finding a reference for this on the internet.

    I'm looking to implement this fluid effect. The theory behind it isn't super complicated, and it boils down to three passes:

    1. The first pass renders all of the particles out to a full screen depth texture. This part is pretty easy:
      upload_2018-9-25_21-32-17.png
      (Note that I'm using a camera with an extremely close Far Plane to more easily visualize the depth)
    2. The second pass renders all the particles again using additive blending to another full screen texture. However, in order to correctly apply the additive effect, the depth texture from the first pass must be sampled.
    3. The third pass then takes the texture from the second pass and uses it to calculate the actual image that is output to the screen.
    My problem is I'm not sure how to go about implementing these passes. I need to be able to store the output of the first two in individual textures (with the first texture being used in the second pass). I'm not entirely sure how to do this. Is there a way to render out each pass in the correct order to a texture? Also, how would I combine the final image with what is already in my buffer?

    Thanks,
    Erik
     
    AntonChegurov likes this.
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    You render to render textures. There's a bunch of ways to go about doing the rest. The short version is you likely want to rely on rendering the spheres via script calls, be it a command buffer, Graphics calls, or using replacement shaders.
     
    Iron-Warrior likes this.
  3. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Thanks very much for the help @bgolus. It took a couple days, but I've gotten pretty close. Few issues with converting the additive normals, but the command buffer stuff is done at least. For anyone reading this, command buffers are superb and a ton of fun.

    FakeMetaballsLoStages.gif

    Will post my code when I've figured the whole thing out.

    EDIT: Final image that I got: https://imgur.com/a/D29OMVQ

    It's not perfect but I'm happy with how far it progressed. Below is the (super messy!) code. Take no mind of the nested if statements.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Rendering;
    4.  
    5. public class CommandBufferFluid : MonoBehaviour
    6. {
    7.     [SerializeField]
    8.     Renderer fluidRenderer;
    9.  
    10.     [SerializeField]
    11.     Shader blurShader;
    12.  
    13.     [SerializeField]
    14.     int iterations = 4;
    15.  
    16.     [SerializeField, Range(0, 3)]
    17.     int step = 0;
    18.  
    19.     private void Start()
    20.     {
    21.         AddBuffer();
    22.     }
    23.  
    24.     private void OnValidate()
    25.     {
    26.         if (Application.isPlaying)
    27.             AddBuffer();
    28.     }
    29.  
    30.     private void AddBuffer()
    31.     {
    32.         Camera.main.RemoveAllCommandBuffers();
    33.  
    34.         Material blurMaterial = new Material(blurShader);
    35.         blurMaterial.hideFlags = HideFlags.HideAndDontSave;
    36.  
    37.         var commandBuffer = new CommandBuffer();
    38.  
    39.         int depthID = Shader.PropertyToID("_ParticleDepthTexture");
    40.         int additiveID = Shader.PropertyToID("_AdditiveTexture");
    41.  
    42.         commandBuffer.GetTemporaryRT(depthID, -1, -1, 0, FilterMode.Point, RenderTextureFormat.RFloat);      
    43.         commandBuffer.SetRenderTarget(depthID);
    44.         commandBuffer.ClearRenderTarget(true, true, Color.clear, 1f);
    45.         commandBuffer.DrawRenderer(fluidRenderer, fluidRenderer.material, 0, 0);
    46.         commandBuffer.SetGlobalTexture("_ParticleDepthTexture", depthID);
    47.  
    48.         if (step == 0)
    49.         {
    50.             commandBuffer.Blit(depthID, BuiltinRenderTextureType.CameraTarget);
    51.         }
    52.         else
    53.         {
    54.             commandBuffer.GetTemporaryRT(additiveID, -1, -1, 0, FilterMode.Point, RenderTextureFormat.ARGBFloat);
    55.             commandBuffer.SetRenderTarget(additiveID);
    56.             commandBuffer.ClearRenderTarget(true, true, Color.clear, 1f);
    57.             commandBuffer.DrawRenderer(fluidRenderer, fluidRenderer.material, 0, 1);
    58.  
    59.             if (step == 1)
    60.             {
    61.                 commandBuffer.Blit(additiveID, BuiltinRenderTextureType.CameraTarget);
    62.             }
    63.             else
    64.             {
    65.                 int blur1 = Shader.PropertyToID("_Temp1");
    66.                 int blur2 = Shader.PropertyToID("_Temp2");
    67.  
    68.                 commandBuffer.GetTemporaryRT(blur1, -2, -2, 0, FilterMode.Bilinear, RenderTextureFormat.ARGBFloat);
    69.                 commandBuffer.GetTemporaryRT(blur2, -2, -2, 0, FilterMode.Bilinear, RenderTextureFormat.ARGBFloat);
    70.  
    71.                 commandBuffer.Blit(additiveID, blur1);
    72.  
    73.                 for (var i = 0; i < iterations; i++)
    74.                 {
    75.                     commandBuffer.Blit(blur1, blur2, blurMaterial, 1);
    76.                     commandBuffer.Blit(blur2, blur1, blurMaterial, 2);
    77.                 }
    78.  
    79.                 commandBuffer.SetGlobalTexture("_AdditiveTexture", blur1);
    80.  
    81.                 if (step == 2)
    82.                 {
    83.                     commandBuffer.Blit(blur1, BuiltinRenderTextureType.CameraTarget);
    84.                 }
    85.                 else
    86.                 {
    87.                     commandBuffer.SetRenderTarget(BuiltinRenderTextureType.CameraTarget);
    88.                     commandBuffer.DrawRenderer(fluidRenderer, fluidRenderer.material, 0, 2);
    89.                 }
    90.             }
    91.         }
    92.  
    93.         commandBuffer.ReleaseTemporaryRT(depthID);
    94.         commandBuffer.ReleaseTemporaryRT(additiveID);
    95.  
    96.         Camera.main.AddCommandBuffer(CameraEvent.AfterForwardAlpha, commandBuffer);
    97.     }
    98. }
    99.  
    Code (csharp):
    1.  
    2. Shader "Fluid/Fake Metaballs Depth"
    3. {
    4.     Properties
    5.     {
    6.         _Matcap("Matcap", 2D) = "white" {}
    7.     }
    8.     SubShader
    9.     {
    10.         Pass
    11.         {
    12.             CGPROGRAM
    13.             #pragma vertex vert
    14.             #pragma fragment frag
    15.            
    16.             #include "UnityCG.cginc"
    17.  
    18.             struct appdata
    19.             {
    20.                 float4 vertex : POSITION;  
    21.                 float2 uv : TEXCOORD0;
    22.             };
    23.  
    24.             struct v2f
    25.             {
    26.                 float4 vertex : SV_POSITION;
    27.                 float2 uv : TEXCOORD0;
    28.                 float depth : DEPTH;
    29.             };
    30.            
    31.             v2f vert (appdata v)
    32.             {
    33.                 v2f o;              
    34.                 o.vertex = UnityObjectToClipPos(v.vertex);  
    35.                 o.depth = COMPUTE_DEPTH_01;
    36.                 o.uv = v.uv;
    37.                 return o;
    38.             }
    39.            
    40.             float4 frag (v2f i) : SV_Target
    41.             {
    42.                 clip(length(i.uv - 0.5) > 0.5 ? -1 : 1);
    43.  
    44.                 return i.depth;
    45.             }
    46.             ENDCG
    47.         }
    48.  
    49.         Pass
    50.         {
    51.             Blend One One
    52.  
    53.             ZTest Always
    54.             ZWrite Off
    55.  
    56.             CGPROGRAM
    57.             #pragma vertex vert
    58.             #pragma fragment frag
    59.            
    60.             #include "UnityCG.cginc"
    61.  
    62.             struct appdata
    63.             {
    64.                 float4 vertex : POSITION;  
    65.                 float4 uv : TEXCOORD0;
    66.             };
    67.  
    68.             struct v2f
    69.             {
    70.                 float4 vertex : SV_POSITION;
    71.                 float2 uv : TEXCOORD0;
    72.                 float4 screenPos : TEXCOORD1;
    73.                 float depth : DEPTH;
    74.                 float size : TEXCOORD2;
    75.             };
    76.            
    77.             v2f vert (appdata v)
    78.             {
    79.                 v2f o;              
    80.                 o.vertex = UnityObjectToClipPos(v.vertex);  
    81.                 o.screenPos = ComputeScreenPos(o.vertex);
    82.                 COMPUTE_EYEDEPTH(o.depth);
    83.                 o.uv = v.uv;
    84.                 o.size = v.uv.z;
    85.                 return o;
    86.             }
    87.  
    88.             uniform sampler2D _ParticleDepthTexture;
    89.  
    90.             float4 frag (v2f i) : SV_Target
    91.             {
    92.                 clip(length(i.uv - 0.5) > 0.5 ? -1 : 1);
    93.  
    94.                 float2 toCenter = (i.uv - 0.5) * 2;
    95.                 float radius = i.size * 0.5;
    96.                 float z = sqrt(1.0 - toCenter.x * toCenter.x - toCenter.y * toCenter.y) * radius;
    97.  
    98.                 float underlyingDepth = tex2D(_ParticleDepthTexture, i.screenPos.xy / i.screenPos.w).r;
    99.                 float decodedDepth = underlyingDepth / _ProjectionParams.w;
    100.                 float dz = saturate(decodedDepth - i.depth + z);
    101.  
    102.                 toCenter *= dz;
    103.  
    104.                 return float4(toCenter, dz, dz / z) * 100;
    105.             }
    106.             ENDCG
    107.         }
    108.  
    109.         Pass
    110.         {
    111.             CGPROGRAM
    112.             #pragma vertex vert
    113.             #pragma fragment frag
    114.            
    115.             #include "UnityCG.cginc"
    116.  
    117.             struct appdata
    118.             {
    119.                 float4 vertex : POSITION;  
    120.                 float2 uv : TEXCOORD0;
    121.             };
    122.  
    123.             struct v2f
    124.             {
    125.                 float4 vertex : SV_POSITION;
    126.                 float2 uv : TEXCOORD0;
    127.                 float4 screenPos : TEXCOORD1;
    128.             };
    129.            
    130.             v2f vert (appdata v)
    131.             {
    132.                 v2f o;              
    133.                 o.vertex = UnityObjectToClipPos(v.vertex);  
    134.                 o.uv = v.uv;
    135.                 o.screenPos = ComputeScreenPos(o.vertex);
    136.                 return o;
    137.             }
    138.  
    139.             sampler2D _AdditiveTexture;
    140.             sampler2D _Matcap;
    141.  
    142.             float4 frag (v2f i) : SV_Target
    143.             {
    144.                 clip(length(i.uv - 0.5) > 0.5 ? -1 : 1);
    145.  
    146.                 float4 merged = tex2D(_AdditiveTexture, i.screenPos.xy / i.screenPos.w);
    147.                 merged.xy /= merged.z;
    148.                 merged.z = sqrt(1.0 - merged.x * merged.x - merged.y * merged.y);
    149.  
    150.                 float2 normal = merged.xy * 0.5 + 0.5;
    151.  
    152.                 float4 mc = tex2D(_Matcap, normal);
    153.                
    154.  
    155.                 return mc;
    156.             }
    157.             ENDCG
    158.         }
    159.     }
    160. }
    161.  
    The matcap materials I used are from the article in the opening post.
     
    Last edited: Sep 29, 2018
    qdeanc, ahnafnafee, qframe and 8 others like this.