Vertex Shader:

/* Spherical Harmonics code Paul Bourke, adapted from http://local.wasp.uwa.edu.au/%7Epbourke/surfaces_curves/sphericalh/ GLSL assistance and general encouragement Memo GLSL implementation alx @ toneburst, 2008 */ ///////////////////// //// CONSTANTS //// ///////////////////// #define TWOPI 6.28318531 #define PI 3.14159265 ///////////////////// //// TWEAKABLES //// ///////////////////// // Pre-Transform controls uniform vec4 TT_0; // TT_0(X) = Pre-Scale X (range 0.0 > 1.0) uniform vec4 TT_1; // TT_1(Y) = Pre-Scale Y (range 0.0 > 1.0) uniform vec4 TT_2; uniform vec4 TT_3; // TT_3(X),(Y) = Pre-Translate X,Y (range 0.0 > 1.0) // Spherical Harmonics controls (range 0.0 to 10.0) uniform float M0,M1,M2,M3,M4,M5,M6,M7; // Light position uniform vec3 LightPosition; ///////////////////// //// VARYINGS //// ///////////////////// // Passes result of shading calculation to Fragment Shader varying float colpos; ///////////////////// //// FUNCTIONS //// ///////////////////// // The actual Spherical Harmonics formula (operates on Spherical coordinates) vec3 sphericalHarmonics(float theta, float phi, float m0,float m1,float m2,float m3,float m4,float m5,float m6,float m7) { vec3 point; float r = 0.0; r += pow(sin(m0*phi),m1); r += pow(cos(m2*phi),m3); r += pow(sin(m4*theta),m5); r += pow(cos(m6*theta),m7); point.x = r * sin(phi) * cos(theta); point.y = r * cos(phi); point.z = r * sin(phi) * sin(theta); return point; } ///////////////////// //// MAIN LOOP //// ///////////////////// void main() { // Create pre-transform matrix from uniform vec4s mat4 TT = mat4(TT_0,TT_1,TT_2,TT_3); // Get vertex coordinates (cartesian) vec4 vertex = gl_Vertex; // Initial vertex position pre-transformed vertex = TT * vertex; // Spherical coordinates to send to Spherical Harmonics function float theta = (vertex.x + 0.5) * TWOPI; // set range to 0 > TWOPI float phi = (vertex.y + 0.5) * PI; // set range 0 > PI // Spherical Harmonics function vertex.xyz = sphericalHarmonics(theta, phi, M0, M1, M2, M3, M4, M5, M6, M7); // Shading calculation colpos = length(vertex.xyz + LightPosition); // Transform vertex by modelview and projection matrices gl_Position = gl_ModelViewProjectionMatrix * vertex; // Forward current color and texture coordinates after applying texture matrix gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; }

And Fragment Shader:

///////////////////// //// TWEAKABLES //// ///////////////////// // Base color uniform vec4 Color; // Lighting range. Range 0.1 > 1.0 (use exponential control) uniform float LightRange; ///////////////////// //// VARYINGS //// ///////////////////// // Shading calculation from Vertex Shader varying float colpos; ///////////////////// //// TEXTURES //// ///////////////////// // Shading lookup table input uniform sampler2D LUT; // Lookup y-position. Range 0.0 > 1.0 uniform float LUT_Y; // Surface texture input uniform sampler2D TileImg; // Surface texture scale. Range 0.001 > 0.5 uniform vec2 Tile; ///////////////////// //// MAIN LOOP //// ///////////////////// void main() { // Fake lighting shading with Lookup Table float lookupX = clamp((1.0-LightRange) * colpos,0.1,0.9); // Lookup shade across x-axis of LUT at y-position set by LUT_Y input vec4 shade = texture2D(LUT, vec2(lookupX,LUT_Y)); // Surface tiling texture vec2 xy = gl_TexCoord[0].xy; vec2 phase = fract(xy / Tile); vec4 texTile = texture2D(TileImg,phase); // Output color compute gl_FragColor = Color * shade * texTile; }

Advertisements

So presumably you need to have some sort of primitive to do this to? such as a cube…? I chucked a cube in and played with some of the values but the best I could get was a dark half-section of my viewer… Any clues?

Ah, no, it needs to me a GLSL Grid primitive.

So:

you need a GLSL Shader with the Vertex and Fragment Shader code as above

then inside that, a Trackball or 3D Transformation Macro (if you want to be able to turn the mesh around)

then inside that, a GLSL Grid. Set the Vertical and Horizontal resolution to 150 or 200 otherwise you’ll get a very low-res surface.

You need to hook up some controls. I’ve added comments with suggested ranges. The Pre-Scale X and Y ones should be set to 1.0 initially or you won’t see anything.

Also, download the Lookup Table from the next post and hook it up to the LUT input on the shader.

Hope all this helps.

alx

I’m obviously doing something wrong here. I’ve got the whole caboodle set up like you described, I think, and I’m still just ending up with random dark objects. Although this GLSL one is better than the cube!

Here are the settings I’ve got:

in the GLSL Shader patch (hastily stitched together from two screen grabs, I might add!)

inside that is a 3D Transformation, and inside that is a GLSL Grid:

which gives this output:

…which all seems a little far away from where you’re at. Do I just need to sit here tweaking it for hours? I’m just a little surprised that it’s coming out dark, I think…

Ok:

TT_0(X) and TT_1(Y) both need to be set to 1

TT_3(Z) and TT_3(W) also have to be set to 1

These determine the scale of the initial mesh.

You need to set LightRange so something other than 0 (try 0.5).

Parameters M0 > M7 are inputs to the Spherical Harmonics formula, and change the form of the mesh. There are suggested ranges in the comments in the shader code (look for greyed-out text after ‘//’).

Tile(X) and (Y) need to be set to something. Try 0.1 for both initially. Don’t forget to hook up a square picture to the TileImg input.

That should get you started.

alx

Also, you may find it necessary to make the mesh smaller by tweaking the Z-Position value of the 3D Tramsform patch.

alx

Ahh that’s the stuff! 🙂

Now, my BSc dissertation is on making live visuals for music, so I’ve just been having a play around making the M values change in time to music, and it’s very easy!

So I was wondering whether you’d mind me using this for that? Of course I’ll make sure you and all of your code is properly referenced…

Please drop me a line if you like! (email address included with this post)

Ah.. you’ve got it to work, hob- good news!

I’ll drop you a mail in a moment.

alx

Probably missing something very obviose, linking in from memo.tv. Where is the lookup table?

Probably missing something very obvious, linking in from memo.tv. Where is the lookup table?

Nevermind, just grabbed the .QTZ. Awesome work, is it cool to use this in a live performance?

Hi Neb!

Absolutely, use it for anything you like. Hopefully, without the lighting calculation, you’ll be able to get a decent framerate. Lot me know how it goes with the gig!

alx

Hi Alex,

i’ve tried to follow the steps of this example but nothing appears on the viewer yet. i have a GLSL SHADER with your code lines pasted on both types of shaders,inside it could be a TRACKBALL with a GLSL GRID or just the grid. i was wondering if there is a plugin or something needed for this goal.

thanks

Hiya,

good to hear from you. You could try downloading a version of the composition from Memo’s QC archive at

http://vdmx.memo.tv/tb_sphericalharmonics_1_01?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+memotv-vdmx-qc+%28VDMX+%26+Quartz+Composer+%40+memo.tv%29

Hope this helps,

a|x

hi Alex

thank you for your help. this is complex for me because i’m a non-programmer newbie at QC stuff, but trying hard to make some compositions for VDMX live performance. at this moment i’m getting many plugins at KINEME for QC. anyway i’ve got too much to learn. thanks again.

I’m a non-programmer, too, really. I guess I gravitated towards QCs programming patches because I enjoy tinkering with code, and there’s a lot you can do with a few lines, or a few tweaks to other’s code.

There’s always too much to learn, no matter how much you already know 😉

Good luck with the performances. Let me know how you get on.

a|x