Archive for the 'GLSL' Category


More Volume Rendering Fun


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.

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.


3D Perlin Vertex Noise GLSL Sourcecode

This is the GLSL vertex shader code for 3D noise. Fragment shader is the same as for the 2D variant.

	3D Perlin-Noise in the vertex shader, based originally on
	vBomb.fx HLSL vertex noise shader, from the NVIDIA Shader Library.

	Original Perlin function substituted for Stefan Gustavson's
	texture-lookup-based Perlin implementation.
	Quartz Composer setup
	toneburst 2009


//  3D Perlin Noise   //

	3D Perlin-Noise from example by Stefan Gustavson, found at


uniform sampler2D permTexture;			// Permutation texture
const float permTexUnit = 1.0/256.0;		// Perm texture texel-size
const float permTexUnitHalf = 0.5/256.0;	// Half perm texture texel-size

float fade(in float t) {
	return t*t*t*(t*(t*6.0-15.0)+10.0);

float pnoise3D(in vec3 p)
	vec3 pi = permTexUnit*floor(p)+permTexUnitHalf; // Integer part, scaled so +1 moves permTexUnit texel
	// and offset 1/2 texel to sample texel centers
	vec3 pf = fract(p);     // Fractional part for interpolation

	// Noise contributions from (x=0, y=0), z=0 and z=1
	float perm00 = texture2D(permTexture, pi.xy).a ;
	vec3  grad000 = texture2D(permTexture, vec2(perm00, pi.z)).rgb * 4.0 - 1.0;
	float n000 = dot(grad000, pf);
	vec3  grad001 = texture2D(permTexture, vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
	float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));

	// Noise contributions from (x=0, y=1), z=0 and z=1
	float perm01 = texture2D(permTexture, pi.xy + vec2(0.0, permTexUnit)).a ;
	vec3  grad010 = texture2D(permTexture, vec2(perm01, pi.z)).rgb * 4.0 - 1.0;
	float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));
	vec3  grad011 = texture2D(permTexture, vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
	float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));

	// Noise contributions from (x=1, y=0), z=0 and z=1
	float perm10 = texture2D(permTexture, pi.xy + vec2(permTexUnit, 0.0)).a ;
	vec3  grad100 = texture2D(permTexture, vec2(perm10, pi.z)).rgb * 4.0 - 1.0;
	float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));
	vec3  grad101 = texture2D(permTexture, vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
	float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));

	// Noise contributions from (x=1, y=1), z=0 and z=1
	float perm11 = texture2D(permTexture, pi.xy + vec2(permTexUnit, permTexUnit)).a ;
	vec3  grad110 = texture2D(permTexture, vec2(perm11, pi.z)).rgb * 4.0 - 1.0;
	float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));
	vec3  grad111 = texture2D(permTexture, vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
	float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));

	// Blend contributions along x
	vec4 n_x = mix(vec4(n000, n001, n010, n011),
			vec4(n100, n101, n110, n111), fade(pf.x));

	// Blend contributions along y
	vec2 n_xy = mix(n_x.xy,, fade(pf.y));

	// Blend contributions along z
	float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));

	// We're done, return the final noise value.
	return n_xyz;

// Sphere Function //

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

vec4 sphere(in float u, in float v) {
	u *= PI;
	v *= TWOPI;
	vec4 pSphere;
	pSphere.x = BaseRadius * cos(v) * sin(u);
	pSphere.y = BaseRadius * sin(v) * sin(u);
	pSphere.z = BaseRadius * cos(u);
	pSphere.w = 1.0;
	return pSphere;

// Apply 3D Perlin Noise //

uniform vec3 NoiseScale;	// Noise scale, 0.01 > 8
uniform float Sharpness;	// Displacement 'sharpness', 0.1 > 5
uniform float Displacement;	// Displcement amount, 0 > 2
uniform float Speed;		// Displacement rate, 0.01 > 1
uniform float Timer;		// Feed incrementing value, infinite

vec4 perlinSphere(in float u, in float v) {
	vec4 sPoint = sphere(u, v);
	// The rest of this function is mainly from vBomb shader from NVIDIA Shader Library
	vec4 noisePos = vec4(,1.0) * (sPoint + (Speed * Timer));
	float noise = (pnoise3D( + 1.0) * 0.5;;
	float ni = pow(abs(noise),Sharpness) - 0.25;
	vec4 nn = vec4(normalize(,0.0);
	return (sPoint - (nn * (ni-0.5) * Displacement));

// Calculate Position, Normal //

const float grid = 0.01;	// Grid offset for normal-estimation
varying vec3 norm;			// Normal

vec4 posNorm(in float u, in float v) {
	// Vertex position
	vec4 vPosition = perlinSphere(u, v);
	// Estimate normal by 'neighbour' technique
	// with thanks to tonfilm
	vec3 tangent = (perlinSphere(u + grid, v) - vPosition).xyz;
	vec3 bitangent = (perlinSphere(u, v + grid) - vPosition).xyz;
	norm = gl_NormalMatrix * normalize(cross(tangent, bitangent));
	// Return vertex position
	return vPosition;

// Phong Directional VS //

// -- Lighting varyings (to Fragment Shader)
varying vec3 lightDir0, halfVector0;
varying vec4 diffuse0, ambient;

void phongDir_VS() {
	// Extract values from gl light parameters
	// and set varyings for Fragment Shader
	lightDir0 = normalize(vec3(gl_LightSource[0].position));
	halfVector0 = normalize(gl_LightSource[0];
	diffuse0 = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
	ambient =  gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
	ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;

// Main Loop //

uniform vec2 PreScale, PreTranslate;	// Mesh pre-transform

void main()
	vec2 uv = gl_Vertex.xy;
	// Offset XY mesh coords to 0 > 1 range
	uv += 0.5;
	// Pre-scale and transform mesh
	uv *= PreScale;
	uv += PreTranslate;
	// Calculate new vertex position and normal
	vec4 spherePos = posNorm(uv[0], uv[1]);
	// Calculate lighting varyings to be passed to fragment shader
	// Transform new vertex position by modelview and projection matrices
	gl_Position = gl_ModelViewProjectionMatrix * spherePos;
	// Forward current texture coordinates after applying texture matrix
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;

2D/3D Perlin Vertex Noise

Crashes on my laptop, works like a dream on my desktop machine.
More info to come.

The red ones above are from a different version of the effect, that does work on my ageing MacBook Pro (though it’s still slow- 12-14fps at 640 x 360). Note the highlights aren’t as smooth, because I had to drop the resolution of the base mesh to improve the framerates a little on the laptop.

And here’s a clip of the 2D version:

and the 3D one:

and with an environment-map shader (not so successful)


GPU Raycasting Now Working

Finally got it to work!
So, here’s Borg and Blob surfaces rendered in a GPU-accelerated GLSL raycaster shader:

As you can see, there’s a certain graininess to the render. This I actually quite like. It can be smoothed-out by decreasing the step-length that each ray is incremented by, but this slows down render times exponentially.

Obviously, there’s no lighting calculation being done, and I’m not working out normals at all. I quite like the ghostly quality you get from this simple opacity-accumulation-style render though.

Thanks once again to Peter Trier for sharing his method, and I’d also like to thank Viktor N. Latypov for his encouragement on this project.

Here’s a clip of the shader at work on a Blob surface. I’ve added some colour to the rendering by mixing-in the ray XYZ-position as RGB colour, to add a bit of interest to the volume.

..and the Borg surface:

And this time, modulating the ray’s start position with live video input:


GPU Raycasting

First attempt at implementing Peter Trier’s simple raycasting setup as an isosurface renderer. It’s definitely not working as it should, but it’s looking interesting, anyway.

Here it’s rendering a Borg isosurface, from Paul Bourke’s site.


Simple X-Ray Shader

From Ogre3D.

/* Vertex Shader */

varying vec3 P;
varying vec3 N;
varying vec3 I;

void main()
	//Transform vertex by modelview and projection matrices
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
	// Position in clip space
	P = vec3(gl_ModelViewMatrix * gl_Vertex);
	// Normal transform (transposed model-view inverse)
	N = gl_NormalMatrix * gl_Normal;
	// Incident vector
	I = P;
	// Forward current color and texture coordinates after applying texture matrix
	gl_FrontColor = gl_Color;
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;

/* Fragment Shader */

varying vec3 P;
varying vec3 N;
varying vec3 I;

uniform float EdgeFalloff;

void main()
	float opacity = dot(normalize(N), normalize(-I));
	opacity = abs(opacity);
	opacity = 1.0 - pow(opacity, EdgeFalloff);
	gl_FragColor = opacity * gl_Color;

The Perennial vBomb.fx

I keep coming back to this one (and so do lots of other people, by the looks of it).
It’s a GLSL conversion of the old NVIDIA HLSL vBomb shader, that applies Perlin Noise to vertex positions in much the same way as the Quartz Composer Vertex Noise example.

The idea here though was that I’d try to make a version that would be more likely to be hardware-accelerated. Since the GLSL noise() functions aren’t actually implemented on all graphics hardware. The fact that they seem to generally be pretty slow, at least on my ATI X1600, suggests to me that this is the case with my card, and GLSL noise() is actually forcing software-render-fallback. The vBomb conversion certainly seems pretty fast, though!

Here some examples that don’t take things any further than the original vBomb, in terms of the output. I’m planning to add lighting too, though. Again, absolutely nothing original about that- in fact, Desaxismundi’s beautifully-lit vBomb vvvv shaders (witness here, and, particularly here) were one of my original inspirations for getting into 3D graphics, and particularly GLSL shaders in the first place. I owe Desaxismundi, and the vvvv community generally a huge debt of gratitude for introducing me to this wonderful (if confusing) world.


Blog Hiatus

I’ve got involved in a few other things lately, and haven’t had so much time to work in fun stuff in QC, sadly. I’ll be getting back to it as soon as I can though.

In the meantime, here’s a nice video produced by George Toledo. It’s a rendering of the IsoSurface shader, and very nice it is too.




Rendering Volume Data Set

More info to follow.


April 2014
« Oct    


Blog Stats

  • 377,706 hits


Get every new post delivered to your Inbox.

Join 34 other followers