Archive for May, 2009

27
May
09

CIBarsSwipe Glitch Updated Code

Here’s an even simpler version of the same thing, just using one image input. The result looks pretty-much the same.

/*
Glitch effect exploiting the CoreImage Bars Swipe transition effect.
toneburst 2009
*/

function __image main(__image Image, __number Threshold) {
// Input image width
var width = Image.extent.width;
// Init output image
var outImg;

if(Math.random() < Threshold) { // Glitch Pass 1 var Angle = (Math.random() < 0.5) ? 0 : 1.57; var Width = Math.random() * width; var BarOffset = Math.random() * 100; var Time = Math.random() * 0.25; var outImg = Filter.CIBarsSwipeTransition(Image, Image, Angle, Width, BarOffset, Time); } else if (Math.random() < Threshold) { // Glitch Pass 2 var Angle = (Math.random() < 0.5) ? 1.57 : 0; var Width = Math.random() * width; var BarOffset = Math.random() * 100; var Time = Math.random() * 0.25; outImg = Filter.CIBarsSwipeTransition(outImg, Image, Angle, Width, BarOffset, Time); } else { outImg = Image; } // Return output image return outImg; }[/code]

26
May
09

Glitches With CIBarsSwipe Effect

Check the ‘Edit Filter Function’ option on a CoreImage Filter patch, and paste the following into the JavaScript panel:

/*
Glitch effect using the Apple CIBarsSwipeTransition effect.
*/

function __image main(__image Image0, __image Image1, __number Threshold) {

var outImg;
Threshold = 1 – Threshold;

if(Math.random() > Threshold) {
var Angle = (Math.random() < 0.5) ? 0 : 1.57; var Width = Math.random() * Image0.extent.width; var BarOffset = Math.random() * 100; var Time = Math.random() * 0.25; var outImg = Filter.CIBarsSwipeTransition(Image0, Image1, Angle, Width, BarOffset, Time); var Angle = (Math.random() < 0.5) ? 1.57 : 0; var Width = Math.random() * Image0.extent.width; var BarOffset = Math.random() * 100; var Time = Math.random() * 0.25; outImg = Filter.CIBarsSwipeTransition(outImg, Image1, Angle, Width, BarOffset, Time); } else { outImg = Image0; } // Return output image return outImg; }[/code] Feed in 2 different inputs, or time-delayed (via Queue patch) version of same image. Instant glitch! Threshold value should be between 0 and 1, and determines likelihood of any given frame glitching, with higher values making it less likely the current frame will pass through unscathed. Note, this could all be done with QC's builtin patches, since BarsSwipe Transition is a standard patch, but I liked the idea of doing it all in one neat little CIFilter.

26
May
09

NVIDIA Post Star Filter

CoreImage Filter conversion of NVIDIA ‘Post Star Filter’ shader, from the NVIDIA Shader Library.

Works nicely on stars (or I guess anything with bright points on a dark background), not so impressive on other material (where it tends to look like a cheap bloom filter).

Here’s an example:
NVIDIA Post Star Filter Example
Original image on left, filter applied on right.

And the Code:
CIFilter:

/*
	Post-process Star Filter.
	Code from NVIDIA Shader Library
	http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html

	Quartz Composer conversion
	toneburst 2009
*/

// Tap weighs
const float wt0 = 1.0;
const float wt1 = 0.8;
const float wt2 = 0.6;
const float wt3 = 0.4;
const float wt4 = 0.2;
const float wtNorm = (wt0 + 2.0 * (wt1 + wt2 + wt3 + wt4));

// X-Pass (Horizontal blur)
kernel vec4 blurX(sampler Image, float Offset)
{
	// Tap offsets for horizontal (x-axis) blur
	const vec2 tx0 = vec2(Offset, 0.0);
	const vec2 tx1 = vec2(Offset * 2.0, 0.0);
	const vec2 tx2 = vec2(Offset * 3.0, 0.0);
	const vec2 tx3 = vec2(Offset * 4.0, 0.0);
	//const vec2 tx4 = vec2(0.0, 0.0);
	const vec2 tx5 = vec2(-Offset, 0.0);
	const vec2 tx6 = vec2(-Offset * 2.0, 0.0);
	const vec2 tx7 = vec2(-Offset * 3.0, 0.0);
	const vec2 tx8 = vec2(-Offset * 4.0, 0.0);
	
	// Init output color
	vec4 outPix = sample(Image, samplerCoord(Image) + tx0) * (wt1 / wtNorm);
	// Sample other taps and accumulate color
	outPix += sample(Image, samplerCoord(Image) + tx1) * (wt2 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + tx2) * (wt3 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + tx3) * (wt4 / wtNorm);
	outPix += sample(Image, samplerCoord(Image)) * (wt0 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + tx5) * (wt1 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + tx6) * (wt2 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + tx7) * (wt3 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + tx8) * (wt3 / wtNorm);
	
	// Return blurred pixel
	return outPix;
}

// Y-Pass (Vertical blur)
kernel vec4 blurY(sampler Image, float Offset)
{
	// Tap offsets for vertical (y-axis) blur
	const vec2 ty0 = vec2(0.0, Offset);
	const vec2 ty1 = vec2(0.0, Offset * 2.0);
	const vec2 ty2 = vec2(0.0, Offset * 3.0);
	const vec2 ty3 = vec2(0.0, Offset * 4.0);
	//const vec2 ty4 = vec2(0.0, 0.0);
	const vec2 ty5 = vec2(0.0, -Offset);
	const vec2 ty6 = vec2(0.0, -Offset * 2.0);
	const vec2 ty7 = vec2(0.0, -Offset * 3.0);
	const vec2 ty8 = vec2(0.0, -Offset * 4.0);

	// Init output color
	vec4 outPix = sample(Image, samplerCoord(Image) + ty0) * (wt1 / wtNorm);
	// Sample other taps and accumulate color
	outPix += sample(Image, samplerCoord(Image) + ty1) * (wt2 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + ty2) * (wt3 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + ty3) * (wt4 / wtNorm);
	outPix += sample(Image, samplerCoord(Image)) * (wt0 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + ty5) * (wt1 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + ty6) * (wt2 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + ty7) * (wt3 / wtNorm);
	outPix += sample(Image, samplerCoord(Image) + ty8) * (wt3 / wtNorm);
	
	// Return blurred pixel
	return outPix;
}

// Composite pass
kernel vec4 compBlur(sampler Image, sampler HPass, sampler VPass, float StarBright)
{
	vec4 img		= sample(Image, samplerCoord(Image));
	vec4 hBlur	= sample(HPass, samplerCoord(HPass));
	vec4 vBlur	= sample(VPass, samplerCoord(VPass));
	
	// Return composited images
	return img + StarBright * (hBlur + vBlur);
}

..and the JavaScript from the CIFilter patch bottom panel (with ‘Edit Filter Function’ option enabled):

/*
	NVIDIA Post Star Filter blur and composite passes.
*/

function __image main(__image Image, __number BlurAmt, __number BlurSize) {
	// Scale blur size
	BlurSize *= 10;
	// X-Pass
	var xBlurred = blurX.apply(Image.definition, null, Image, BlurSize);
	// Y-Pass
	var yBlurred = blurY.apply(Image.definition, null, Image, BlurSize);
	// Composite
	compBlurred = compBlur.apply(Image.definition, null, Image, xBlurred, yBlurred, BlurAmt);
	// Output
	return compBlurred;
}

VDMX version of filter in Box.net widget, name
‘tb_nvStarFilter_1.0.qtz’

22
May
09

Texture-Lookup-Deform By 2-Point Bezier-Curve

Same Bezier Curve formula applied in CIFilter to deforming texture-lookup X and Y coordinates.

22
May
09

2-Point Bezier Curve

Inspired by a query from 2bitpunk, I decided yesterday to have another go at Bezier curves.

I’ve looked at this in the past, and have always been really confused by the maths, or found sourcecode, but been unable to separate-out the relevant maths from the rest of the code. Yesterday though, I stumbled on this page, which had the necessary equation without a load of confusing explanation, that, with my mathematical myopia, I wouldn’t stand a cat’s chance in hell of understanding (as the phrase goes).

Soo… after an hour or so of swearing at QC’s buggy JavaScript module, I managed to put together a simple 2-point Bezier demo. Ironically, in the end, it was the dragging-control-points bit that took the most hair-tearing to implement. My eventual solution to that problem wasn’t ideal, but was functional, at least.

Here’s the JS code to generate a Bezier Curve with a settable number of steps, taking as input 4 2D points (2 anchor-points, 2 control-points/handles) and outputting a structure of points in 3D space descibing the resulting curve. There’s also a chunk of code to output a second structure containing the coordinates of the anchor and control-points, so you can see where they are:

/*
	Bezier curve between 2 points, with 2 control-points.
	http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm
*/

function bezier(A, B, D, C, t)
{
	// Note I've reversed the order of C and D so that
	// anchor and control-points are in more intuitive order
	var a = t;
	var b = 1 - t;
	
	var out=	A * Math.pow(b, 3) +
			3 * B * Math.pow(b, 2) * a +
			3 * C * b * Math.pow(a, 2) +
			D * Math.pow(a, 3);
	
	return out;
}

function (__structure Points_Struct, __structure Controlpoints_Struct)
			main
		(__number P0_X, __number P0_Y,
		 __number P1_X, __number P1_Y,
		 __number P2_X, __number P2_Y,
		 __number P3_X, __number P3_Y,
		 __index Steps)
{
	if(!_testMode) {
		/*
			P0 is first anchorpoint, P1 first controlpoint
			P2 is second anchorpoint, P3 second controlpoint
			(see note in bezier function) 
		*/
	
		// Init output arrays
		var points = new Array();
		var controlpoints = new Array();
		
		// Time-increment amount
		var stepSize = 1 / Steps;
		
		// Curve with steps segments
		for(i = 0; i <= Steps; i++) {
			var thisPoint = new Object();
			t = stepSize * i;
			thisPoint.X = bezier(P0_X, P1_X, P2_X, P3_X, t);
			thisPoint.Y = bezier(P0_Y, P1_Y, P2_Y, P3_Y, t);
			thisPoint.Z = 0;
		
			points[i] = thisPoint;
		}
		
		// Control-points
		var thisControlpoint = new Object();
		thisControlpoint.X = P0_X;
		thisControlpoint.Y = P0_Y;
		thisControlpoint.Z = 0;
		controlpoints[0] = thisControlpoint;
		var thisControlpoint = new Object();
		thisControlpoint.X = P1_X;
		thisControlpoint.Y = P1_Y;
		thisControlpoint.Z = 0;
		controlpoints[1] = thisControlpoint;
		var thisControlpoint = new Object();
		thisControlpoint.X = P2_X;
		thisControlpoint.Y = P2_Y;
		thisControlpoint.Z = 0;
		controlpoints[2] = thisControlpoint;
		var thisControlpoint = new Object();
		thisControlpoint.X = P3_X;
		thisControlpoint.Y = P3_Y;
		thisControlpoint.Z = 0;
		controlpoints[3] = thisControlpoint;

		// Output
		var result = new Object();
		result.Points_Struct = points;
		result.Controlpoints_Struct = controlpoints;
		return result;
	}
}

It would be easy to extend the curve into 3D space by simply passing the Z-coords to the Bezier function too, rather than just setting Z to a constant.

Example video clip:

I think my mistake in the past has been to try and implement Bezier curve-drawing in a fragment shader/CIFilter, whereas it’s much easier to simple generate a load of points, and then draw them using 3D geometry.

EDIT:
Check out this lovely piece for work by Jeogho Park, using the above bezier JavaScript code.

22
May
09

Plane-Deformation By Lookup-Table

Inspired by this page on Inigo Quilez’ website, I decided to try the same thing in Quartz Composer.

The basic idea is, you find some interesting formula to deform a 2D plane in some way, then write that formula into a 2D lookup-table. Then, you use that LUT to generate texture coordinates to render a second image. As Inigo says, you can do the whole thing in a single pixel/fragment shader now, but I thought I’d try it this way, anyway.

In the example clip below, I’m passing in an image of a blurry circle, made using a simple smoothstep function, and adjusting the parameters while I swap the LUT, and apply animation to the deformation.

The whole thing is done in two CoreImage filters, one for the base image, and one to generate the LUT and apply the deformation.

Apparently, this is a 90’s demoscene staple. I wasn’t involved with realtime graphics then, so it’s new and exciting to me..!

Here are some examples of the same effect applied to the iSight input:

With a less blurry base image, you can see some quite nasty aliasing. The effect could do with some kind of adaptive antialiasing, but I’m not quite sure how to go about that, to be honest. Mind you, it’s an old-school effect, so maybe it’s OK if it’s a bit rough around the edges (literally, in fact)…

QTZ is in the Box.net widget.
‘tb_Plane-DeformLUT.qtz’

With thanks to Inigo Quilez.

12
May
09

Taking a Random Walk

Inspired by this video by Simon Geilfus (which sadly hasn’t fared well with Vimeo’s compression-method), I decided to try something similar in Quartz Composer.

The basic idea, as outlined in Simon’s post, is very simple:
1. Place a point in 3D space
2. Take the position of the previous point, and add a small random offset on the X, Y and Z axes
3. Create a new point at the coordinates thus generated
4. Repeat, offsetting each new point from the coordinates of the last point.

Here’s some JavaScript:

/*
3D Random-Walk experiment, inspired by Simon Geilfus’ video at
http://vimeo.com/4491896

– PointsStruct –
output should be connected to Kineme GL Tools
Point/Quad/Triange Structure patches.

– LastX/Y/Z –
conect to GL Look At Center inputs (with smoothing)
so camera appears to follow point-drawing.

– dummy –
input fed from Patch Time to force updating every frame.

toneburst 2009
*/

// Init array to hold points
var points = new Array();

// Init object to hold initial point
var p = new Object();
p.X = 0;
p.Y = 0;
p.Z = 0;
p.R = 0;
p.G = 0;
p.B = 0;

// Add point to array
points[0] = p;

// Init Frame/Iteration-counter variable
var frames = 1;

function (__structure PointsStruct,
__number LastX, __number LastY, __number LastZ,
__string NumPoints)
main
(__boolean Draw, __index MaxPoints, __number StepSize,
__number dummy)
{
if(!_testMode && Draw) {

// Fetch previous point from array
var previousPoint = points[frames – 1];

// Init temp Object variable to hold new point
var tmpP = new Object();

// Random 3D position based on offset from last point
tmpP.X = previousPoint.X + StepSize * (Math.random() – 0.5);
tmpP.Y = previousPoint.Y + StepSize * (Math.random() – 0.5);
tmpP.Z = previousPoint.Z + StepSize * (Math.random() – 0.5);
// Random RGB values (only works for Triangles and Quads)
tmpP.R = Math.random();
tmpP.G = Math.random();
tmpP.B = Math.random();

// Add point to array at index set by frames variable
points[frames] = tmpP;

// Increment frame-counter and reset frame-counter if MaxPoints exceeded.
// Reset to 1 rather than 0 so that previous point
// can be fetched from points array index 0 after reset
frames += 1;
frames = (frames < MaxPoints) ? frames : 1; // Init output object var result = new Object(); // Assign Points array to output object // (JavaScript array converted to QCStructure on output) result.PointsStruct = points; // Last point coordinates (for camera control) result.LastX = points[frames - 1].X; result.LastY = points[frames - 1].Y; result.LastZ = points[frames - 1].Z; // Number of iterations (for debugging) result.NumPoints = frames + " iterations"; // Output values return result; } }[/code] The key to rendering the data is the Kineme GL Tools Point/Line/Triangle/Quad Structure plugins, which takes a simple array of 3D points (and optionally colours, for the Triangle and Quad versions), and create 3D primitives from them. I've also added a stock fog effect to increase the sense of depth, and placed all the rendered objects inside a Kineme GL Tools Look At patch, which effectively makes the camera appear to follow the points as they are drawn. [vimeo 4607256] and another variation. [vimeo 4626625] This time, only complete triangles are drawn, and a Queue patch is used to keep track of the points (speeding things up quite a lot). and another [vimeo 4636184] in which I mess around with a GLSL fake depth-of-field effect on a set of point-sprites.




Twitter

May 2009
M T W T F S S
« Apr   Jun »
 123
45678910
11121314151617
18192021222324
25262728293031

Links

Blog Stats

  • 470,218 hits