Wednesday, December 10, 2008

Mona Lisa in 50 polygons!

Wow, this is seriously good!

http://rogeralsing.com/2008/12/07/genetic-programming-evolution-of-mona-lisa/

b e n

Wednesday, December 3, 2008

Orb code...

Here's the code for the latest version for the spiky orb thing.



b e n




import javax.media.opengl.* ;
import processing.opengl.* ;


//
// Scalar to convert from degrees to radians.
//
final float PI_DIV_180 = PI / 180.0 ;

//
// Switch to control lighting.
// Lights initially off.
//
boolean gLights = false ;

//
// Spherical coordinates of camera.
//
float gCameraR = 130.0 ;
float gCameraPhi = PI / 4 ;
float gCameraTheta = 0.0 ;

//
// Frame counter.
//
float gFrame = 0.0 ;

//
// The orb's current rotation and history.
//
float gBallTheta = 0.0f ;
float gBallPhi = 0.0f ;

RotationHistory gRotationHistory = new RotationHistory( 200 ) ;


/**
* Keyboard controller.
*
* Press a key to change something:-
*
* l - turns lights on/off
*/
void keyPressed()
{
switch ( key )
{
case 'l' :
gLights = ! gLights ;
break ;
}
}

//
// Usual set up.
//
void setup()
{
//
// Enable OpenGL mode.
//
size( 800, 600, OPENGL ) ;
hint( DISABLE_OPENGL_ERROR_REPORT ) ;

//
// Set up the drawing environment.
//
colorMode( RGB, 1 ) ;
background( 0.0 ) ;
smooth() ;
}

void draw()
{
//
// Update the camera.
//
// Currently, the orb is kept at the origin and the camera swoops in and out.
//
gCameraR = 180.0 + ( sin( gFrame/50.0 ) + cos( gFrame / 57 ) ) * 25 ;

//
// Update the animation.
//
// gFrame is the frame counter and is used to animate various parts of the orb.
//
gFrame += 1.0 ;

//
// The orb spins round the origin.
//
gBallTheta += 2.0 * sin( gFrame/53.0 ) ;
gBallPhi += 2.0 * sin( gFrame/83.0 ) ;

//
// The orb's rotation is recorded and used to animate the wavy hairs/dendrites.
//
gRotationHistory.push( gBallTheta, gBallPhi ) ;

//
// Initialise the background.
//
background( 0.0 ) ;
drawStars( 1000, 800, 600 ) ;

//
// Initialsie the camera.
//
setCameraSpherical( gCameraR, gCameraPhi, -gCameraTheta ) ;

//
// Draw the orb.
//
// Keep the same sequence of random numbers from frame to frame.
//
randomSeed( 0 ) ;

//
// Some magic numbers.
//
int numberOfHairs = 10000 ;
float bodyR = 25.0 ;
float minHairLength = 24.0 ;
float shortHairLength = 30.0 ;
float longHairLength = 10.0 ;
float longHairMaxLength = 30.0 ;
float longDendriteLength = 20.0 ;
float longDendriteMaxLength = 60.0 ;

//
// Set up a couple of spinning light sources for the body.
//
float cr = 0.0 ;

if ( gLights )
{
cr = 1.0 ;

lights();

float x = sin( gFrame/30.0) ;
float y = sin( gFrame/37.0) ;
float z = sin( gFrame/43.0) ;

directionalLight( 1.0, 1.0, 1.0, x, y, z );
directionalLight( 0.3, 0.3, 0.3, -x, -y, -z );
}
else
{
cr = 0.0 ;

noLights() ;
}

//
// Draw the body/sphere in the same colour as the hairs.
//
drawBody( bodyR, cr * 1., cr * 0.4, cr * 0.1, 1.0 ) ;

//
// Set up OpenGL for drawing.
//
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; // g may change
GL gl = pgl.beginGL();

gl.glEnable( gl.GL_BLEND ) ;
gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA ) ;

drawSpikes( gl, 30, bodyR, longHairLength, longHairMaxLength, bodyR + 0.5 ) ;
drawDendrites( gl, 15, bodyR, longDendriteLength, longDendriteMaxLength, bodyR + 0.5 ) ;
drawFurr( gl, 10000, minHairLength, shortHairLength ) ;

pgl.endGL() ;
}

/**
* Draw dendrites.
* These are the long thin, multi-coloured lines.
*
* Note, at the moment dendrites are regenerated on each frame - not very efficient!!!
*/
void drawDendrites( GL gl, int count, float br, float l1, float l2, float p1 )
{
for ( int i = 0 ; i < count ; ++ i )
{
//
// Calculate a random length and position for the dendrite.
//
float length = random( l1, l2 ) ;
float theta = random( 0.0, 360.0 ) ;
float phi = random( 0.0, 180.0 ) ;

gl.glPushMatrix() ;
gRotationHistory.record( 0 ).draw( gl ) ;
drawPatch( gl, br+0.1, theta, phi, 4, 16 ) ;
gl.glPopMatrix() ;

color c1 = color( abs( sin( gFrame /100.0 ) ), abs( sin( gFrame /123.0 ) ), abs( sin( gFrame /176.0 ) ), 1.0 ) ;
color c2 = color( abs( sin( gFrame /57.0 ) ), abs( sin( gFrame /23.0 ) ), abs( sin( gFrame /67.0 ) ), 0.0) ;

//
// Use a hair class to do the drawing.
//
Hair hair = new Hair( length*2, br, theta + random( 1.0 ), phi + random( 1.0 ), c1, c2, 1.0 ) ;
hair.draw( gl ) ;
}
}

/**
* Draw the long spikes.
*
* The spikes are the thick orange things.
*
* Note, at the moment spikes and patches are regenerated on each frame - not very efficient!!!
*
* @param gl the OpenGL context
* @param count the number of spikes to draw
* @param br the radius of the orb body/sphere
* @param l1 the minimum length of a spike
* @param l2 the mximum length of a spike
* @Param p1 the angular radius of the patch at the base of each spike
*/
void drawSpikes( GL gl, int count, float br, float l1, float l2, float p1 )
{
//
// Draw each spike in turn.
//
for ( int i = 0 ; i < count ; ++ i )
{
//
// Calculate a random position for the spike.
//
float theta = random( 0.0, 360.0 ) ;
float phi = random( 0.0, 180.0 ) ;

//
// Draw an ornage patch at the base of the spike.
//
gl.glPushMatrix() ;

gRotationHistory.record( 0 ).draw( gl ) ;
drawPatch( gl, br+0.1, theta, phi, 4, 16 ) ;

gl.glPopMatrix() ;

//
// The length of the spike is between l1 and l2.
//
float length = random( l1, l2 ) ;

//
// Draw the spike.
// Spikes get their thickness from being composed of many hairs.
//
for ( int j = 0 ; j < 10 ; ++j )
{
//
// Draw this hair at a random length.
//
float l = j == 9 ? length : random( l1, length ) ;

Hair hair = new Hair( l, br, theta + random( 1.0 ), phi + random( 1.0 ), color( 1.0, 1.0, 1.0, 1.0 ), color( 1.0, 0.4, 0.1, 0.1 ), 1.0 ) ;
hair.draw( gl ) ;
}
}
}

/**
* Draw the furry bits.
* @param gl the OpenGL context
* @param count the number of furr hairs
* @param r1 the minimum length of the furr
* @param r2 the mximum length of the furr
*/
void drawFurr( GL gl, int count, float r1, float r2 )
{
gl.glPushMatrix() ;

gRotationHistory.record( 0 ).draw( gl ) ;

float PI_DIV_180 = PI / 180.0 ;

gl.glBegin( gl.GL_LINES ) ;

for ( int i = 0 ; i < count ; ++ i )
{
//
// Calculate a random position for the furr hair.
//
float theta = random( 360.0 ) ;
float phi = random( 180.0 ) ;

float x1 = cos( theta * PI_DIV_180 )*sin( phi * PI_DIV_180 ) ;
float y1 = sin( theta * PI_DIV_180 ) * sin( phi * PI_DIV_180 ) ;
float z1 = cos( phi * PI_DIV_180 ) ;

//
// Randomise the length of the furr.
//
float r = r1 + ( r2 - r1 ) * random( 1.0 ) ;

//
// Choose a colour for the furr.
//
float c1 = 1.0f ;
float c2 = 1.0f ; //0.4f ;

//
// Furr is drawn semi-opaque at the base and transparent at the tip.
//
gl.glColor4f( c1, c1, c1, 0.5 ) ;
gl.glVertex3f( x1 *r1 , y1*r1, z1*r1 ) ;


gl.glColor4f( c2, c2, c2, 0.0) ;
gl.glVertex3f( x1*r, y1*r, z1*r ) ;
}

gl.glEnd() ;

gl.glPopMatrix() ;

}

/**
* Draw the black sphere.
* The sphere is used to hide any background geometry.
* Note, at the moment the animated 'orb' is alwaysdrawn at the origin.
* @param r the radius of the sphere
* @param alpha the alpha value to draw the sphere with
*/
void drawBody( float r, float red, float green, float blue, float alpha )
{
noStroke() ;
fill( red, green, blue, alpha ) ;

sphere( r ) ;
}

/**
* Set up the camera using spherical coordinates.
* @param r the distance from the pov to the camera
* @param phi the polar angle with the z-axis
* @param theta the azimuthal angle in the x/y-plane
*/
void setCameraSpherical( float r, float phi, float theta )
{
//
// Work out the x/y-z-coordinates of the camera.
//
float x = r * cos( theta )*sin( phi ) ;
float y = r * sin( theta ) * sin( phi ) ;
float z = r * cos( phi ) ;

//
// Work out the up vector.
// This is simply the image of the point ( 1, 0, 0 ) under the
// the given spherical map.
//
float nx = cos( theta ) * cos( phi ) ;
float ny = sin( theta ) * cos( phi ) ;
float nz = - sin( phi ) ;

// beginCamera() ;
// camera() ;
camera( x, y, z, 0.0, 0.0, 0.0, nx, ny, nz ) ;
// endCamera() ;
}

/**
* Draw a 'circular' patch on the surfce of the orb.
* @param gl the current gl context
* @param r the r-coordinate of the patch
* @param theta the azimuth angle of the centre of the patch, in degrees
* @param phi the altitude andgle of the centre of the patch, in degrees
* @param ar the angular radius of the patch in degrees
* @param smoothness the number of segments to draw the patch with
*/
void drawPatch( GL gl, float r, float theta, float phi, float ar, int smoothness )
{
//
// Draw a patch at the zenith and use a transform to get it in the right place.
//
gl.glPushMatrix() ;

gl.glRotatef( theta, 0.0, 0.0, 1.0 ) ;
gl.glRotatef( phi, 0.0, 1.0, 0.0 ) ;

gl.glBegin( gl.GL_TRIANGLE_FAN ) ;

//
// Draw the patch - it will be shaped like an umbrella.
//
float x = r * sin( ar * PI_DIV_180 ) ;
float z = r * cos( ar * PI_DIV_180 ) ;

gl.glColor4f( 1.0, 1.0, 1.0, 1.0 ) ;
gl.glVertex3f( 0.0, 0.0, r ) ;

gl.glColor4f( 1.0, 0.0, 0.0, 0.0 ) ;

for ( float i = 0.0 ; i <= smoothness ; ++i )
gl.glVertex3f( x * cos( TWO_PI * i / smoothness ), x * sin( TWO_PI * i / smoothness ), z ) ;

gl.glEnd() ;

gl.glPopMatrix() ;

}


void drawStars( int count, float width, float height )
{
//
// fill( 1.0 ) ;
// stroke( 1.0 ) ;
//
// beginShape( POINTS ) ;
//
// for ( int i = 0 ; i < count ; ++ i )
// vertex( random( width ), random( height ), -50 ) ;
//
// endShape() ;
}

/********************************************************************************************************************************************************************/

/********************************************************************************************************************************************************************/

/**
* Class hair.
* Represents a hair by length, position and colour.
*/
class Hair
{
//
// The length of the hair.
//
float length ;

//
// The start point of the hair.
//
float r, theta, phi ;

//
// The start and end point colours of the hair.
//
float r1, g1, b1, a1 ;
float r2, g2, b2, a2 ;

//
// How smooth to draw the hair.
//
int sections ;

/**
* Default constructor is hidden - use the full constructor.
*/
private Hair()
{
}

/**
* Constructor initialised with position, length, colour and smoothness.
* @param length the lenght of the hair
* @param r the r-coordiante to the root of the hair
* @param theta the azimuth angle of the hair
* @param phi the altitude angle of the hair
* @param c1 the start point colour of the hair
* @param c2 the end point colour of the hair
* @param smoothness how smooth to draw the hair
*/
public Hair( float length, float r, float theta, float phi, color c1, color c2, float smoothness )
{

this.length = length ;

this.r = r ;
this.theta = theta * PI_DIV_180 ;
this.phi = phi * PI_DIV_180 ;

r1 = red( c1 ) ;
g1 = green( c1 ) ;
b1 = blue( c1 ) ;
a1 = alpha( c1 ) ;

r2 = red( c2 ) ;
g2 = green( c2 ) ;
b2 = blue( c2 ) ;
a2 = alpha( c2 ) ;

this.sections = round( length / smoothness ) ;

//
// this.x1 = length *cos( theta )*sin( phi ) ;
// this.y1 = length * sin( theta ) * sin( phi ) ;
// this.z1 = length * cos( phi ) ;
}

/**
* Draw the hair.
* The hair is drawn in sections. The number of sections is defined by
* the hair's smoothness attribute.
* @param gl the current OpenGL context
*/
public void draw( GL gl )
{
gl.glPushMatrix() ;

//
// The hair is drawn in sections.
//
gl.glBegin( gl.GL_LINE_STRIP ) ;

for ( int i = 0 ; i <= sections ; ++i )
{
//
// Calculate the fractional position along the hair of this vertex.
//
float dh = float( i ) / float( sections ) ;

//
// Work out the coordinates of the vertex.
//
float h = r + length * dh ;
float x = h * cos( this.theta ) * sin( this.phi ) ;
float y = h * sin( this.theta ) * sin( this.phi ) ;
float z = h * cos( this.phi ) ;

//
// Rotate the vertex by the position of the ball at i frames ago.
//
float theta = gRotationHistory.record( -i ).getTheta() * PI_DIV_180 ;
float phi = gRotationHistory.record( -i ).getPhi() * PI_DIV_180 ;

float x1= x * cos( phi ) + z * sin( phi ) ;
float y1 = y ;
float z1 = - x * sin( phi ) + z * cos( phi ) ;

x = x1 * cos( theta ) - y1 * sin( theta ) ;
y = x1 * sin( theta ) + y1 * cos( theta ) ;
z = z1 ;

//
// Calculate the colour of the vertex by interpolating between the start
// and end colours of the hair.
//
gl.glColor4f( r1 + ( r2 - r1 ) * dh, g1 + ( g2 - g1 ) * dh, b1 + ( b2 - b1 ) * dh, a1 + ( a2 - a1 ) * dh ) ;

//
// Draw the vertx, it will form the start/end of a line segment.
//
gl.glVertex3f( x, y, z ) ;
}

gl.glEnd() ;

gl.glPopMatrix() ;
}

}

/********************************************************************************************************************************************************************/

/********************************************************************************************************************************************************************/

/**
* Class RotationHistory
* This class is used to record the position/coordiantes of the sphere during animation.
* The last 'n' frames of animation are stored.
*/
class RotationHistory
{
//
// How deep the history buffer is.
//
int historyDepth = 0 ;
RotationRecord[] history = new RotationRecord[ 0 ] ;

//
// The current frame counter.
//
int frame = 0 ;

/**
* Default constructor initialises the animator with a history level of 10.
*/
public RotationHistory()
{
historyDepth = 100 ;
history = new RotationRecord[ historyDepth ] ;

frame = 0 ;

//
// Initialise the history to a static case.
//
for ( int i = 0 ; i < historyDepth ; ++i )
history[ i ] = new RotationRecord() ;
}

/**
* Constructor initialised with a history depth.
* @param depth how deep the history buffer is
*/
public RotationHistory( int depth )
{
historyDepth = depth ;
history = new RotationRecord[ depth ] ;

frame = 0 ;

//
// Initialise the history to a static case.
//
for ( int i = 0 ; i < historyDepth ; ++i )
history[ i ] = new RotationRecord() ;
}

/**
* Push a new rotation record into the history.
* The oldest record is lost.
* @param theta the azimuth angle
* @param phi the altitude angle
*/
public void push( float theta, float phi )
{
frame++ ;

history[ frame % historyDepth ] = new RotationRecord( theta, phi ) ;
}


/**
* Get a history record.
* @param index the history index, 0 = current, -1 = previous record etc
* @return the history rotation record
*/
public RotationRecord record( int index )
{
return history[ abs( frame + index ) % historyDepth ] ;
}

}

/********************************************************************************************************************************************************************/

/********************************************************************************************************************************************************************/

/**
* Class RotationRecord.
* Used to store the azimuth and altitude angles of rotation.
*/
class RotationRecord
{
//
// The rotation angles.
//
float theta ;
float phi ;

/**
* Default constructor initialised with zero rotation.
*/
public RotationRecord()
{
theta = 0.0 ;
phi = 0.0 ;
}

/**
* Constructed initialised with rotation angles theta and phi.
* @param theta the azimuth angle
* @param phi the altitude angle
*/
public RotationRecord( float theta, float phi )
{
this.theta = theta ;
this.phi = phi ;
}

/**
* Accessor to the orientation angle theta.
* @return the value of rotation angle theta
*/
public float getTheta()
{
return theta ;
}

/**
* Accessor to the orientation angle phi.
* @return the value of rotation angle phi
*/
public float getPhi()
{
return phi ;
}

/**
* Draw the rotation as a transform.
* @param gl the current OpenGL context
*/
public void draw( GL gl )
{
gl.glRotatef( theta, 0.0, 0.0, 1.0 ) ;
gl.glRotatef( phi, 0.0, 1.0, 0.0 ) ;
}
}

Monday, December 1, 2008

I think I went a bit over the top

I tried to come up with a demo of Processing and OpenGL at the weekend. It started off simple but then it went a bit ott!



b e n