Morph a sphere to a cube and a cube to a sphere with GLSL

I'm getting started with GLSL with quartz composer. I have a patch with a particle system in which each particle is mapped into a sphere with a blend value. With blend=0 particles are in random positions, blend=1 particles are in the sphere. The code is here:

vec3 sphere(vec2 domain)
{
vec3 range;
range.x = radius * cos(domain.y) * sin(domain.x);
range.y = radius * sin(domain.y) * sin(domain.x);
range.z = radius * cos(domain.x);
return range;
}

// in main:

vec2 p0 = gl_Vertex.xy * twopi;
vec3 normal = sphere(p0);;
vec3 r0 = radius * normal;
vec3 vertex = r0;

normal = normal * blend + gl_Normal * (1.0 - blend);
vertex = vertex * blend + gl_Vertex.xyz * (1.0 - blend);


I'd like the particle to be on a cube if blend=0

I've tried to find but I can't figure out some parametric equation for the cube. Maybe it is not the right way?

• what is domain? or p0? I'm sorry but it is quite impossible to have parametric cube. – Notabene Jan 8 '11 at 18:55
• and for blendig you can use glsl mix funtion. example: mix(value1,value2,mixFactor) where mixFactor is number in range 0-1 – Notabene Jan 8 '11 at 22:14

1 Answer

edit: source shader code tested, updated and works...

there is also video...

Once you use a 3D coord instead 2D to sample cube, it is possible (but not parametric :)).

First theory:

Use normalize(GL_Vertex - cubeOrigin) as sampling vector.

You have to know to which face of cube vertex belongs. It is the biggest componnent in sampling vector.

Once you have face, you can specify face normal. Than compute angle between face normal and sampling vector. Use Law of sines to get distance of point in space from cube origin(in middle). Multiply this distance with normal and you got it :)

// this code sucks for shader ... it would be slow it is written to be clear not optimal.

uniform int timer;

//return face's ID based on sampling vector
int face(vec3 coord)
{
if((abs(coord.x) > abs(coord.y)) && (abs(coord.x) > abs(coord.z)))
{
if (coord.x > 0)
return 0;
else
return 1;
}
if( abs(coord.y) > abs(coord.z))
{
if (coord.y > 0)
return 2;
else
return 3;
}
if (coord.z > 0)
return 4;
return 5;
}

vec3 cube(vec3 position,vec3 cubeOrigin)
{
int CUBE_SIZE = 2;
vec3 coord = normalize(position - cubeOrigin);
int face = face(coord);
vec3 faceNormal = vec3(0);
switch (face)
{
case 0: faceNormal = vec3(1,0,0); break;
case 1: faceNormal = vec3(-1,0,0); break;
case 2: faceNormal = vec3(0,1,0); break;
case 3: faceNormal = vec3(0,-1,0); break;
case 4: faceNormal = vec3(0,0,1); break;
case 5: faceNormal = vec3(0,0,-1); break;
}

float gamma = acos (dot(faceNormal,coord));
float alfa = 3.14 - 1.57 - gamma; //there is no PI or HALF_PI in glsl you have to define it on your own.
//this is little hard stuff. You want to know length from origin to place on cube. It is simple triangle and can be solved by law of sines.
//It should be multiplied with sin(HALF_PI) but it is 1.
float posFactor =  (CUBE_SIZE/2.0)/sin(alfa) ;

return (cubeOrigin + coord * posFactor);
}

void main(void)
{
vec3 transformed = cube(gl_Vertex.xyz,vec3(0.0,0.0,0.0));
vec4 cubetrans = vec4 (transformed,1.0);
gl_Position     = mix(gl_ModelViewProjectionMatrix * cubetrans,gl_ModelViewProjectionMatrix * gl_Vertex,timer/200.0);

gl_FrontColor = gl_Color;
}

• it's quit clear but i think i missed something. normal=positionOnCube makes no sense.. vertex? i wrote it, it compile saying: Warning: vertex shader writes varying 'Normal' which is not active – nkint Jan 9 '11 at 0:07
• well yes it is stupid to use normal. Are you rendering points or triangles? Instead of try to use: Normalize(randomVertexPosition - cubeOrigin) ... it has to be normalized. – Notabene Jan 9 '11 at 0:11
• If you want full source code, just say ;) – Notabene Jan 9 '11 at 2:16
• that is an interesting algorithm! can you elaborate on that law of sines? or do you have a link maybe? – clamp Apr 11 '11 at 15:50
• any one has complete source code? if so can please post on github? – Vamsi Dec 4 '15 at 4:31