Archive for July, 2009

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
10
Jul
09

Volumetric Light-Scattering Post-Process

Half-hour project, from GPU Gems 3.

It’s not a very realistic effect, since the actual lighting on the cubes comes from the front, whereas the big sun thing is behind them. Also, sometimes rays from further-back cubes actually sometimes appear on top of the frontmost cubes, which spoils the illusion a little. There are ways around this, but they require rendering the same geometry multiple times, which isn’t really possible to do efficiently in QC.

EDIT:
It’s just occurred to me that; of course the lightrays shouldn’t be picking up colour from the the foreground objects. I guess it will be necessary to render more than once, afterall. I’d need a pass where the foreground objects are black, then I render the light rays from the sun, then additively blend in the lit foreground objects on top.
What I’ve got at the moment is essentially just a zoom blur.
Doh..!

06
Jul
09

More Raycaster Screenshots

First 7 screenshots show Chladni surfaces

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.




Twitter

July 2009
M T W T F S S
« Jun   Sep »
 12345
6789101112
13141516171819
20212223242526
2728293031  

Links

Blog Stats

  • 474,654 hits