## Archive for the 'CIFilter Code' Category

10
Jul
09

### Volumetric Light Scattering Attempt 2

This attempt is slightly better.
I’ve implemented the shader as a Core Image Filter this time, mainly to make it easier to do the various compositing operations necessary.

I’m still not particularly pleased with it, to be honest. Maybe it just needs something more interesting than 3 cubes…

02
Jul
09

### Borg 2D Polar Mapping

This is the Borg equation with polar coordinates.

Here’s the CIFilter Kernel code for cartesian and polar versions (I’ll let you work out sensible ranges for the various controls):

```/*
Borg equation in cartesian and polar varieties.
From 3D surface equation found here:
http://local.wasp.uwa.edu.au/~pbourke/geometry/borg/

Quartz Composer setup
toneburst 2009
https://machinesdontcare.wordpress.com
*/

kernel vec4 tb_borg_cartesian(sampler Image, vec2 NormFactor, float Z, vec2 Scale, vec2 Offset)
{
// Normalised coords of current pixel
vec2 xyNorm = samplerCoord(Image) * NormFactor;
xyNorm -= 0.5;
xyNorm *= Scale;
xyNorm += Offset;

float borg = sin(xyNorm.x * xyNorm.y) + sin(xyNorm.y * Z) + sin(Z * xyNorm.x);

// Sample image and return pixel
return vec4(vec3(1.0), borg);
}

kernel vec4 tb_borg_polar(sampler Image, vec2 NormFactor, float Phi, vec2 Scale, vec2 Offset)
{
// Normalised coords of current pixel
vec2 xyNorm = samplerCoord(Image) * NormFactor;
xyNorm -= 0.5;
xyNorm = abs(xyNorm);

// Cartesian to polar
vec2 polar;
polar[0] = length(xyNorm);				// R
polar[1] = atan(xyNorm.x/xyNorm.y);		// Theta

polar *= Scale;
polar += Offset;

float borg = sin(polar[0] * polar[1]) + sin(polar[1] * Phi) + sin(Phi * polar[0]);

// Sample image and return pixel
return vec4(vec3(1.0), borg);
}```

UPDATE:

01
Jul
09

### More Moiré Screenshots

Moiré variations.

01
Jul
09

### Interesting Moiré Error

I was just experimenting with a moiré pattern Core Image filter, and made a little mistake in my code, with interesting results.

The basic idea was to try and emulate the interference patterns you get when you try to video something like an LCD screen, closeup, and at a slight angle.

I thought I could do this by using CoreImage StripesGenerator to create a base image, then applying slightly different PerspectiveTransforms to two copies of the image, then compositing them back together again. It seems to work pretty well.

I’ve done the whole thing using JavaScript in a Core Image Filter patch, though it could also be done using standard Quartz Composer patches and noodling them together.

I stumbled on the effect above when I tried to increase the size of the base image, while leaving the dimensions of the Crop filter the same. This seems to force extra interpolation, which smoothes out the lines, creating the gradients you can see in the screenshots above.

Here’s the code to create the effect above:

```/*
Moiré effects using CIStripes and Perspective Transform filters.

toneburst 2009
https://machinesdontcare.wordpress.com
*/

function __image main(__boolean Trigger) {

var black = new Vec(0,0,0,1);
var white = new Vec(1,1,1,1);
var center = new Vec(128,128);
var dims = new Vec(0,0,1024,1024);
var stripes = Filter.CIStripesGenerator(center,black,white,1,1);

var rotate90 = new AffineTransform().rotateByDegrees(90);
stripes = Filter.affineTransform(stripes,rotate90);

stripes = Filter.CICrop(stripes,dims);

var offset = 2;
tl0 = new Vec(0 - Math.random() * offset, 256 - Math.random() * offset);
tr0 = new Vec(256 - Math.random() * offset, 255 - Math.random() * offset);
br0 = new Vec(256 - Math.random() * offset, 0 - Math.random() * offset);
bl0 = new Vec(0 - Math.random() * offset, 0 - Math.random() * offset);
var stripesP_0 = Filter.CIPerspectiveTransform(stripes,tl0,tr0,br0,bl0);

tl1 = new Vec(0 + Math.random() * offset, 256 + Math.random() * offset);
tr1 = new Vec(256 + Math.random() * offset, 256 + Math.random() * offset);
br1 = new Vec(256 + Math.random() * offset, 0 + Math.random() * offset);
bl1 = new Vec(0 + Math.random() * offset, 0 + Math.random() * offset);
var stripesP_1 = Filter.CIPerspectiveTransform(stripes,tl1,tr1,br1,bl1);

var moiré = Filter.CIDarkenBlendMode(stripesP_0,stripesP_1);

return moiré;
}```

The single input ‘Trigger’ causes a new pattern to be generated whenever it changes state (from off to on or vice-versa).

To get a more standard moiré effect, replace the line

var dims = new Vec(0,0,1024,1024);
with
var dims = new Vec(0,0,256,256);

There’s probably mileage in rejigging the code to do something a bit more subtle than just making a random pattern every time the button is pushed.

25
Jun
09

### Random Gradient Displace CIFilter Code

Jiggles image around based on random greyscale gradients.

CIFilter code (top panel with ‘Edit Filter Function’ enabled):

```/*
Combine channels of 3 monochrome input images.
R-channel from ImageR
G-channel from ImageG
B-channel from ImageB

toneburst 2009
*/

kernel vec4 tb_combineChannels(sampler ImageR, sampler ImageG, sampler ImageB)
{
float R = sample(ImageR, samplerCoord(ImageR)).r;
float G = sample(ImageG, samplerCoord(ImageG)).r;
float B = sample(ImageB, samplerCoord(ImageB)).r;

return vec4(R, G, B, 1.0);
}

/*
Displace Image input pixels based on RGB values of DisplaceImg.

toneburst 2009
*/

kernel vec4 tb_displace(sampler Image, sampler DisplaceImg, float DisplaceAmt)
{
vec4 dImg = sample(DisplaceImg, samplerCoord(DisplaceImg));
vec2 dAmt = (dImg.rg * 2.0 - 1.0) * DisplaceAmt;
return sample(Image, samplerCoord(Image) + dAmt);
}```

JavaScript (bottom panel):

```/*
Creates random gradient in RGB channels.
whenever 'Trigger' pressed and displaces input image based

toneburst 2009
*/

function __image main(__image Image, __boolean Trigger, __number DisplaceAmt) {

if(Trigger) {
var dims = new Vec(Image.extent.width,Image.extent.height);

var black = new Vec(0,0,0,1);
var white = new Vec(1,1,1,1);

var p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
var p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

// Call kernel function and return result
} else {
return Image;
}
}```
17
Jun
09

```///////////////////////
// CIFilter Kernel Code
///////////////////////

kernel vec4 combineChannels(sampler ImageR, sampler ImageG, sampler ImageB)
{
float R = sample(ImageR, samplerCoord(ImageR)).r;
float G = sample(ImageG, samplerCoord(ImageG)).r;
float B = sample(ImageB, samplerCoord(ImageB)).r;

return vec4(R, G, B, 1.0);
}

kernel vec4 multiplyChannels(sampler ImageR, sampler ImageG, sampler ImageB)
{
float R = sample(ImageR, samplerCoord(ImageR)).r;
float G = sample(ImageG, samplerCoord(ImageG)).r;
float B = sample(ImageB, samplerCoord(ImageB)).r;
float shade = R * G * B;

}

///////////////////
// JavaScript
///////////////////

function __image main(__boolean Trigger, __index Type) {

var dims = new Vec(256,256);

var black = new Vec(0,0,0,1);
var white = new Vec(1,1,1,1);

var p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
var p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

switch (Type) {
case 0:
// Call kernel function and return result
break;
case 1:
break;
}
}```

Makes greyscale triangles and squares.

EDIT:
Just uploaded a QTZ with three variations on the basic random gradients theme, all in one CIFilter patch.
‘tb_randomGradients_1.0.qtz’ in the box.net widget on right.

And here’s a clip of it in action, courtesy of Lee Grosbauer:

Cheers, Lee!

16
Jun
09

Creates linear gradients between two random points across RGB channels every time ‘Trigger’ is clicked.

CIFilter Kernel Code (top panel)

```kernel vec4 combineChannels(sampler ImageR, sampler ImageG, sampler ImageB)
{
float R = sample(ImageR, samplerCoord(ImageR)).r;
float G = sample(ImageG, samplerCoord(ImageG)).r;
float B = sample(ImageB, samplerCoord(ImageB)).r;

return vec4(R, G, B, 1.0);
}```

Javascript (bottom panel)

```function __image main(__boolean Trigger) {

var dims = new Vec(256,256);

var black = new Vec(0,0,0,1);
var white = new Vec(1,1,1,1);

var p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
var p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);

// Call kernel function and return result