Back to home

3D Math

I've been reading up with 3D math, openGL, physics etc.. for a while now and yes, finally I think I'm getting somewhere. The first results, although still extremely basic, but quite fun are ready to be shown. I've created a sphere from ofxVec3f objects (3d vector objects, in C++), which get randomly distributed using a simple spatial algorithm.

Then, after I've calculated the positions for the points I create rectangles, actually just openGL GL_QUADS, but using the crossproduct to get the perpendicular lines/positions that make up de quad. When I've got the positions of the QUADs I use an alpha transparent image and put that as a texture on it.

Calculating the points for the quad
Below is the code I've used to calculate the vertices for the QUAD. I'm not sure if this is the best solution, but it works perfect!

void TestQuad::draw() {
    ofEnableAlphaBlending();
 
 
    glBegin(GL_LINE_STRIP);
    for(int i = 0; i < tail.size(); ++i) {
        float a = ((float)tail.size()-i)/(float)tail.size() * .2;
        glColor4f(1.0, 0.0, 0.6,a);
        glVertex3f(tail.at(i).x, tail.at(i).y, tail.at(i).z);
    }
    glEnd();
 
    ofxVec3f normal = position - center;
    ofxVec3f up_vec(0,1,0);
    ofxVec3f p1 = normal.getCrossed(up_vec).normalize().scale(size);
    ofxVec3f p2 = normal.getCrossed(p1).normalize().scale(size);
    ofxVec3f p3 = normal.getCrossed(p2).normalize().scale(size);
    ofxVec3f p4 = normal.getCrossed(p3).normalize().scale(size);
    ofxVec3f pp1 = position+p1;
    ofxVec3f pp2 = position+p2;
    ofxVec3f pp3 = position+p3;
    ofxVec3f pp4 = position+p4;
 
 
    glColor4f(1.0,1.0,1.0,0.9f);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,texture_id);
 
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(pp1.x, pp1.y, pp1.z);
        glTexCoord2f(1.0f, 0.0f); glVertex3f(pp2.x, pp2.y, pp2.z);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(pp3.x, pp3.y, pp3.z);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(pp4.x, pp4.y, pp4.z); 
    glEnd();
    glDisable(GL_TEXTURE_2D);
}

Distributing points on a sphere

// from: http://local.wasp.uwa.edu.au/~pbourke/geometry/spherepoints/
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
 
/*
   Create N points on a sphere aproximately equi-distant from each other
   Basically, N points are randomly placed on the sphere and then moved
   around until then moved around until the minimal distance between the
   closed two points is minimaised.
   Paul Bourke, July 1996
*/
 
#define ABS(x) (x < 0 ? -(x) : (x))
 
typedef struct {
  double x,y,z;
} XYZ;
 
void Normalise(XYZ *,double);
double Distance(XYZ,XYZ);
 
/*
   Called with three arguments, the number of points to distribute, the
   radius of the sphere, and the maximum number of iterations to perform.
*/
int main(argc,argv)
int argc;
char **argv;
{
   int i,j,n;
   int counter = 0,countmax = 100;
   int minp1,minp2;
   double r,d,mind,maxd;
   XYZ p[1000],p1,p2;
 
   /* Check we have the right number of arguments */
   if (argc < 4) {
      fprintf(stderr,"Usage: %s npoints radius niterations\n",argv[0]);
      exit(0);
   }
   if ((n = atoi(argv[1])) < 2)
      n = 3;
   if ((r = atof(argv[2])) < 0.001)
      r = 0.001;
   if ((countmax = atoi(argv[3])) < 100)
      countmax = 100;
 
   /* Create the initial random cloud */
   for (i=0;i<n;i++) {
       p[i].x = (rand()%1000)-500;
       p[i].y = (rand()%1000)-500;
       p[i].z = (rand()%1000)-500;
       Normalise(&p[i],r);
    }
 
    while (counter < countmax) {
 
        /* Find the closest two points */
        minp1 = 0;
        minp2 = 1;
        mind = Distance(p[minp1],p[minp2]);
        maxd = mind;
        for (i=0;i<n-1;i++) {
            for (j=i+1;j<n;j++) {
                if ((d = Distance(p[i],p[j])) < mind) {
                   mind = d;
                   minp1 = i;
                   minp2 = j;
                }
                if (d > maxd)
                   maxd = d;
            }
        }
 
        /*
           Move the two minimal points apart, in this case by 1%
           but should really vary this for refinement
        */
        p1 = p[minp1];
        p2 = p[minp2];
        p[minp2].x = p1.x + 1.01 * (p2.x - p1.x);
        p[minp2].y = p1.y + 1.01 * (p2.y - p1.y);
        p[minp2].z = p1.z + 1.01 * (p2.z - p1.z);
        p[minp1].x = p1.x - 0.01 * (p2.x - p1.x);
        p[minp1].y = p1.y - 0.01 * (p2.y - p1.y);
        p[minp1].z = p1.z - 0.01 * (p2.z - p1.z);
        Normalise(&p[minp1],r);
        Normalise(&p[minp2],r);
 
        counter++;
    }
 
    /* Write out the points in your favorite format */
 
}
 
void Normalise(p,r)
XYZ *p;
double r;
{
   double l;
 
   l = r / sqrt(p->x*p->x + p->y*p->y + p->z*p->z);
   p->x *= l;
   p->y *= l;
   p->z *= l;
}
 
double Distance(p1,p2)
XYZ p1,p2;
{
   XYZ p;
 
   p.x = p1.x - p2.x;
   p.y = p1.y - p2.y;
   p.z = p1.z - p2.z;
   return(sqrt(p.x*p.x + p.y*p.y + p.z*p.z));
}