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;

//      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
	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:


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.


1 Response to “Parametric Heart”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


October 2008
« Sep   Nov »


Blog Stats

  • 477,440 hits

%d bloggers like this: