Archive for February, 2008


Patching Marathon, GPU Branching

After a patching marathon, I’ve finally completed my conversion of Desaxismundi’s 55 Maths Surfaces into individual GLSL patches. That’s 55 patches, each with 13 connections…
You can do the maths if you like; all I know is that’s a lot of little yellow leads. This program is going to give me RSI…

I did manage to keep things relatively tidy, by grouping the GLSL patches into 6 Macros. Demultiplexer patches were used to switch on the appropriate macro, then enable the correct GLSL patch within the active macro. I initially attempted the switching using JavaScript, but it turned out to be easier to achieve using Demultiplexers and some very simple maths.

The reason for all this is that, after making a few enquiries, I’ve discovered that graphics hardware tends to have ‘issues’ with branching logic. Apparently, some GPUs actually evaluate the result of both (or all) results, then chooses which result to use. This meant that in the case of some of the surface shaders I’d put together previously, the GPU was attempting to compute 10 different positions for each vertex- which is obviously not a Good Thing, in terms of efficiency. It seemed the only safe solution was to separate each surface calculation into its own discrete GLSL shader patch. Hence my patching hell….

The result, however, promises to be well worth the effort. The composition certainly seems to run a lot more smoothly now. It’s looking good. The only thing left to do is to iron-out the massive scale differences between some of the surfaces, probably by applying a second transform matrix to the result of the vertex position calculation. I think I’ll hold off on that for the moment, though.



My attempt to emulate VVVVs Spreading functions, when applied to an iterated GLSL patch.
Because QC can’t do multiple GLSL shaders, each iteration contains a Render In Image patch, so it’s not a very efficient composition. Also, since each GLSL shader is rendered to a 2D image, there’s no way of compositing the different slices together in a genuine 3D space- hence I’ve made them all semi transparent, trying to make a feature of a limitation.

Pseudo Spreads 01Pseudo Spreads 02
Pseudo Spreads 03Pseudo Spreads 04
Pseudo Spreads 05


The Best Thing About Quartz Composer

… and the worst thing….

Quartz Composer Spaghetti 02


SuperShape 2D CIFilter Sourcecode

Based on supershape formula

CIFilter conversion by alx at toneburst, 2008

////    SUPERSHAPE 2D     ////

vec2 super2D(float m, float n1, float n2, float n3, float val)
	float r;
	float t1, t2;
	float a = 1.0, b = 1.0;
	t1 = cos(m * val / 4.0) / a;
	t1 = abs(t1);
	t1 = pow(t1, n2);
	t2 = sin(m * val / 4.0) / b;
	t2 = abs(t2);
	t2 = pow(t2, n3);
	r = pow(t1 + t2, 1.0 / n1);
	r = 1.0 / r;
	vec2 xy = (abs(r) == 0.0) ?	vec2(0.0,0.0) : 
							vec2(r * cos(val),r * sin(val));
 	// Output
 	return xy;  

////      MAIN LOOP       ////

kernel vec4 superShape_2D(	float M, float N1, float N2, float N3,
						float Scale, float Twist, float Width,
						float Zoom, vec2 Center,
						float PolarMix, float CartesianMix, float PolarCartesianMix,
						float ColorTable, __color Color, sampler LUT)
	// Sampler dimensions
	vec2 dims = samplerSize(LUT);
	// Normalised coord of current pixel of LUT texture (0.0 > 1.0)
	vec2 xy = samplerCoord(LUT) / dims;
	// Centered coords (-1.0 > 1.0) + center-offset
	vec2 xyCenter = ((2.0 * xy - 1.0) + Center) * Zoom;
	// Polar coords (angle)
	float phi = (atan(xyCenter.y,xyCenter.x));
	// Distance from center (including offset)
	float r = distance(xyCenter,vec2(0.0,0.0) + Center);
	/* Create value to send to superShape function */
	// Mix polar-coordinate values phi and r
	float polar = mix(phi,r,PolarMix);
	// Mix cartesian coordinate X and Y values
	float cartesian = mix(xyCenter.x,xyCenter.y,CartesianMix);
	// Mix the mixed values
	float polarCartesian = mix(polar,cartesian,PolarCartesianMix)  * Scale + Twist;
	// Send value to superShape function
	vec2 point = super2D(M,N1,N2,N3,polarCartesian);
	// Distance between current pixel and superShape result for this pixel
	float dist = distance(xyCenter,point);
	// Scale distance
	float distSmooth = smoothstep(Width,0.0,dist);
	// Output
	return sample(LUT, vec2(distSmooth,ColorTable) * dims) * Color;

More Maths Surfaces

I’m working my way through Desaxismundi’s Maths Surface shader collection, adding them to to my Quartz Composer file.

I’ve also added controls, and my usual Smooth patches, for added niceness.

Maths Surfaces 06Maths Surfaces 07
Maths Surfaces 08Maths Surfaces 09


Maths Surfaces

HLSL to GLSL conversion of Desaxismundi’s VVVV Maths surfaces shaders.

I really like the simple lighting on this shader. Desaxismundi has removed all the normal-calculation he had in an earlier version of the shader, so you can’t really use more realistic lighting. I actually quite like the flat-shaded ‘graphic’ look, though.

Maths Surfaces 01Maths Surfaces 02
Maths Surfaces 03Maths Surfaces 04
Maths Surfaces 05Maths Surfaces 06

The plan is to try to use multiple Render In Image  patches with nested GLSL shaders, to composite multiple shaders on top of each other. Before I can do that effectively, I’ll have to get my head around 3D transformation matrices (gulp)…


More 2D Supershapes

Same basic code, only this time, the colours are retreived from a two-dimensional lookup table, so you can fade from one set of colours to another.

I don’t seem to be be getting the obvious natural forms I got with the previous versions (like the starfish at the bottom-right of the last post). Not quite sure what I’ve changed that would cause this difference. On the other hand, I’ve made a lot of tweaks to the code, and to the ranges of the various controls, so it’s probably a combination of things.

This version also adds some extra controls, so the effect can be driven not just by the polar coordinate ‘phi’ (angle) values, as was the case in the original code, but also from the r (polar radius), X and Y values, or any mix of the four.

2D Supershapes LUT 062D Supershapes LUT 04
2D Supershapes LUT 032D Supershapes LUT 02
2D Supershapes LUT 012D Supershapes LUT 06
2D Supershapes LUT 072D Supershapes LUT 08

Still to do:
• Better lookup table
• Find some way of smoothing the edge of the phi value to eliminate the nasty hard edge you tend to get between the minimum and maximum value for the angle coordinate. You can see what I mean in the screenshot on the right of the 2nd-last row. You can’t eliminate the problem completely, as it’s inherent in the way polar coordinates work, but I think it should be possible to do some kind of crossfade to at least dull the edge of the line. There’s also a slight but annoying glitch going from the centre, horizontally to the right edge. It’s just visible on this same screenshot, and I think it may be a bug in the Render In Image patch.


2D Supershapes

Realtime, but 2D-only, sadly…
Based on code from this page.

SuperShape 2D 01SuperShape 2D 02SuperShape 2D 04SuperShape 2D 03
SuperShape 2D 05SuperShape 2D 06


SuperShapes in Quartz Composer!!

Before you get too excited, they’re not realtime. I have a lot of learning to do before I’ll be able to get realtime SuperFormula rendering happening in QC, sadly.

These are models rendered out of Paul Bourke’s supershapes X11 application which I just bought, imported into QC (via MeshLab) with the OFF model rendering plugin.

Cheating, really, but I couldn’t resist…

SuperShape 01
SuperShape 02
SuperShape 03

For those not in-the-know, the SuperFormula is a mathematical formula capable of creating a vast range of 2D and 3D forms, including many that apear in the natural world, from just seven variables.
See the Geniaal website for more info. It’s pretty-much the holy grail of realtime generative 3D. There’s plenty of info about it on the web, including some ready-made OpenGL code, so I’m eventually planning to find a way of generating SuperShapes in QC (assuming someone doesn’t beat me to it, of course). That means either in GLSL, or as a custom plugin (which might actually be easier, given the OpenGL code itself is already available). I know a few people who may be able to help with the 3D maths, so it’s not a complete pipedream…


Iterated GLSL Patches

I didn’t think it was possible to use multiple GLSL shaders in Quartz Composer. Turns out it is… kind of.
If you render each shader into an Image, you can use as many of them as you like (or as your computer can cope with).
It also turns out it’s possible to use them inside an Iterator this way too, as long as you Render In Image with each iteration.

This example uses a very basic GLSL shader inside a Render In Image patch, inside an Iterator. Each iteration is fed a different color value, that is multiplied by the color from the iSight input. Very unexciting effect, but good to know it can be done.

Iterated GLSL patches


February 2008


Blog Stats

  • 493,214 hits