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…

Advertisements
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:
Added ‘tb_borg2D_1.0.qtz’ to Box.net download widget.

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.
	Adjustable displacement amount.
	
	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
	on gradient RGB values.
	
	toneburst 2009
*/

function __image main(__image Image, __boolean Trigger, __number DisplaceAmt) {
	
	if(Trigger) {
		var dims = new Vec(Image.extent.width,Image.extent.height);
		var gradDims = new Vec(0,0,dims.x,dims.y);
	
		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);
	
		var gradR = Filter.CILinearGradient(p0, p1, black, white);
		gradR = Filter.CICrop(gradR, gradDims);

		p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
		p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
	
		var gradG = Filter.CILinearGradient(p0, p1, black, white);
		gradG = Filter.CICrop(gradG, gradDims);
	
		p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
		p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
	
		var gradB = Filter.CILinearGradient(p0, p1, black, white);
		gradB = Filter.CICrop(gradB, gradDims);
	
		var gradRGB = tb_combineChannels.apply(gradR.definition, null, gradR, gradG, gradB);

		// Call kernel function and return result
		return tb_displace.apply(gradRGB.definition,null,Image,gradRGB,DisplaceAmt);
	} else {
		return Image;
	}
}
17
Jun
09

Random Gradients Variation

///////////////////////
// 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; 
  
    return vec4(vec3(shade), 1.0);  
}

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

function __image main(__boolean Trigger, __index Type) {  
  
    var dims = new Vec(256,256);  
    var gradDims = new Vec(0,0,dims.x,dims.y);  
  
    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);  
  
    var gradR = Filter.CILinearGradient(p0, p1, black, white);  
    gradR = Filter.CICrop(gradR, gradDims);  
  
    p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);  
    p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);  
  
    var gradG = Filter.CILinearGradient(p0, p1, black, white);  
    gradG = Filter.CICrop(gradG, gradDims);  
  
    p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);  
    p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);  
  
    var gradB = Filter.CILinearGradient(p0, p1, black, white);  
    gradB = Filter.CICrop(gradB, gradDims);  
  
    switch (Type) {
    case 0:
    		// Call kernel function and return result  
    		return combineChannels.apply(gradR.definition, null, gradR, gradG, gradB);
    		break;
    	case 1:
    		return multiplyChannels.apply(gradR.definition, null, gradR, gradG, gradB);
    		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.
Download it if you think you’ll find it useful…
‘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

Random Gradient CIFilter JavaScript

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 gradDims = new Vec(0,0,dims.x,dims.y);
	
	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);
	
	var gradR = Filter.CILinearGradient(p0, p1, black, white);
	gradR = Filter.CICrop(gradR, gradDims);

	p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
	p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
	
	var gradG = Filter.CILinearGradient(p0, p1, black, white);
	gradG = Filter.CICrop(gradG, gradDims);
	
	p0 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
	p1 = new Vec(Math.random() * dims.x, Math.random() * dims.y);
	
	var gradB = Filter.CILinearGradient(p0, p1, black, white);
	gradB = Filter.CICrop(gradB, gradDims);
	
	
	// Call kernel function and return result
	return combineChannels.apply(gradR.definition, null, gradR, gradG, gradB);
}



Twitter

November 2017
M T W T F S S
« Aug    
 12345
6789101112
13141516171819
20212223242526
27282930  

Links

Blog Stats

  • 475,892 hits