Sine Wave Zion - Additive Colour Demo in Shadertoy
Chilin - my African friend asked me if I could make a shader to visualise a sound or sine wave with harmonics included, so I wrote this WebGL shadertoy:
In the end, I didn't quite get there but this shader makes a nice illustration of the theory of additive colours, as various offsets of the sine waves are given their own channel: Red for the main frequency, Green for the second harmonic or octave, and Blue for the third harmonic.
Features: sine waves, pi, mouse input to alter parameters, interference patterns
Highlights of the code
This is just a normalised sine function of time multiplied by the pixel co-ordinates being rendered.
vec2 S; // speed of fundamental
S.x = (xy.x + xy.y)*(xy.x - xy.y)*0.5; // "velocity potential" a square of the pixel distance so it gets big quick
S.x -= iGlobalTime *timespeed; // animate stream
vec2 sxy = sin(3.14159 * S * 1.0 ); // its a sine wave of time and pi
The Full Code
// Concept: an animation of wave harmonics // show 1st, 2nd, 3rd order harmonics somehow float divs = 2.2; void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec4 m = iMouse; if ( m.x == 0. && m.y == 0.) { m.x = iResolution.x / 2.; m.y = iResolution.y / 2.; } float dist = m.x - ( iResolution.x / 2.0 ); // centererd float speed = 0.0009; // 0.9 camera movement to plane float timespeed = 0.1 ; // 0.1 wave movement on the ribbons // MOUSE: multiple by my or mx to get value between 1 and 2 float my = float( (m.y + iResolution.y ) / iResolution.y ); float mx = float( (m.x + iResolution.y ) / iResolution.x ); float t = 8.0 - speed ; // divs create staggered / staged division, old setting was divs += t / 0.20; // let the mouse distance control the zoom divs += t / ( ( m.x + 2. ) / iResolution.x ); vec2 div = vec2( divs, divs*iResolution.y/iResolution.x ); vec2 uv = fragCoord.xy / iResolution.xy; // center on screen then pan off: uv -= 0.1 + (iGlobalTime*0.0001); float b = 1.0*divs/iResolution.x; // blur over 2.4 pixels vec2 xy = div*uv; vec2 S; // speed of fundamental vec2 S2; // speed of 1st octave vec2 S3; // speed of 2nd harmonic (perfect fifth?) S.x = (xy.x + xy.y)*(xy.x - xy.y)*0.5; // "velocity potential" S2.x = (xy.x + xy.y)*(xy.x - xy.y)*0.5; // "velocity potential" S3.x = (xy.x + xy.y)*(xy.x - xy.y)*0.5; // "velocity potential" S.y = xy.x*xy.y; // stream function S2.y = xy.x*xy.y; // stream function S3.y = xy.x*xy.y; // stream function // speed of the dots S.x -= iGlobalTime *timespeed; // animate stream S2.x -= iGlobalTime *timespeed + (my * 20. ); // animate stream S3.x -= iGlobalTime *timespeed + (my * 20.); // animate stream // HERE IS THE WAVE HARMONICS // SXY IS FUNDAMENTAL WAVE2 IS 2ND HARMONIC // sxy is *probably* the main wave // wave2 is the 2nd harmonic vec2 sxy = sin(3.14159 * S * 1.0 ); vec2 wave2 = sin(3.14159 * S2 * 2.0 ); // 2.00 is double vec2 wave3 = sin(3.14159 * S3 * 3.0 ); // 3.00 is double // w2 is the 2nd harmonic float a = sxy.x * sxy.y; // combine sine waves using product float w2 = wave2.x * wave2.y; // combine sine waves using product float w3 = wave3.x * wave3.y; // combine sine waves using product // not sure what this does but we will do it to w2, w3 as well a = 0.5*a + 0.5; // remap to [0..1] a = smoothstep( 0.85-b, 0.85+b, a ); // threshold w2 = 0.5*a + 0.5; // remap to [0..1] w2 = smoothstep( 0.85-b, 0.85+b, a ); // threshold w3 = 0.5*a + 0.5; // remap to [0..1] w3 = smoothstep( 0.85-b, 0.85+b, a ); // threshold float c = sqrt( a ); // correct for gamma float w2gamma = sqrt( w2 ); // correct for gamma float w3gamma = sqrt( w3 ); // correct for gamma float red, green, blue; red = sxy.x - sxy.y ; green = wave2.x - wave2.y; blue = wave3.x - wave3.y; float crossover = -1.5; if (red < crossover) { red = red * -1.; } if (green < crossover) { green = green * -1.; } if (blue < crossover) { blue = blue * -1.; } fragColor = vec4( red, green, blue, 1.0); }Posted by tomachi on March 17th, 2017 filed in Visuals