Oh, gotcha. I always get my gamma exponents backward…
That looks really nice, actually, and largely fixes the problem that led me to the threshold in the first place, namely that it was darkening bright pixels if the previous frame’s pixel was dark, which shouldn’t ever happen.
Here’s the updated code and a screenshot:
/* COMPATIBILITY
- HLSL compilers
- Cg compilers
*/
// TWEAKABLES //
#define response_time 1.0 // This controls how brightly the phosphors glow. The default value is 1, lower values reduce the effect.
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
float frame_count;
float frame_direction;
float frame_rotation;
sampler2D texture;
};
struct previous
{
uniform sampler2D texture;
float2 tex_coord;
};
struct tex_coords
{
float2 tex;
float2 prev;
float2 prev1;
float2 prev2;
float2 prev3;
float2 prev4;
float2 prev5;
float2 prev6;
};
void main_vertex
(
float4 position : POSITION,
out float4 oPosition : POSITION,
uniform float4x4 modelViewProj,
float2 tex : TEXCOORD,
previous PREV,
previous PREV1,
previous PREV2,
previous PREV3,
previous PREV4,
previous PREV5,
previous PREV6,
out tex_coords coords
)
{
oPosition = mul(modelViewProj, position);
coords = tex_coords(tex, PREV.tex_coord,
PREV1.tex_coord,
PREV2.tex_coord,
PREV3.tex_coord,
PREV4.tex_coord,
PREV5.tex_coord,
PREV6.tex_coord);
}
float3x3 RGB_to_YIQ = float3x3(
0.299,0.587,0.114,
0.595716,-0.274453,-0.321263,
0.211456,-0.522591, 0.311135);
struct output
{
float4 col : COLOR;
};
output main_fragment(in float2 texCoord : TEXCOORD0,
uniform input IN,
previous PREV,
previous PREV1,
previous PREV2,
previous PREV3,
previous PREV4,
previous PREV5,
previous PREV6
)
{
// Sample our textures, with the previous frames in linear color space
float3 curr = tex2D(IN.texture, texCoord);
float3 prev0 = pow(tex2D(PREV.texture, texCoord), 2.2);
float3 prev1 = pow(tex2D(PREV1.texture, texCoord), 2.2);
float3 prev2 = pow(tex2D(PREV2.texture, texCoord), 2.2);
float3 prev3 = pow(tex2D(PREV3.texture, texCoord), 2.2);
float3 prev4 = pow(tex2D(PREV4.texture, texCoord), 2.2);
float3 prev5 = pow(tex2D(PREV5.texture, texCoord), 2.2);
float3 prev6 = pow(tex2D(PREV6.texture, texCoord), 2.2);
// Convert each previous frame to a grayscale image based on luminance value (i.e., convert from RGB to YIQ colorspace, where Y=luma)
float3 luma0 = (float3(mul(prev0, RGB_to_YIQ).r));
float3 luma1 = (float3(mul(prev1, RGB_to_YIQ).r));
float3 luma2 = (float3(mul(prev2, RGB_to_YIQ).r));
float3 luma3 = (float3(mul(prev3, RGB_to_YIQ).r));
float3 luma4 = (float3(mul(prev4, RGB_to_YIQ).r));
float3 luma5 = (float3(mul(prev5, RGB_to_YIQ).r));
float3 luma6 = (float3(mul(prev6, RGB_to_YIQ).r));
// Add each previous frame's luma value together with a linear decay
float3 trails = float3(0.0);
trails += luma0 * (response_time / 100.0);
trails += luma1 * (response_time / 200.0) / 2.0;
trails += luma2 * (response_time / 300.0) / 2.0;
trails += luma3 * (response_time / 400.0) / 2.0;
trails += luma4 * (response_time / 500.0) / 2.0;
trails += luma5 * (response_time / 600.0) / 2.0;
trails += luma6 * (response_time / 700.0) / 2.0;
trails = pow(trails, 1.0 / 2.2); // Bring the previous frames back to sRGB color space
output OUT;
OUT.col = float4((curr + trails), 1.0);
return OUT;
}
EDIT: made a couple more tweaks