Amoeba Dance

Apr 2008

This is a little test using GLSL in Quartz Composer 3.0, and controlling via VDMX. All happening in realtime, completely audio-reactive with no post production, user-interaction or timeline animations etc.

 

Soundtrack "Caliper Remote" by Autechre (from LP5 - 1998)

Who needs autechre when you have a bunch of mad girls!
P.S. I have hours of footage of this if anyone is interested :P

 

The Quartz Composer patch simply creates a sphere and applies a GLSL vertex shader to it to distort the mesh based on spherical coordinates. A lot of these parameters are published and in VDMX a 9-band audio analysis is performed and assigned to them through the QC ports. Throughout the piece I don't touch anything, everything is completely audio reactive. With more time more parameters can be added to the GLSL shader, and with more specific audio analysis the results can be a lot more impressive.

Infinite thanks to Alex 'Toneburst' for sucking me into GLSL.

The GLSL code is below, a few generic functions to convert between cartesian and spherical coordinates, and then a radial distortion function (could be anything - will most probably embellish on this animation a bit more).

I'm a bit curious about the line:

sCoords.theta = atan(cPoint.x, cPoint.y);

I originally had it the other way round:

sCoords.theta = atan(cPoint.y, cPoint.x);

Which is what I would have expected according to the maths, but there's a weird glitch when I do it that way, and swapping the order of x and y gets rid of it... weird.

I also noticed that when not using any distortion at all, but just mapping cartesian to spherical and back to cartesian again the sphere is not perfectly round but ever so slightly squared. I'm guessing this is due to rounding errors on the GPU.

UPDATE:
A few people have mentioned they don't get the same look when they use the QTZ file, this is because the QTZ file renders with very basic shading and there is a bit of realtime post fx done in VDMX. The Effects I'm using (from top to bottom) are:
Serpia Tone (100%, Source Atop)
Shaded Material (0-40% tied to audio analysis, Soft Light)
City Lights (100%, Source Atop)
Bloom (100%, Screen)

UPDATE 2:
A lot of people have said that this QTZ / VDMX setup runs quite slow on their machines. This video was created with a Mac Pro with ATI X1900XT and runs pretty smooth. On a Macbook Pro with ATI X1600 it is quite slower and I need to set the QTZ to run at 320x240 instead of 640x480 (setup in VDMX). Alternatively you can open the QTZ file and bring down the number of segments of the sphere. At the moment it is 200x200 which is stupendously high - but runs smooth on a Mac Pro so I kept it high as possible :). Even 50x50 will still give a pretty smooth mesh unless the deformation waves have quite a short wavelength. I wanted to publish the number of segments as a input parameter so it can be tweaked in VDMX but unfortunately QC does not allow that...

 

/************** generic cartesian spherical conversion functions ***************/
struct spherical {
	float r, phi, theta;
};
 
spherical cartesianToSpherical(vec3 cPoint) {
	spherical sCoords;
	float xyLen = length(cPoint.xy);
	sCoords.r = length(cPoint);  
	sCoords.phi = acos(cPoint.z / sCoords.r);
	sCoords.theta = atan(cPoint.x, cPoint.y);
	return sCoords;
}
 
vec3 sphericalToCartesian(spherical sPoint) {
	vec3 cCoords;
	cCoords.x = sPoint.r * sin(sPoint.phi) * cos(sPoint.theta);
	cCoords.y = sPoint.r * sin(sPoint.phi) * sin(sPoint.theta);
	cCoords.z = sPoint.r * cos(sPoint.phi);
	return cCoords;
}
/*************************************************************/
 
 
uniform float RadMod;
 
uniform vec2 count;
uniform vec2 phase;
uniform vec2 amount;
 
 
 
/************* simple scaling function, adds to the radius ***********/
// takes a spherical coordinates as parameter
// and returns spherical coordinates
spherical radialDistort(spherical sPoint, float RadMod) {
	sPoint.r += RadMod;
	return sPoint;
}
 
 
/************* modulates radius based on theta and phi ***********/
// takes a spherical coordinates as parameter
// and returns spherical coordinates by writing to the same parameter
// did it like that just to try out the in/out keywords
void radialDistort2(inout spherical sPoint) {
	sPoint.r += sin(sPoint.phi * count.x + phase.x) * amount.x;
	sPoint.r += cos(sPoint.theta * count.y + phase.y) * amount.y;
}
 
 
 
void main()
{
	spherical sphereCoords = cartesianToSpherical(gl_Vertex.xyz);
 
	// this function just scales and returns the new spherical coordinates in the function
	sphereCoords = radialDistort(sphereCoords, RadMod);
 
	// this function does some other stuff and writes the spherical coordinates back to the same variable
	// did it like that just to try out the in/out keywords
	radialDistort2(sphereCoords);
 
	// convert modified spherical coordindates back to cartesian
	vec3 outCoords = sphericalToCartesian(sphereCoords);
	gl_Position = gl_ModelViewProjectionMatrix * vec4(outCoords, 1.0);
 
 
	// lighting
	vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
	vec3 lightDir = normalize(vec3(gl_LightSource[0].position));
	float NdotL = max(dot(normal, lightDir), 0.0);
	vec4 diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
	gl_FrontColor =  NdotL * diffuse;
 
	// add fake lighting based on radius;
	gl_FrontColor =  gl_FrontColor * 0.5 + (abs(sphereCoords.r)-RadMod) * 0.5;
}
( categories: )