Shader Study 03 - Metaballs: vimeo.com/46562719
/************************************ | |
* Shader Study 03 : Metaballs * | |
* num3ric - Eric Renaud-Houde * | |
* Summer 2012 * | |
************************************/ | |
#version 120 | |
#extension GL_ARB_texture_rectangle : enable | |
#extension GL_ARB_texture_non_power_of_two : enable | |
// Window size in pixels: Vec2f(getWindowSize()); | |
uniform vec2 windowSize; | |
// Particle positions in screen coordinates | |
uniform vec2 particles[100]; | |
// "Light wave" frequency. | |
// Standard range: [0.0, 0.15] | |
uniform float freq; | |
// "Light wave" frequency. | |
// Standard range: [0.0, 2*PI] | |
uniform float hue; | |
uniform sampler2DRect tex0; | |
const mat3 rgb2yiq = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135); | |
const mat3 yiq2rgb = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.1070, 1.7046); | |
float colorBurn(float bottom, float top) { | |
if ( top < 0.001 ) return 0.0; // We don't want to divide by zero | |
float col = 1.0 - (1.0 - bottom) / (2.0 * top); | |
return ( col < 0.0 ) ? 0.0 : col; | |
} | |
float vividLightBlend(float c1, float c2 ) { | |
float bottom, top; | |
if (c1 == c2) return c1; | |
if (c1 < c2) { | |
bottom = c1; | |
top = c2; | |
} else { | |
bottom = c2; | |
top = c1; | |
} | |
if ( top < 0.5 ) { | |
//unsure if this condition is necessary. | |
return colorBurn(bottom, top); | |
} else { | |
return bottom / ( 1.0 - 2.0 * (top - 0.5)); | |
} | |
} | |
void main() | |
{ | |
vec2 screenPos = gl_TexCoord[0].st; | |
screenPos.x *= windowSize.x/windowSize.y; | |
// Compute color with hue shift | |
// http://stackoverflow.com/questions/9234724/how-to-change-hue-of-a-texture-with-glsl | |
vec3 yiqColor = rgb2yiq * texture2DRect(tex0, windowSize*gl_TexCoord[0].st).rgb; | |
float originalHue = atan(yiqColor.b, yiqColor.g); | |
float finalHue = originalHue + hue; | |
float chroma = sqrt(yiqColor.b * yiqColor.b + yiqColor.g * yiqColor.g); | |
vec3 color = yiq2rgb*vec3(yiqColor.r, chroma * cos(finalHue), chroma * sin(finalHue)); | |
float potential = 0.0; | |
int i=0; | |
for (; i<100; i=i+1) | |
{ | |
potential += 1.0 / distance(screenPos, particles[i].xy/windowSize.yy);; | |
} | |
// Threshold for the equipotential line/isosurface between | |
// the black center and "the light waves". Manually adjusted. | |
if (potential > 300.0) { | |
potential = 0.0; | |
} else { | |
float inv_freq = 1.0/freq; | |
float light_wave_id = potential * freq; | |
if (abs(mod(light_wave_id, 2.0)) < 1.0) { | |
// light to dark | |
potential = freq * mod(potential, inv_freq); | |
} else { | |
// dark to light | |
potential = 1.0 - freq * mod(potential, inv_freq); | |
} | |
} | |
float r = vividLightBlend(potential, color.x); | |
float g = vividLightBlend(potential, color.y); | |
float b = vividLightBlend(potential, color.z); | |
gl_FragColor = vec4(r, g, b, 1.0); | |
} |
#extension GL_ARB_texture_rectangle : enable | |
#extension GL_ARB_texture_non_power_of_two : enable | |
void main() | |
{ | |
gl_TexCoord[0] = gl_MultiTexCoord0; | |
gl_Position = ftransform(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment