Trail shader

Hi!

I’ve been working for some time now on way to have objects leave a trail, and I’m reaching a point where I just don’t understand what could possibly be wrong in my code.

The principle is quite simple:

  • I use a special camera to render only the objects that should leave a trail.
  • I print them on a Trail texture that I faded a bit so that its info slowly disappears.
  • I print this texture above the view of lower cameras.

The issue is that if I try for example to fade the trail texture by 10% before printing new info on it, I would expect my objects to have a trail of 10 instances of my “remanent” object, each one of them more transparent than the previous one, and it’s not the case, it only gives me 4 instances.
As far as I can tell, there must be something I don’t understand about rendering, or the way the textures work, but I can’t figure out what.

My post effect code (set on the main camera which renders the background):

using System;
using UnityEngine;

public class RemanentPostEffect : MonoBehaviour
{
    public Material remanentMaterial;
    public Material alphaMergeMaterial;
   
    public Camera remanentCamera;

    RenderTexture trailTexture;
   

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if(trailTexture == null)
        {
            //Create a texture to store the current trail
            trailTexture = new RenderTexture(source.width, source.height, 24, RenderTextureFormat.ARGB32);
            trailTexture.Create();
            remanentMaterial.SetTexture("_TrailTexture", trailTexture);
            remanentMaterial.SetFloat("_FrameFadeAmount", 0.1f);
        }
       
        RenderTexture currentRemanentObjectsViewTexture = RenderTexture.GetTemporary(source.width, source.height, 24, RenderTextureFormat.ARGB32);
        RenderTexture remanentObjectsWithTrailTexture = RenderTexture.GetTemporary(source.width, source.height, 24, RenderTextureFormat.ARGB32);

        //Clear those texture since they can contain some info already
        RenderTexture.active = currentRemanentObjectsViewTexture;
        GL.Clear(true, true, Color.clear);
        RenderTexture.active = remanentObjectsWithTrailTexture;
        GL.Clear(true, true, Color.clear);
        RenderTexture.active = null;

        //Render view from remanent camera only
        remanentCamera.targetTexture = currentRemanentObjectsViewTexture;
        remanentCamera.Render();
        remanentCamera.targetTexture = null;
       
        //Blit using the remanent material, with MainTex the current render from the remanent camera
        Graphics.Blit(currentRemanentObjectsViewTexture, remanentObjectsWithTrailTexture, remanentMaterial);

        //Merge remanent objects and their trail with the source texture
        alphaMergeMaterial.SetTexture("_HoverTex", remanentObjectsWithTrailTexture);
        Graphics.Blit(source, destination, alphaMergeMaterial);

        //Save trail texture to use in next frame
        RenderTexture.active = trailTexture;
        GL.Clear(true, true, Color.clear);
        RenderTexture.active = null;
        Graphics.Blit(remanentObjectsWithTrailTexture, trailTexture);

        RenderTexture.ReleaseTemporary(currentRemanentObjectsViewTexture);
        RenderTexture.ReleaseTemporary(remanentObjectsWithTrailTexture);
    }
}

The shader I use to create the trail (generated with Shader Forge):

// Shader created with Shader Forge v1.33
// Shader Forge (c) Neat Corporation / Joachim Holmer - http://www.acegikmo.com/shaderforge/

Shader "Shader Forge/RemanentPostEffect" {
    Properties {
        _MainTex ("MainTex", 2D) = "white" {}
        _TrailTexture ("TrailTexture", 2D) = "white" {}
        _FrameFadeAmount ("FrameFadeAmount", Float ) = 0.1
        [HideInInspector]_Cutoff ("Alpha cutoff", Range(0,1)) = 1
    }
    SubShader {
        Tags {
            "IgnoreProjector"="True"
            "Queue"="Transparent"
            "RenderType"="Transparent"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDBASE
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase
            #pragma only_renderers d3d9 d3d11 glcore gles n3ds wiiu
            #pragma target 3.0
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform sampler2D _TrailTexture; uniform float4 _TrailTexture_ST;
            uniform float _FrameFadeAmount;
            struct VertexInput {
                float4 vertex : POSITION;
                float2 texcoord0 : TEXCOORD0;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.uv0 = v.texcoord0;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex );
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
                float4 _TrailTexture_var = tex2D(_TrailTexture,TRANSFORM_TEX(i.uv0, _TrailTexture));
                float3 emissive = ((_MainTex_var.rgb*_MainTex_var.a)+((1.0 - _MainTex_var.a)*_TrailTexture_var.rgb));
                float3 finalColor = emissive;
                return fixed4(finalColor,max(_MainTex_var.a,saturate((_TrailTexture_var.a+(-1*_FrameFadeAmount)))));
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

I am attaching the project as unity package, in case anyone would want more precise information.
Also attached, a screenshot of the result with alpha from the trail being reduced by 0.1 each render (disregard the second ball, I have the issue where the final render is flipped, but I haven’t seriously looked into that yet).

(For the record, I initially tried otherwise, my researches can be found here: Texture2D.GetPixels without alloc? - Unity Engine - Unity Discussions )

2951698–218861–RemanentPostEffect.unitypackage (73.4 KB)

Bump?

I downloaded your package. Can I manipulate the trail size with anything? I wanted to create a similar trail in my project.