Skip to content

Instantly share code, notes, and snippets.

@num3ric
Created September 23, 2012 06:52
Show Gist options
  • Save num3ric/3769142 to your computer and use it in GitHub Desktop.
Save num3ric/3769142 to your computer and use it in GitHub Desktop.
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