home dev games gallery work
Lewpen.com»Research & Development»3D Graphics»OpenGL»Reflective Sphere

Reflective Sphere

Analytical reflections in OpenGL

/ Source / common / 001 / radialobject.cpp

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>


#include "radialobject.h"

#include "interpolate.h"

#include "vector.h"





//---- ARGUMENTS

int radialObject_res = 27;






//---- getRadialObjectDistanceCube

//  Returns the distances necessary for a cube

double getRadialObjectDistanceCube( double x, double y, double z, double time )
{
  //- Calculate distance from each plane, nearest one wins

//  double dist_x = x<=0.0001 ? 3 : sqrt( 1.0 + (y*y + z*z)/(x*x) );  //  Distance from x = +/-1 plane
//  double dist_y = y<=0.0001 ? 3 : sqrt( 1.0 + (x*x + z*z)/(y*y) );
//  double dist_z = z<=0.0001 ? 3 : sqrt( 1.0 + (x*x + y*y)/(z*z) );

  double dist_x = sqrt( 1.0 + (y*y + z*z)/(x*x) );  //  Distance from x = +/-1 plane
  double dist_y = sqrt( 1.0 + (x*x + z*z)/(y*y) );
  double dist_z = sqrt( 1.0 + (x*x + y*y)/(z*z) );

  if( dist_x < dist_y && dist_x < dist_z ) return dist_x;  //  x is smaller than both y and z
  if( dist_y < dist_z ) return dist_y;                     //  y is smaller than z
  return dist_z;                                           //  must be z then
}





//---- getRadialObjectDistanceSphere

//  Returns the distances necessary for a sphere given a directional vector

double getRadialObjectDistanceSphere( double x, double y, double z, double time )
{
  return sqrt( x*x + y*y + z*z );  //  Sphere is the size of the directional vector
}



//---- getRadialObjectDistanceTetra

double getRadialObjectDistanceTetra( double x, double y, double z, double time )
{
  double nx, ny, nz;

  double d1, d2, d3, d4;

  nx = 0; ny = 2; nz = 0;

  d1 = 1.0 / (nx*x + ny*y + nz*z );

  if( d1 < 0 ) d1 = 9999;

//  vector_rotate_z( &x, &y, &z, 0.33333333333333333333 );
//  vector_rotate_z( &px, &py, &pz, 0.33333333333333333333 );
  vector_rotate_z( &nx, &ny, &nz, 0.33333333333333333333 );

  d2 = 1.0 / (nx*x + ny*y + nz*z );

  if( d2 < 0 ) d2 = 9999;

  vector_rotate_y( &x, &y, &z, 0.33333333333333333333 );
//  vector_rotate_y( &px, &py, &pz, 0.33333333333333333333 );
//  vector_rotate_y( &nx, &ny, &nz, 0.33333333333333333333 );

  d3 = 1.0 / (nx*x + ny*y + nz*z );

  if( d3 < 0 ) d3 = 9999;

  vector_rotate_y( &x, &y, &z, 0.33333333333333333333 );
//  vector_rotate_y( &px, &py, &pz, 0.33333333333333333333 );
//  vector_rotate_y( &nx, &ny, &nz, 0.33333333333333333333 );

  d4 = 1.0 / (nx*x + ny*y + nz*z );

  if( d4 < 0 ) d4 = 9999;

  if( d1 < d2 && d1 < d3 && d1 < d4 ) return d1;
  if( d2 < d3 && d2 < d4            ) return d2;
  if( d3 < d4                       ) return d3;
                                      return d4;
/*
  if( d1 > d2 && d1 > d3 && d1 > d4 ) return d1 <= 0.001 ? 9999 : 1.0/d1;
  if( d2 > d3 && d2 > d4            ) return d2 <= 0.001 ? 9999 : 1.0/d2;
  if( d3 > d4                       ) return d3 <= 0.001 ? 9999 : 1.0/d3;
                                      return d4 <= 0.001 ? 9999 : 1.0/d4;
*/
}



//---- getRadialObjectDistanceTetraStar

double getRadialObjectDistanceTetraStar( double x, double y, double z, double time )
{
  double d1 = getRadialObjectDistanceTetra( x, y, z, time );
  double d2 = getRadialObjectDistanceTetra( -x, -y, -z, time );

/*
  if( d1 >  2 ) d1 =  2;
  if( d1 < -2 ) d1 = -2;
  if( d2 >  2 ) d2 =  2;
  if( d2 < -2 ) d2 = -2;
*/

  return d1 > d2 ? d1*d1 : d2*d2;
}




//---- getRadialObjectDistanceBlob

//  Returns the distances necessary for a sphere given a directional vector

double getRadialObjectDistanceBlob_baseMag = 1.2;

double getRadialObjectDistanceBlob_xMag = 0.15;
double getRadialObjectDistanceBlob_yMag = 0.20;
double getRadialObjectDistanceBlob_zMag = 0.23;

double getRadialObjectDistanceBlob_xWavelength = 3.3268;
double getRadialObjectDistanceBlob_yWavelength = 7.1212;
double getRadialObjectDistanceBlob_zWavelength = 10.7181;

double getRadialObjectDistanceBlob_xPhase = 0.2188;
double getRadialObjectDistanceBlob_yPhase = 0.3287;
double getRadialObjectDistanceBlob_zPhase = 0.1221;

double getRadialObjectDistanceBlob_xSpeed = 2.1311;
double getRadialObjectDistanceBlob_ySpeed = 3.2021;
double getRadialObjectDistanceBlob_zSpeed = 5.3211;

double getRadialObjectDistanceBlob( double x, double y, double z, double time )
{
  return getRadialObjectDistanceBlob_baseMag +
         getRadialObjectDistanceBlob_yMag * sin( x*getRadialObjectDistanceBlob_xWavelength + getRadialObjectDistanceBlob_xPhase + time * getRadialObjectDistanceBlob_xSpeed ) +
         getRadialObjectDistanceBlob_yMag * sin( y*getRadialObjectDistanceBlob_yWavelength + getRadialObjectDistanceBlob_yPhase + time * getRadialObjectDistanceBlob_xSpeed ) +
         getRadialObjectDistanceBlob_yMag * sin( z*getRadialObjectDistanceBlob_zWavelength + getRadialObjectDistanceBlob_zPhase + time * getRadialObjectDistanceBlob_xSpeed );
}





//---- getRadialObjectDistanceZNPill

//  Returns the distances necessary for a ZN Pill logo shape

double getRadialObjectDistanceZNPill( double x, double y, double z, double time )
{
  //  works like a sphere but we subtract from x, y, z first which stretches the shape

  double w = 5, h = 3, d = 1.5;

  double ww = (w-1)*0.5;
  double hh = (h-1)*0.5;
  double dd = (d-1)*0.5;

  if( x < -ww ) {x += ww;} else if( x < ww ) {x = 0;} else {x -= ww;}
  if( y < -hh ) {y += hh;} else if( y < hh ) {y = 0;} else {y -= hh;}
  if( z < -dd ) {z += dd;} else if( z < dd ) {z = 0;} else {z -= dd;}

//  double d = getRadialObjectDistanceCube( x, y, z, time );



  return sqrt( x*x + y*y + z*z );  //  Sphere is the size of the directional vector
}





//---- getRadialObjectDistanceMultiple

double getRadialObjectDistanceMultiple( double x, double y, double z, double time, int ting )
{
  switch( ting )
  {
    case 0:
      return getRadialObjectDistanceCube( x, y, z, time );
    case 1:
  //    return getRadialObjectDistanceZNPill( x, y, z, time );
    case 2:
      return getRadialObjectDistanceSphere( x, y, z, time );
  }

  return getRadialObjectDistanceBlob( x, y, z, time );
}





//---- getRadialObjectDistanceAlternating

//  Given a direction vector and a time returns the distance from the origin

double getRadialObjectDistanceAlternating( double x, double y, double z, double time )
{
  //- Depending on the time make it an interpolation of one of the shapes

  double rate = /*sledgehammer*/2.791;//2.6728251515;//2.923;  //  changes <rate> times per second
  double changetime = 0.75;//0.25  //  Length of time it takes to change as a fraction of <rate>

  int numshapes = 4;  //  Number of different shapes to flick between

  int bit = ( (int)(time*rate) );  //  changes by 1 <rate> times per second (integer phase)
  double spare = time*rate - bit;  //  Fractional part of the phase

  bit %= numshapes;


//  bit = 0;
//  spare = changetime*0.5 + 0.5*changetime*sin( time*0.239 );

  //  morphing, get two values and interpolate

  if( spare < changetime )
  {
    double alpha = spare/changetime;
    int prev = (bit+numshapes-1) % numshapes;

    double d0 = getRadialObjectDistanceMultiple( x, y, z, time, prev );
    double d1 = getRadialObjectDistanceMultiple( x, y, z, time, bit );

    return interpolateSpringy( d0, d1, spare/changetime );
  }

  //  one particular shape

  else
  {
    return getRadialObjectDistanceMultiple( x, y, z, time, bit );
  }

}






//---- drawCubicRadialObjectSide

//  axis = 0 for x, 1 for y and 2 for z
//  side = -1 for back and 1 for front

double drawCubicRadialObjectSide_x[ RADIALOBJECT_MAXRES+1 ][ RADIALOBJECT_MAXRES+1 ];
double drawCubicRadialObjectSide_y[ RADIALOBJECT_MAXRES+1 ][ RADIALOBJECT_MAXRES+1 ];
double drawCubicRadialObjectSide_z[ RADIALOBJECT_MAXRES+1 ][ RADIALOBJECT_MAXRES+1 ];

void drawCubicRadialObjectSide( int axis, int side, double time, GET_RADIALOBJECT_DISTANCE thing_fn )
{
  int i, j;

  //- Calculate points

  switch( axis )
  {
    case 0:
      for( j=0; j<=radialObject_res; j++ )
      {
        for( i=0; i<=radialObject_res; i++ )
        {
          //  Point in plane

          drawCubicRadialObjectSide_x[j][i] = side;
          drawCubicRadialObjectSide_y[j][i] = side * 2.0 * ((i+0.0)/radialObject_res - 0.5);
          drawCubicRadialObjectSide_z[j][i] = side * 2.0 * ((j+0.0)/radialObject_res - 0.5);

          //  Normalise

          vector_normalise( &drawCubicRadialObjectSide_x[j][i], &drawCubicRadialObjectSide_y[j][i], &drawCubicRadialObjectSide_z[j][i] );

          //  Make shape

          double d = thing_fn( drawCubicRadialObjectSide_x[j][i], drawCubicRadialObjectSide_y[j][i], drawCubicRadialObjectSide_z[j][i], time );

          drawCubicRadialObjectSide_x[j][i] *= d;
          drawCubicRadialObjectSide_y[j][i] *= d;
          drawCubicRadialObjectSide_z[j][i] *= d;
        }
      }
      break;

    case 1:
      for( j=0; j<=radialObject_res; j++ )
      {
        for( i=0; i<=radialObject_res; i++ )
        {
          //  Point in plane

          drawCubicRadialObjectSide_x[j][i] = side * 2.0 * ((i+0.0)/radialObject_res - 0.5);
          drawCubicRadialObjectSide_y[j][i] = side;
          drawCubicRadialObjectSide_z[j][i] = side * 2.0 * ((j+0.0)/radialObject_res - 0.5);

          //  Normalise

          vector_normalise( &drawCubicRadialObjectSide_x[j][i], &drawCubicRadialObjectSide_y[j][i], &drawCubicRadialObjectSide_z[j][i] );

          //  Make shape

          double d = thing_fn( drawCubicRadialObjectSide_x[j][i], drawCubicRadialObjectSide_y[j][i], drawCubicRadialObjectSide_z[j][i], time );

          drawCubicRadialObjectSide_x[j][i] *= d;
          drawCubicRadialObjectSide_y[j][i] *= d;
          drawCubicRadialObjectSide_z[j][i] *= d;
        }
      }
      break;
    
    case 2:
      for( j=0; j<=radialObject_res; j++ )
      {
        for( i=0; i<=radialObject_res; i++ )
        {
          //  Point in plane

          drawCubicRadialObjectSide_x[j][i] = side * 2.0 * ((i+0.0)/radialObject_res - 0.5);
          drawCubicRadialObjectSide_y[j][i] = side * 2.0 * ((j+0.0)/radialObject_res - 0.5);
          drawCubicRadialObjectSide_z[j][i] = side;

          //  Normalise

          vector_normalise( &drawCubicRadialObjectSide_x[j][i], &drawCubicRadialObjectSide_y[j][i], &drawCubicRadialObjectSide_z[j][i] );

          //  Make shape

          double d = thing_fn( drawCubicRadialObjectSide_x[j][i], drawCubicRadialObjectSide_y[j][i], drawCubicRadialObjectSide_z[j][i], time );

          drawCubicRadialObjectSide_x[j][i] *= d;
          drawCubicRadialObjectSide_y[j][i] *= d;
          drawCubicRadialObjectSide_z[j][i] *= d;
        }
      }
      break;
  }

  //- Draw the quads

  //  This can be made more efficient by keeping the distances calulated in the above for loops

  double col;

  for( j=0; j<radialObject_res; j++ )
  {
    for( i=0; i<radialObject_res; i++ )
    {
      glColor3f( (i+0.0)/radialObject_res, (j+0.0)/radialObject_res, 0 );

      glBegin( GL_TRIANGLE_FAN );

        col = vector_length(drawCubicRadialObjectSide_x[j][i],drawCubicRadialObjectSide_y[j][i],drawCubicRadialObjectSide_z[j][i]);
//        glColor3f( col *= 0.5, col, col );
        glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j][i])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j][i])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j][i])*col );
        glVertex3f( drawCubicRadialObjectSide_x[j  ][i  ], drawCubicRadialObjectSide_y[j  ][i  ], drawCubicRadialObjectSide_z[j  ][i  ] );
        
        col = vector_length(drawCubicRadialObjectSide_x[j][i+1],drawCubicRadialObjectSide_y[j][i+1],drawCubicRadialObjectSide_z[j][i+1]);
//        glColor3f( col *= 0.5, col, col );
        glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j][i+1])*col );
        glVertex3f( drawCubicRadialObjectSide_x[j  ][i+1], drawCubicRadialObjectSide_y[j  ][i+1], drawCubicRadialObjectSide_z[j  ][i+1] );
        
        col = vector_length(drawCubicRadialObjectSide_x[j+1][i+1],drawCubicRadialObjectSide_y[j+1][i+1],drawCubicRadialObjectSide_z[j+1][i+1]);
//        glColor3f( col *= 0.5, col, col );
        glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j+1][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j+1][i+1])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j+1][i+1])*col );
        glVertex3f( drawCubicRadialObjectSide_x[j+1][i+1], drawCubicRadialObjectSide_y[j+1][i+1], drawCubicRadialObjectSide_z[j+1][i+1] );
        
        col = vector_length(drawCubicRadialObjectSide_x[j+1][i],drawCubicRadialObjectSide_y[j+1][i],drawCubicRadialObjectSide_z[j+1][i]);
//        glColor3f( col *= 0.5, col, col );
        glColor3f( (0.25+0.25*drawCubicRadialObjectSide_x[j+1][i])*col, (0.25+0.25*drawCubicRadialObjectSide_y[j+1][i])*col, (0.25+0.25*drawCubicRadialObjectSide_z[j+1][i])*col );
        glVertex3f( drawCubicRadialObjectSide_x[j+1][i  ], drawCubicRadialObjectSide_y[j+1][i  ], drawCubicRadialObjectSide_z[j+1][i  ] );
      
      glEnd();
    }
  }
  
}





//---- drawRadialObject

//  Draws a radial object using a cubic scheme

void drawRadialObject( double time, GET_RADIALOBJECT_DISTANCE thing_fn )
{
  //- Draw each side of a cube

  drawCubicRadialObjectSide( 0,  1, time, thing_fn );
  drawCubicRadialObjectSide( 0, -1, time, thing_fn );
  drawCubicRadialObjectSide( 1,  1, time, thing_fn );
  drawCubicRadialObjectSide( 1, -1, time, thing_fn );
  drawCubicRadialObjectSide( 2,  1, time, thing_fn );
  drawCubicRadialObjectSide( 2, -1, time, thing_fn );
}
Related Articles

Procedural city block layout

Animated 4-dimensional objects mapped down to 3D

Simulating a cloth falling and slipping over objects

Windows C++ OpenGL example

Games

The Dodge Game
Flatspace

2-Player Games:

Quake 2D
Meteora

Puzzle Games:

Mini Tetris
Sudoku Solver

Development

3D Graphics:

3D Graphics Articles
WebGL Examples
OpenGL Examples
Flash 3D Engine
Java 3D Engine

Development:

Programming Articles
Game Development Examples

Work

Portfolio
Clients
Startups & Projects
Expertise

Links

CubeLogix Studios
PHP Charts & Graphs
Local Legends Football