Nick
2006.07.26, 02:43 PM
I don't know if this algorithm/technique has been used before, but I'm having trouble figuring out how to control the growth more. I figured out how to draw it and have it create the basic tree, but my trees are definitely no where near real looking. I tried to use the current generation to help reduce things like branch divisions and branch lengths, but I still get some awkwardly long looking branches.
Can anyone take a look at this and offer any suggestions as to how to control the tree's growth more? Here's the full code. Just compile it in terminal and run from there. It needs to be linked with the GLUT, OpenGL, and Cocoa frameworks.
//g++ trees.cpp -o trees -framework GLUT -framework OpenGL -framework Cocoa
#include <GLUT/glut.h>
#include <OpenGL/OpenGL.h>
#include <stdio.h>
#include <list.h>
#include <math.h>
#include <time.h>
class Node
{
public:
Node( void ):mNext( NULL ) {}
~Node( void )
{
std::list< Node* >::iterator itr;
for ( itr = mChildren.begin(); itr != mChildren.end(); ++itr )
delete ( *itr );
if ( mNext )
delete mNext;
}
void draw( void )
{
glRotatef( mYaw, 0, 1, 0 );
glRotatef( mPitch, 0, 0, 1 );
glBegin( GL_LINES );
glColor3f( mR, mG, mB );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, mLength, 0 );
glEnd();
glTranslatef( 0, mLength, 0 );
if ( !mChildren.empty() )
{
std::list< Node* >::iterator itr;
for ( itr = mChildren.begin(); itr != mChildren.end(); ++itr )
{
glPushMatrix();
( *itr )->draw();
glPopMatrix();
}
}
if ( mNext )
mNext->draw();
}
float mLength;
float mPitch, mYaw;
float mR, mG, mB;
std::list< Node* > mChildren;
Node *mNext;
};
// Global Variables
Node *gRoot = NULL;
float gYaw = 0.0f; //make the tree spin
int gNumDivisions = 5; //number of divisions in each branch
#define MAX_GENERATIONS 3
#define MIN_LENGTH 0.5f
#define MAX_LENGTH 1.0f
#define MIN_PITCH -5.0f
#define MAX_PITCH 5.0f
#define MIN_CHILD_PITCH_ADJUST 45.0f
#define MAX_CHILD_PITCH_ADJUST 60.0f
// End Global Variables
//simply wrapping the random function
float randFloat( float min, float max )
{
if ( max <= min )
return max;
float newRand = ( float )( rand() % ( int )( max * 100 ) );
newRand *= 0.01f;
newRand += min;
return newRand;
}
Node* generateNode( float length, float pitch, float yaw, int division, int numChildren, int generation )
{
Node *newNode = new Node;
newNode->mLength = length;
newNode->mPitch = pitch;
newNode->mYaw = yaw;
newNode->mR = randFloat( .3, 1 );
newNode->mG = randFloat( .3, 1 );
newNode->mB = randFloat( .3, 1 );
if ( division > 0 )
{
newNode->mNext = generateNode( randFloat( MIN_LENGTH, MAX_LENGTH ), randFloat( MIN_PITCH, MAX_PITCH ), randFloat( 0.0f, 360.0f ), division - 1, numChildren, generation );
if ( generation <= MAX_GENERATIONS )
{
for ( int i = 0; i < numChildren; i++ )
{
newNode->mChildren.push_back( generateNode( randFloat( MIN_LENGTH / ( float )generation, MAX_LENGTH / ( float )generation ), randFloat( MIN_PITCH, MAX_PITCH ) + randFloat( MIN_CHILD_PITCH_ADJUST, MAX_CHILD_PITCH_ADJUST ), randFloat( 0.0f, 360.0f ), gNumDivisions / ( generation + 1 ), numChildren, generation + 1 ) );
}
}
}
return newNode;
}
bool generateTree( void )
{
srand( time( NULL ) );
gRoot = generateNode( 1, 0, 0, gNumDivisions, 1, 1 );
return true;
}
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
glTranslatef( 0, -3, -10 );
glRotatef( gYaw, 0, 1, 0 );
gYaw += .1f;
if ( gYaw > 360 )
gYaw -= 360;
glColor3f( 0, 1, 0 );
gRoot->draw();
glutSwapBuffers();
}
void reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0f, (float)width / (float)height, .01f, 1000.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
void idle( void )
{
glutPostRedisplay();
}
int main( int argc, char *argv[] )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 800, 600 );
glutCreateWindow( "Tree Generation" );
glutDisplayFunc( display );
glutReshapeFunc( reshape );
glutIdleFunc( idle );
glEnable( GL_LINE_SMOOTH );
glEnable( GL_DEPTH_FUNC );
if ( !generateTree() )
{
delete gRoot;
return -1;
}
glutMainLoop();
delete gRoot;
return 0;
}
Can anyone take a look at this and offer any suggestions as to how to control the tree's growth more? Here's the full code. Just compile it in terminal and run from there. It needs to be linked with the GLUT, OpenGL, and Cocoa frameworks.
//g++ trees.cpp -o trees -framework GLUT -framework OpenGL -framework Cocoa
#include <GLUT/glut.h>
#include <OpenGL/OpenGL.h>
#include <stdio.h>
#include <list.h>
#include <math.h>
#include <time.h>
class Node
{
public:
Node( void ):mNext( NULL ) {}
~Node( void )
{
std::list< Node* >::iterator itr;
for ( itr = mChildren.begin(); itr != mChildren.end(); ++itr )
delete ( *itr );
if ( mNext )
delete mNext;
}
void draw( void )
{
glRotatef( mYaw, 0, 1, 0 );
glRotatef( mPitch, 0, 0, 1 );
glBegin( GL_LINES );
glColor3f( mR, mG, mB );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, mLength, 0 );
glEnd();
glTranslatef( 0, mLength, 0 );
if ( !mChildren.empty() )
{
std::list< Node* >::iterator itr;
for ( itr = mChildren.begin(); itr != mChildren.end(); ++itr )
{
glPushMatrix();
( *itr )->draw();
glPopMatrix();
}
}
if ( mNext )
mNext->draw();
}
float mLength;
float mPitch, mYaw;
float mR, mG, mB;
std::list< Node* > mChildren;
Node *mNext;
};
// Global Variables
Node *gRoot = NULL;
float gYaw = 0.0f; //make the tree spin
int gNumDivisions = 5; //number of divisions in each branch
#define MAX_GENERATIONS 3
#define MIN_LENGTH 0.5f
#define MAX_LENGTH 1.0f
#define MIN_PITCH -5.0f
#define MAX_PITCH 5.0f
#define MIN_CHILD_PITCH_ADJUST 45.0f
#define MAX_CHILD_PITCH_ADJUST 60.0f
// End Global Variables
//simply wrapping the random function
float randFloat( float min, float max )
{
if ( max <= min )
return max;
float newRand = ( float )( rand() % ( int )( max * 100 ) );
newRand *= 0.01f;
newRand += min;
return newRand;
}
Node* generateNode( float length, float pitch, float yaw, int division, int numChildren, int generation )
{
Node *newNode = new Node;
newNode->mLength = length;
newNode->mPitch = pitch;
newNode->mYaw = yaw;
newNode->mR = randFloat( .3, 1 );
newNode->mG = randFloat( .3, 1 );
newNode->mB = randFloat( .3, 1 );
if ( division > 0 )
{
newNode->mNext = generateNode( randFloat( MIN_LENGTH, MAX_LENGTH ), randFloat( MIN_PITCH, MAX_PITCH ), randFloat( 0.0f, 360.0f ), division - 1, numChildren, generation );
if ( generation <= MAX_GENERATIONS )
{
for ( int i = 0; i < numChildren; i++ )
{
newNode->mChildren.push_back( generateNode( randFloat( MIN_LENGTH / ( float )generation, MAX_LENGTH / ( float )generation ), randFloat( MIN_PITCH, MAX_PITCH ) + randFloat( MIN_CHILD_PITCH_ADJUST, MAX_CHILD_PITCH_ADJUST ), randFloat( 0.0f, 360.0f ), gNumDivisions / ( generation + 1 ), numChildren, generation + 1 ) );
}
}
}
return newNode;
}
bool generateTree( void )
{
srand( time( NULL ) );
gRoot = generateNode( 1, 0, 0, gNumDivisions, 1, 1 );
return true;
}
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
glTranslatef( 0, -3, -10 );
glRotatef( gYaw, 0, 1, 0 );
gYaw += .1f;
if ( gYaw > 360 )
gYaw -= 360;
glColor3f( 0, 1, 0 );
gRoot->draw();
glutSwapBuffers();
}
void reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0f, (float)width / (float)height, .01f, 1000.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
void idle( void )
{
glutPostRedisplay();
}
int main( int argc, char *argv[] )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 800, 600 );
glutCreateWindow( "Tree Generation" );
glutDisplayFunc( display );
glutReshapeFunc( reshape );
glutIdleFunc( idle );
glEnable( GL_LINE_SMOOTH );
glEnable( GL_DEPTH_FUNC );
if ( !generateTree() )
{
delete gRoot;
return -1;
}
glutMainLoop();
delete gRoot;
return 0;
}