Archive for October, 2008

29
Oct
08

Subsurface Scatter Shader

GLSL translation of this fake sub-surface scattering shader by InvalidPointer.

I’m always amazed when these things actually work…

Vertex Shader:

////////////////////////////
// SUB-SURFACE SCATTER VS //
////////////////////////////

/* --------------------------
SubScatter Vertex Shader:

Fake sub-surface scatter lighting shader by InvalidPointer 2008.
Found at
http://www.gamedev.net/community/forums/topic.asp?topic_id=481494

HLSL > GLSL translation
toneburst 2008
-------------------------- */

// Set light-position
uniform vec3 LightPosition;

// Varying variables to be sent to Fragment Shader
varying vec3 worldNormal, eyeVec, lightVec, vertPos, lightPos;

void subScatterVS(in vec4 ecVert)
{
	lightVec = LightPosition - ecVert.xyz;
	eyeVec = -ecVert.xyz;
	vertPos = ecVert.xyz;
	lightPos = LightPosition;
}

////////////////
//  MAIN LOOP //
////////////////

void main()
{
	worldNormal = gl_NormalMatrix * gl_Normal;
	
	vec4 ecPos = gl_ModelViewProjectionMatrix * gl_Vertex;
	
	// Call function to set varyings for subscatter FS
	subScatterVS(ecPos);
	
	//Transform vertex by modelview and projection matrices
	gl_Position = ecPos;

	//Forward current texture coordinates after applying texture matrix
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}

Fragment Shader:

////////////////////////////
// SUB-SURFACE SCATTER FS //
////////////////////////////

/* --------------------------
SubScatter Fragment Shader:

Fake sub-surface scatter lighting shader by InvalidPointer 2008.
Found at
http://www.gamedev.net/community/forums/topic.asp?topic_id=481494

HLSL > GLSL translation
toneburst 2008
-------------------------- */

// Variables for lighting properties
uniform float MaterialThickness;
uniform vec3 ExtinctionCoefficient; // Will show as X Y and Z ports in QC, but actually represent RGB values.
uniform vec4 LightColor;
uniform vec4 BaseColor;
uniform vec4 SpecColor;
uniform float SpecPower;
uniform float RimScalar;
//uniform sampler2D Texture;

// Varying variables to be sent to Fragment Shader
varying vec3 worldNormal, eyeVec, lightVec, vertPos, lightPos;

float halfLambert(in vec3 vect1, in vec3 vect2)
{
	float product = dot(vect1,vect2);
	return product * 0.5 + 0.5;
}

float blinnPhongSpecular(in vec3 normalVec, in vec3 lightVec, in float specPower)
{
	vec3 halfAngle = normalize(normalVec + lightVec);
	return pow(clamp(0.0,1.0,dot(normalVec,halfAngle)),specPower);
}

// Main fake sub-surface scatter lighting function

vec4 subScatterFS()
{
	float attenuation = 10.0 * (1.0 / distance(lightPos,vertPos));
	vec3 eVec = normalize(eyeVec);
	vec3 lVec = normalize(lightVec);
	vec3 wNorm = normalize(worldNormal);
	
	vec4 dotLN = vec4(halfLambert(lVec,wNorm) * attenuation);
	//dotLN *= texture2D(Texture, gl_TexCoord[0].xy);
	dotLN *= BaseColor;
	
	vec3 indirectLightComponent = vec3(MaterialThickness * max(0.0,dot(-wNorm,lVec)));
	indirectLightComponent += MaterialThickness * halfLambert(-eVec,lVec);
	indirectLightComponent *= attenuation;
	indirectLightComponent.r *= ExtinctionCoefficient.r;
	indirectLightComponent.g *= ExtinctionCoefficient.g;
	indirectLightComponent.b *= ExtinctionCoefficient.b;
	
	vec3 rim = vec3(1.0 - max(0.0,dot(wNorm,eVec)));
	rim *= rim;
	rim *= max(0.0,dot(wNorm,lVec)) * SpecColor.rgb;
	
	vec4 finalCol = dotLN + vec4(indirectLightComponent,1.0);
	finalCol.rgb += (rim * RimScalar * attenuation * finalCol.a);
	finalCol.rgb += vec3(blinnPhongSpecular(wNorm,lVec,SpecPower) * attenuation * SpecColor * finalCol.a * 0.05);
	finalCol.rgb *= LightColor.rgb;
	
	return finalCol;	
}

////////////////
//  MAIN LOOP //
////////////////

void main()
{
	gl_FragColor = subScatterFS();
}
28
Oct
08

soundFlower Update

I realised I hadn’t spent enough time optimising the controls of my tb soundFlower qcClip, so I’m uploading an updated version. Same effect, but the control ranges make a bit more sense, and the audio-response is a bit better.

Also, I didn’t mention in my previous post that you need the excellent Kineme Audio Tools plugin to run this QTZ.

New version in the Box.net widget ‘tb soundFlower 1.01.qtz’

28
Oct
08

tb MetaImage Update (CIFilter Code)

Updated version of the Meta-Image filter I did ages ago, originally based on one of Pete Warden’s original free FreeFrame effects. This one has a couple of nice new options and the whole thing has been implemented in a single CIFilter patch, this time.

CIFilter Kernel Code:

/*
	'Meta-Image' effect.
	Original image is scaled and tiled, optionally recoloured
	by multiplication with colour of centre pixel of each tile.
	Based on original FreeFrame effect by Pete Warden.
	
	toneburst 2008
	https://machinesdontcare.wordpress.com
*/

///////////////////
//   Pre-zoom    //
///////////////////

kernel vec4 vvZoom(sampler Image, vec2 Center, float Level) 
{	
	// Based on VVZoom effect, from
	// http://www.vidvox.com/phpBB2/viewtopic.php?t=1785&highlight=vvzoom
	
	vec2 loc = destCoord();
	loc = samplerTransform(Image,loc);
	vec2 modifiedCenter = samplerTransform(Image, Center);
	loc = (loc - modifiedCenter)*(1.0/Level) + modifiedCenter;
	
	return sample(Image,loc); 
}

/////////////////////////////////////////
// Simple version, without recolouring //
/////////////////////////////////////////

kernel vec4 tbMetaImage(sampler Image, vec2 Divisor, float Mix)
{
	// Input image dimensions
	vec2 dims = samplerSize(Image);
	// Normalised coords of current pixel
	vec2 xyNorm = samplerCoord(Image) / dims;
	
	// Coords to sample tiled image
	vec2 miniImagePos = fract(xyNorm / Divisor);
	
	// Output tiled image
	return sample(Image, mix(xyNorm,miniImagePos,Mix) * dims);
}

//////////////////////
// With recolouring //
//////////////////////

kernel vec4 tbMetaImageClr(sampler Image, vec2 Divisor, float Mix)
{
	// Input image dimensions
	vec2 dims = samplerSize(Image);
	// Normalised coords of current pixel
	vec2 xyNorm = samplerCoord(Image) / dims;
	
	// Coords to sample tiled image
	vec2 miniImagePos = fract(xyNorm / Divisor);
	// Coords to sample centre pixel of each tile
	vec2 colorPos = (floor(xyNorm / Divisor) * Divisor) + 0.5 * Divisor;
	
	// Color at centre of current tile
	vec4 centreColor = sample(Image, colorPos * dims);
	// Sample scaled input image for current tile
	vec4 miniImage = sample(Image, mix(xyNorm,miniImagePos,Mix) * dims);
	
	// Output tiled image * centre color
	// mixed with original mini image color
	return mix(miniImage,miniImage * centreColor,Mix);
}

.. and the JavaScript from the bottom panel:

function __image main(__image Image, __vec2 Divisor, __number Type, __number PreZoom, __number Mix)
{
	// Scale and round control values
	Divisor.x = 1 / Math.round(Divisor.x); // Range 50 > 1, exponential-in
	Divisor.y = 1 / Math.round(Divisor.y); // Range 50 > 1, exponential-in
	
	// Pre-zoom
	center = new Vec(0.5 * Image.extent.width,0.5 * Image.extent.width);
	var zoomedImage = vvZoom.apply(Image.definition,null,Image,center,PreZoom);
	
	if(Type == 0.0) {
		return tbMetaImage.apply(zoomedImage.definition, null, zoomedImage, Divisor,Mix);
	} else if(Type == 1.0) {
		return tbMetaImageClr.apply(Image.definition, null, Image, Divisor,Mix);	}	
}

One nice new feature I’ve added is the ability to ‘mix’ between the effect and original image, but not as a simple crossfade- it’s actually mixing between the coordinates the image is sampled at, so you get this weird zooming effect.

I’ve realised I should be thinking more about making my effects start in an interesting way. Rather than just being on or off, I could have them transition in some interesting way from the original image to the effected version. Or maybe this wouldn’t be such a great idea, usability-wise. Anyone any thoughts on this?

28
Oct
08

tb SoundFlower

An audio-reactive circular oscilloscope-type thing, with feedback.
Requires Kineme Audio Tools plugin.

This is an old project resurrected. I’ve finally got around to adding the ability to choose the audio interface and channel for the effect via a little info box, overlaid on top of the output. It’s a not-particularly elegant hack, but I can’t see any other way of doing it, since you can’t populate an Index splitter with names items programmatically from inside QC (as far as I know).

tb_soundFlower.qtz in the widget.

26
Oct
08

tb Tunnel

I’ve been working on a QTZ tunnel effect, but taking a different approach to the one goto10 used for his excellent take on the theme.

Since I’ve been working a lot with GLSL, I thought I’d try writing a shader to do something similar. In fact, all the shader does, is create a bendy tube, and apply a texture to it. All the rest of the work is done with a series of CIFiltes. My brainwave, and the germ for the project, was the realisation that if I applied a frame-roll type effect to the texture on the tube and positioned it so that we were looking down the inside of the tube, I could make it look the viewer was travelling down a tunnel. Obvious, really.

I’ve added a few other controls, too, and setup the texture movement to be synced to VDMXs Measure Position.

Controls:

Rate Select:
Rate of tunnel movement, based on Measure Position.

Curve Controls:
Rate and amount of bends in tunnel

Tile Controls:
Controls for mirroring, and tiling the input image.

Live/Capture:
This is an important one.
Live Input
uses the realtime input (as you’d expect). The only problem with this is that movement in the image can conflict with the movement of the tunnel effect, making it look jerky, so I’ve added
Captured Input
Grabs a still-frame at regular intervals (set by the rate control), and uses this as the texture. The downside is that you won’t see changes to the tile controls until the next cycle.

Color Controls:
Obvious, really.

Thanks to aienn for the footage used in the screenshots

10
Oct
08

From The Archives

Some screenshots of a version of the Maths Surfaces QTZ I found on my Desktop (really need to tidy up a bit).

I may have uploaded these before, so apologies if that’s the case.

10
Oct
08

Velvet Heart

Cheesy, I know, but really just a test of normal-calculation in the Vertex Shader. The velvet/rim-lighting effect was just the first lighting shader that came to hand, as it were…

I’ll post the sourcecode and QTZ soon, for what it’s worth.

08
Oct
08

Parametric Heart

OK; this needs some explanation. The background is, ages ago, when I was working on the original Desaxismundi Maths Surfaces QTZ, I found that some of the surfaces didn’t really work as I expected. Some of them also weren’t really that interesting, in the end, so I thought it would be cool to find a few different ones to replace the more boring and/or non-working ones. One of the 3D forms I thought would be fun to do, if I could find a parametric equation for it, was a ‘Valentine’s Day’-style architypal love-heart shape. I managed to find a few different equations to create something along these lines, but didn’t get around to testing any of them, and forgot about it for a few months. Then, I came across this page on Mike Williams’ site again this morning, had a bit of free time, and thought I’d have another go at making ‘Yet Another Heart’ into a parametric GLSL Vertex Shader. I was able to create both the solid heart shape (based on a modulated sphere) and the heart hoop version (based on a torus). Once I’d found the right formulae to create the base Sphere and Torus forms from a flat GLSL Grid patch, both were pretty easy to implement, though the maths could probably be made more efficient.

Here’s the Vertex Shader for the solid version:

///////////////////////////
//      CONSTANTS        //
///////////////////////////

const float PI = 3.14159265;
const float TWOPI = 6.28318531;

///////////////////////////
//       CONTROLS        //
///////////////////////////

uniform float A, B, C, D;

///////////////////////////
//  PARAMETRIC EQUATION  //
//      FUNCTIONS        //
///////////////////////////

vec4 heartSphere(in vec4 point)
{
	/*
		Parametric 3D heart equation, based on parametric sphere:
		
		u = point.x * PI;
		v = point.y * TWOPI;
		
		sphere.x = radius * cos(u) * sin(v);
		sphere.y = radius * sin(u) * sin(v);
		sphere.z = radius * cos(v);
		
		Adapted from Mike Williams' equation, found at
		http://www.econym.demon.co.uk/isotut/real.htm#heart1
	*/
	
	float u = point.x * PI;
	float v = point.y * TWOPI;
	
	vec4 outPos;
	outPos.x = (cos(u) * sin(v)) - pow(abs(sin(u) * sin(v)), A) * B;
	outPos.y = cos(v) * C;
	outPos.z = sin(u) * sin(v);
	outPos.w = point.w;
	
	return outPos;
}

///////////////////////////
//   VARYINGS (TO FS)    //
///////////////////////////

varying float shade;

///////////////////////////
//       MAIN LOOP       //
///////////////////////////

void main()
{
	// Set vert to parametric formula
	// applied to original vertex position
	vec4 vert = heartSphere(gl_Vertex);
	
	// Scale
	vert.xyz *= D;
	
	// Generate value for 'fake' lighting effect
	// based on vertex distance from origin
	shade = 1.0 - smoothstep(0.0,0.8,distance(vert.xyz, vec3(0.0)));	
	//Transform vertex by modelview and projection matrices
	gl_Position = gl_ModelViewProjectionMatrix * vert;
	
	//Forward current color and texture coordinates after applying texture matrix
	gl_FrontColor = gl_Color;
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}

..and here’s the very simple Fragment Shader:

///////////////////////////
//  VARYINGS (FROM FS)   //
///////////////////////////

varying float shade;

///////////////////////////
//       CONTROLS        //
///////////////////////////

uniform vec4 Base_Color;

///////////////////////////
//       MAIN LOOP       //
///////////////////////////

void main()
{
	// Multiply base color by value from Fragment Shader
	gl_FragColor = Base_Color * vec4(vec3(shade), 1.0);
}

No normal-calculation here, so it can’t be lit properly. Normals could be calculated quite easily (with a performance hit, of course) using the method outlined by tonfilm. Parameters A B C and D should be in the 0 > 1 range.

I’m definitely going to add this to to the Maths Surfaces collection, and there are a couple of other surfaces on Mike’s site I might have a go at, too. I’ll have to work up to it though, as it always takes ages to update the Surfaces QTZ, because I always think of extra tweaks to make, which then have to be copied to all 50+ shaders.

‘tb Heart Surface 00.qtz’ in the Box.net widget.




Twitter

October 2008
M T W T F S S
 12345
6789101112
13141516171819
20212223242526
2728293031  

Links

Blog Stats

  • 495,318 hits