Archive for the 'Quartz Composer' Category


Adaptive Tiling Remake

Following a request for the Adaptive Tiling composition mentioned in a previous post from 2012, I spend a fruitless hour or so trying to track down the file. So I decided to try and recreate the setup, based on an iterative Core Image Filter.

It’s a long time since I did any Quartz Composer work, and I can’t remember exactly how I did it last time, so I don’t know if the remade version is as efficient as the original, but it does seem to work.

Here’s the Dropbox link to the file.

As usual, you’re welcome to do whatever you want with it, but some form of credit would be nice if you use it as part of your own work (especially if it’s used commercially). Drop me a message and let me know what you did with it, if you do find it useful.

This composition uses a builtin camera, but could easily to adapted into a plugin for VDMX or other realtime video applications.


Voronoi 2

Just a quick test of a simple voronoi pattern generator. Nothing ground-breaking, just thought I’d try it in QC.

Incidentally, I’ve messed around with a voronoi shader in the past. This is a different method, and is a bit of a cheat. Essentially, all you do is create a load of cones, at random positions, pointy end pointing out at you. the lines where the cones intersect define the edge of each cell. In this case, I’ve mapped a gradient onto the cone (which is actually a cylinder primitive, with the top diameter set to 0), for tonal variation.

The only problem with this method is that the perspective effect distorts the pattern.


Adaptive Tiling

It’s a lonnnnnnng time since I did anything in QC, so I thought I’d try and keep my hand in a bit, by doing something really simple.

As usual, it didn’t turn out to do quite as simple as I thought it would, in the end, but it looks very simple 😉

It’s basically just a 2D tiling effect, but works iteratively, so brighter areas of the image are subdivided into small tiles.

Uses a JavaScript loop inside a Core Image Kernel. I don’t know what the latest state-of-play is with JavaScript in CIFilter patches. There used to be memory leaks. Dunno if this is still the case.


Toneburst In The Wild

I’ve been doing some work over the past year or so for Nicky Smith, AKA wierdcore, who, among many other things, is in charge of visuals for Aphex Twin’s live shows. Here’s some examples of some of my QC work in use.

Note: not all the QC work in these clips with carried out by me. You might recognise a few things from earlier posts here though.


Gray-Scott Reaction-Diffusion Test

Test of Gray-Scott reaction-diffusion pattern generator, implemented in a Core Image Filter kernel in Quartz Composer.

This version is much more controllable than my previous RD experiments, but still capable of producing some interesting patterns.

I’m planning to add some more performance-orientated controls for warping and realtime editing, also for seeding the effect with live input image and/or adding masks so that different patterns can be generated in different areas. None of which is particularly original (there are examples or similar setups all over YouTube), but I’ve not seem it done in QC before.


VasaRiley Belated Release

I’ve been tied up with other things lately, but finally got around to releasing the VasaRiley qcFX for VDMX I made for Weirdcore last year. I’d hoped to find time to do a quick demo video, and put together some documentation of the controls (since it’s quite complex), but haven’t had time, with other projects etc., unfortunately.

‘tb_VasaRiley_1.0.qtz’ in the widget, anyway.


RGB Feedback

Feedback with slightly different values for RGB channels.


Non-Marching Squares

I has looking into Marching cube algorithms for extracting meshes from volume data yesterday, and thought, as a little test, I’d try making a very simple 2D edge-detection type setup, using some of the same principles. There’s lots of stuff on the web about marching cubes, and the 2D version, marching squares, so I’m not going to go into a detailed explanation here, but to summarise my setup:

• divide the image into tiles
• for each tile, test to see if the colour/luminosity value pixel at each corner is above or below a given threshold value.
• use the results of these tests to lookup into a table.
In my case, this table is an image strip something like this (I’ve added the numbers for debugging purposes)

In the original Marching Cubes code, the logic for choosing the correct cell from the table is quite elegant. You basically create a binary number, where each digit is either a 0 or a 1, according to whether the corresponding grid-point value is above or below the threshold. Decoding the binary into an integer gives you the index into the table. Unfortunately, because GLSL doesn’t have support for binary numbers, I’ve had to kludge that a bit, but it works fine.
• draw the selected table cell into the working tile of the input image

Here’s some results.

It’s a bit glitchy around the edges of the tiles, but I’m quite pleased with it. I’ve added some controls to recolour the tiles in various ways, and to deliberately scan the corners in the wrong order, for a more abstract look.

I call this ‘non-marching cubes’ because I’m not really doing the marching bit. Variations on this technique are often used iteratively to detect, and then follow edges in an image. Tools like the Magic Wand in Photoshop use similar techniques to create selections based on colour values, for example.

Vertex Shader code for the simple black-and-white version:

uniform float CellCount;
varying vec2 cellCoords;

void main()
	//Transform vertex by modelview and projection matrices
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
	//Forward current color and texture coordinates after applying texture matrix
	gl_FrontColor = gl_Color;
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
	cellCoords = gl_TexCoord[0].xy * CellCount;

..and the Fragment Shader:

uniform sampler2D Texture, EdgeTable;
uniform vec2 CellSize;
uniform float Threshold;
uniform int Scramble;
uniform vec2 ClampAmt;  // Values for clamping edges
varying vec2 cellCoords;
const float eTableCellWidth = 1.0 / 16.0;

void main()
	// Cell corners (putting in vec4 allows swizzling for different tile patterns)
	vec4 corners;
	corners[0] = max(floor(cellCoords.x) * CellSize.x, ClampAmt[0]);       // Left
	corners[1] = min(ceil(cellCoords.x) *CellSize.x, 1.0 - ClampAmt[0]);   // Right
	corners[2] = max(floor(cellCoords.y) * CellSize.y, ClampAmt[0]);       // Top
	corners[3] = min(ceil(cellCoords.y) * CellSize.y, 1.0 - ClampAmt[0]);  // Bottom
	// Swizzle corners for different effects
	corners = (Scramble == 1) ? corners.xywz : (Scramble == 2) ? corners.yxzw : (Scramble == 3) ? corners.zwyx : corners;

	// Sample corners	
	float c0	= texture2D(Texture, vec2(corners[0], corners[2])).r;
	float c1 	= texture2D(Texture, vec2(corners[1], corners[2])).r;
	float c2 	= texture2D(Texture, vec2(corners[0], corners[3])).r;
	float c3 	= texture2D(Texture, vec2(corners[1], corners[3])).r;
	// Clamp coords for edge-table
	vec2 cellCoordsClamp = fract(cellCoords);
	cellCoordsClamp.x = clamp(cellCoordsClamp.x, ClampAmt[1], 1.0 - ClampAmt[1]); 
	cellCoordsClamp.y = clamp(cellCoordsClamp.y,ClampAmt[1], 1.0 - ClampAmt[1]);
	// Calculate index for edge-table
	// Returns 0.0 > 15.0 to index into edge-table strip
	float index = 0.0;
	index += step(Threshold, c0);
	index += step(Threshold, c1) * 2.0;
	index += step(Threshold, c2) * 4.0;
	index += step(Threshold, c3) * 8.0;
	// Sample edge-table and return
	vec2 ttcoords	= vec2(cellCoordsClamp.x * eTableCellWidth + (eTableCellWidth * index), cellCoordsClamp.y);
	gl_FragColor = texture2D(EdgeTable, ttcoords);

Cube, Cylinder, Line Field qcFX Updated

Updated versions of some of my very early QC experiments, but this time using OpenCL instead of the Image Pixel patch, which speeds things up quite a lot. It should fall back to using Image Pixel if OpenCL isn’t available, but I’ve not been able to test that, as I no longer have a non-OpenCL-capable machine.

‘tb Field qcFX’ in the Widget.


tb Pleasure Division

Coming soon.


July 2020


Blog Stats

  • 493,214 hits