Wow, this is seriously good!
http://rogeralsing.com/2008/12/07/genetic-programming-evolution-of-mona-lisa/
b e n
Wednesday, December 10, 2008
Wednesday, December 3, 2008
Orb code...
Here's the code for the latest version for the spiky orb thing.
b e n
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
b e n
Thursday, November 27, 2008
Another applet embed test...
Here is a simple Processing applet that doesn't use OpenGL. I would be very grateful if somebody could tell me if it appears in the blog with IE on Windows.
Here's the html you'll need to embed an applet:-
<iframe width="482" height="322" frameborder="0" marginwidth="0" marginheight="0" src="http://somewhere-over-the-rainbow/applet/index.html"></iframe>
You'll need somewhere to store your applet though.
Here's the html you'll need to embed an applet:-
<iframe width="482" height="322" frameborder="0" marginwidth="0" marginheight="0" src="http://somewhere-over-the-rainbow/applet/index.html"></iframe>
You'll need somewhere to store your applet though.
Embedding a Processing applet in a blog.
Well I think I've worked out how to embed an applet to show up in a blog. Well it works for me but I'm using Safari on a Mac. Would be great if somebody could tell me if it works on IE on Windows. The applet should appear below. Click and drag mouse to rotate camera, shift drag to zoom in and out.
Oh, I should mention the applet enables OpenGL mode so if it doesn't show up it could be because of that. As a test I'll post another applet which doesn't use OpenGL.
Sunday, November 23, 2008
Well I've started to write some Processing code for Chapter 33. I'm thinking that it might be useful to the reader to have a template project that sets up a 3-d environment ready for experimenting with. This is my first stab at it.
The code draws a grid, marks the origin and draws the x, y and z-axis. It also sets up some lighting. The view can be rotated using the cursor keys but mouse control would be much better... I'll add that in tomorrow. Code needs tidying up too. One thing that might be a bit confusing is that Processing uses a left hand coordinate system whereas OpenGL uses a right hand system. I've added a reflection transform so that the scene uses a right hand system, but I'm wondering if this just confuses things and I should really just stick with Processing's choice.
Here's the code in its rough state:-
import processing.opengl.*;
//
// Spherical coordiantes of camera.
//
float cameraR = 100.0 ;
float cameraPhi = PI / 4 ;
float cameraTheta = 0.0 ;
void setup()
{
//
// Enable OpenGL mode.
//
size(800, 600, OPENGL ) ;
colorMode( RGB, 1 ) ;
}
/**
* Handle a keyboard key press.
* At the moment, cursor keys control the camera.
*/
void keyPressed()
{
if ( key == CODED )
switch( keyCode )
{
case UP :
cameraPhi = cameraPhi > 0.1 ? cameraPhi - 0.01 : 0.1 ;
break ;
case DOWN :
cameraPhi = cameraPhi < PI / 4 - 0.1 ? cameraPhi + 0.01 : PI / 4 - 0.1 ;
break ;
case RIGHT :
cameraTheta = cameraTheta + 0.02 ;
break ;
case LEFT :
cameraTheta = cameraTheta - 0.02 ;
break ;
}
cameraTheta = cameraTheta < 2*PI ? cameraTheta : cameraTheta - 2*PI ;
}
/**
* Draw the scene.
*/
void draw()
{
//
// Initialise the view.
//
background( 0.0 ) ;
setCameraSpherical( cameraR, cameraPhi, -cameraTheta ) ;
//
// Reference page states that in OpenGL mode smooth defaults to on, but that's not the case!
//
smooth() ;
//
// Processing seems to use a left hand coordinate system.
// I prefer right as this is the norm for OpenGL.
//
scale( 1.0, -1.0, 1.0 ) ;
//
// Set up the lighting for the scene.
// This is done early on so that the lighting is fixed relative to the scene.
//
setupLights() ;
//
// Draw the coordinate centre and axis, and a grid.
// This will help when trying to work out the effect of transformations etc.
//
drawAxis( 10.0 ) ;
drawXYGrid( 100.0, 10, 4 ) ;
// cameraTheta += 0.01 ;
}
void setupLights()
{
ambientLight( 0.1, 0.1, 0.1 ) ;
directionalLight( 51.0, 102.0, 126.0, -1.0, -1.0, -1.0 ) ;
}
/**
* 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 ) ;
//
// Need to 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( x, y, z, 0.0, 0.0, 0.0, nx, ny, nz ) ;
endCamera() ;
}
/**
* Draw the unit x, y, z vectors.
*/
void drawAxis( float length )
{
pushMatrix();
//
// Highlight the origin with a white sphere.
//
noStroke() ;
fill( 1.0, 1.0, 1.0 ) ;
sphere( 1.5 ) ;
//
// Draw the x, y and z axis.
// The axis are actually drawn as unit length lines
// and we make use of a scaling transform to get them to the desired length.
//
scale( length, length, length ) ;
strokeWeight( 2 ) ;
beginShape( LINES ) ;
//
// x-axis in red.
//
stroke( 1.0, 0.0, 0.0 ) ;
vertex( 0.0, 0.0, 0.0 ) ;
vertex( 1.0, 0.0, 0.0 ) ;
//
// y-axis in green.
//
stroke( 0.0, 1.0, 0.0 ) ;
vertex( 0.0, 0.0, 0.0 ) ;
vertex( 0.0, 1.0, 0.0 ) ;
//
// z-axis in blue.
//
stroke( 0.0, 0.0, 1.0 ) ;
vertex( 0.0, 0.0, 0.0 ) ;
vertex( 0.0, 0.0, 1.0 ) ;
endShape() ;
popMatrix() ;
}
/**
* Draw a grid in the x-y plane.
*/
void drawXYGrid( float scale, int divisions, int minorDivisions )
{
pushMatrix();
scale( scale, scale, 0 ) ;
translate( -0.5, -0.5, 0 ) ;
noFill() ;
strokeWeight( 1 ) ;
float dw = 1.0 / divisions ;
float dm = dw / minorDivisions ;
beginShape( LINES ) ;
for ( int i = 0 ; i <= divisions ; ++i )
{
//
// Draw the minor divisions
//
strokeWeight( 0.5 ) ;
stroke( 0.6, 0.6, 0.6 ) ;
if ( i < divisions )
for ( int j = 1 ; j < minorDivisions ; ++j )
{
vertex( 0, i*dw + j*dm, 0 ) ;
vertex( 1, i*dw + j*dm, 0 ) ;
vertex( i*dw + j*dm, 0, 0 ) ;
vertex( i*dw + j*dm, 1, 0 ) ;
}
if ( i == divisions / 2 )
stroke( 0.9, 0.9, 0.9 ) ;
else
stroke( 0.8, 0.8, 0.8 ) ;
strokeWeight( 1.0 ) ;
vertex( 0, i*dw, 0 ) ;
vertex( 1, i*dw, 0 ) ;
vertex( i*dw, 0, 0 ) ;
vertex( i*dw, 1, 0 ) ;
}
endShape() ;
popMatrix();
}
Tuesday, October 21, 2008
Thursday, October 16, 2008
Subscribe to:
Posts (Atom)