Giving visuals an analog feel

Hi guys,

I have been working on audio-reactive visuals for a while now and I’m looking for a way to make it feel more analog. I guess the most important aspects are color and noise, maybe some subtle glitches too. This video gives you an idea of what I’m looking for.

Does anyone have any tips on where to start with this? I have a little experience in writing shaders.

Any examples or ideas would be great.


The only thing that comes to mind would be to take a look at all those vintage, instagram-like photo effects you see on everyone’s iphone lately. You could probably do the same kind of process in OF. It would be a post-processing type way of doing it, not sure how to make something that would look inherently analog in a digital medium though. Here are some photoshop actions that recreate all of the cliche vintage iphone effects:


I think some of what is going on in that video is “chromatic aberration”, this is something that you should be able to accomplish with a fragment shader:

Also in the emulator world, there are a number of projects that attempt to make your computer act more like an old tv.

This post talks about patches to stella that do this:
Here are some cpp things that emulate NTSC output for various platforms:
This blog post talks about some of the high level ways to jack up your signal:

Of course, you won’t do that bad by going and grabbing some of Vade’s patches off of his site:

All those shader that Vade has on his site are basically how I learned the GLSL that I know. There’s a ton on there once you look around a little. Really remarkably stuff that only requires minor tweaking to get working in OF.

I’ve always been a fan of grain myself for analog feelings. Some of my rather lame attempts at frag shaders for that are here:

uniform sampler2D m_Texture;  
varying vec2 texCoord;  
uniform float m_Time;  
uniform float m_Strength;  
uniform float grainSize;  
void main() {  
    float x = (texCoord.x+4.) * (texCoord.y+4.) * (m_Time*10.);  
    vec4 grain = vec4(mod((mod(x, 13.) + 1.) * (mod(x, 123.) + 1.), grainSize)-(grainSize*0.5)) * m_Strength;  
    gl_FragColor = texture2D(m_Texture, texCoord) + grain;  


uniform float time;  
varying vec4 vertexInImageSpace;  
float rand(vec2 co)  
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);  
void main()  
    //just get a random number, using the vertex's screen-space position as a seed along with the time.  
    float r = rand(vec2(vertexInImageSpace.x/2.0 + sin(time), vertexInImageSpace.y/2.0 + cos(time)));  
    //play with the noise a bit; clamp it based on its value and scale the alpha.  
    if(r < 0.3) r = 0.0;  
    vec4 finalColor = vec4(r,r,r,r*0.7);  
    gl_FragColor = texture2D(m_Texture, vertexInImageSpace.xy) - clamp(finalColor, 0.0, 1.0);  

Thanks for all the replies. I’ve started reading the Orange Book for learning shaders and I must say it’s a lot of fun. I generated a noise texture in photoshop and I blended it in using this:

        vec2 noiseCoords = float(frameNum * 50) + texCoord;  
	noiseCoords = mod(noiseCoords, noiseTextureSize);  
	vec4 noiseColor = texture2DRect(noiseTexture, noiseCoords);  
	vec4 noiseCol1 = mix(noiseColor, texture2DRect(tex0, texC), 0.95);  

which gives me almost the exact same results as Joshua’s second shader. My guess is that texture lookup is faster then the random number generation but I could be wrong. I’ll be looking around at Vade’s website for some more examples.

Yep, texture look-up is most definitely faster than random num generation. Really the only thing either of them have that’s at all quasi-cool is the grain size control in the first one, and even that needs a bunch of work to actually look like film grain :slight_smile:

I ended up using the following shader, in case it might be of interest to anyone. I used the technicolor color filtering from Vade’s website.


uniform sampler2DRect tex0;  
varying vec2 texCoord;  
void main(){  
	texCoord = gl_MultiTexCoord0.xy;  
	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;  
	gl_Position = pos;  


uniform sampler2DRect tex0;  
uniform sampler2DRect noiseTexture;  
uniform vec2 textureSize;  
uniform vec2 noiseTextureSize;  
uniform int frameNum;  
uniform float vignetteSize;  
uniform float colorFilterAmount;  
uniform float noiseAmount;  
varying vec2 texCoord;  
const vec4 redfilter 		= vec4(1.0, 0.0, 0.0, 1.0);  
const vec4 bluegreenfilter 	= vec4(0.0, 1.0, 0.7, 1.0);  
void main(){	  
	vec2 texC = texCoord;  
	float vignetteSizeSquared = vignetteSize * vignetteSize;  
	vec4 col = texture2DRect(tex0, texC);  
	// vignette  
	vec2 center = textureSize / 2.0;  
	vec2 d = center - vec2(texCoord);  
	float distSQ = d.x*d.x + d.y*d.y;  
	float invDistSQ = 1.0 / distSQ;  
	col.rgb -= distSQ / vignetteSizeSquared;  
	col = clamp(col, 0.0, 1.0);  
	// noise   
	vec2 noiseCoords = float(frameNum * 50) + texCoord;  
	noiseCoords = mod(noiseCoords, noiseTextureSize);  
	vec4 noiseColor = texture2DRect(noiseTexture, noiseCoords);  
	noiseColor = mix(noiseColor, col, noiseAmount);  
	// color filter  
	vec4 redrecord = noiseColor * redfilter;  
	vec4 bluegreenrecord = noiseColor * bluegreenfilter;  
	vec4 rednegative = vec4(redrecord.r);  
	vec4 bluegreennegative = vec4((bluegreenrecord.g + bluegreenrecord.b)/2.0);  
	vec4 redoutput = rednegative * redfilter;  
	vec4 bluegreenoutput = bluegreennegative * bluegreenfilter;  
	vec4 result = redoutput + bluegreenoutput;  
	result = mix(noiseColor, result, colorFilterAmount);  
	result.a = noiseColor.a;  
	gl_FragColor = result;  

Without shader:

With shader:

Nice. Love the line curvature and the vignetting is nice. Looking forward to seeing how the noise works into in over time too, since you’re altering per frame.