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 )
