views:

221

answers:

2

I am working on a project to display and animate a tree growing. I am using C++ and OpenGL on this project. The tree grows to a certain number of branches, stops, and then the tree's leaves fall to the ground. I have decided to use Lidenmayer systems to graphically depict this because it seemed an easier alternative to creating a structure and defining each element of the tree. So far I can display the trunk of the tree and the sky, but I am lost as to how to actually get the tree to grow new branches. I considered maybe doing a for loop to control this but I was not sure how to complete it. What would be a good way to deal with this?

My L-System rules:

derivation length: 10 Axiom: F F --> G[-F][+F]GF G --> GG

angle of rotation = 15.0 degrees (.2618 radians)

Update: Here's what I've got so far.

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

int treeSeed = 0;
float branchAngle = .2618;

/*
    Controls the growth of the tree. Factor
    of growth is inverse to that of the ShrinkTree
    method

*/

//void GrowTree()
//{
    /*Tree grows in a direction depending
    on the L-System rules */
//
//   int i;
//   for(i = 0; i <=10 ; i++)
//   {
//    
//    //grow tree
//
//   }

//}

/*
Tree shrinks in a direction depending
on the L-System rules. Factor of shrinkage is 
inverse to that of the GrowTree method.*/

void ShrinkTree()
{
    /*int j;
    for (j = -; j <=10 ; j++)
    {

    }*/

}

//void treeAninmation()
//{
//
//  glutPostRedisplay();
//}


/*
    Draws a leaf on the branch.
    If the seed axiom is at zero,
    a new leaf is drawn. Otherwise,
    the branch shrinks to accomodate
    existing leaves.


*/

void DrawLeaf()
{


    if(treeSeed==0)
    {
     glBegin(GL_QUADS);
     glColor3f(0.0f,1.0f,0.0f);

     glVertex2f(-0.05, -40.5);
     glVertex2f(-0.05, -20.5);
     glVertex2f(-0.02, -40.5); 
     glVertex2f(-0.02,-20.5);

     glEnd();

    }
    /*else
    {

     GrowTree();
     DrawTwig(treeSeed-1);
     glPushMatrix();
       glRotate(branchAngle,1.0f,0.0f,0.0f);
       DrawLeaf(treeSeed-1);
     glPopMatrix();
     glPushMatrix();
       glRotate(branchAngle, );
       DrawLeaf(treeSeed-1);
     glPopMatrix();
    }*/

}


void DrawTwig()
{

    /*

     Draws trunk of tree
     Represents base scenario of
     recursion

    */
    if(treeSeed==0)
    {

     glLineWidth(5.0);

     glBegin(GL_LINE_STRIP);

     glColor3f(0.60f,0.40f,0.12f);

     glVertex2f(-0.10, -80.5);
     glVertex2f(-0.10, -100.5);

     glEnd();

    }

    /*else
    {
     ShrinkTree();
     DrawTwig(treeSeed-1);

    }*/
}



/* Draws the tree with leaves *
    Uses recursion to draw tree structure
    Relies on L-System formula in order
    to produce a tree 

*/

void DrawTree()
{

    DrawTwig(treeSeed);
    //DrawLeaf(treeSeed);


}




/* Draws the horizon, the sky, and the ground*/

void RenderScene(void)
{
    // clears color buffer
    glClear(GL_COLOR_BUFFER_BIT);

    /*
    //GLfloat y;
    GLfloat fSizes[2]; // Store supported line width range
    GLfloat size;  // Store supported line width increments
    */

    //The horizon lies in the xy plane

    glBegin(GL_LINE_STRIP);

    glColor3f(0.0f,0.0f,0.0f); //sets color of horizon to black
    glVertex2f(-135.0,0.0);
    glVertex2f(135.0,0.0);

    glEnd();

    //The sky lies in the xy plane
    //Starts at horizon line,
    //goes upwards to height edge of screen,
    //and goes rightwards to width edge of screen.


    glBegin(GL_QUADS);

    glColor3f(0.0f,0.0f,1.0f);

    glVertex2f(135.0, 0.0);
    glVertex2f(-135.0, 0.0);
    glVertex2f(-135.0, 100.0); 
    glVertex2f(135.0,100.0);


    glEnd();

    DrawTree();

    glFlush();

}


void SetupRC(void)
{

    glClearColor(1.0f,1.0f,1.0f,1.0f);

}


void ChangeSize(GLsizei w, GLsizei h)
{
    GLfloat aspectRatio;

    //prevents divison by zero
    if(h ==0)
     h = 1;

    //set Viewport to window dimensions
    glViewport(0,0,w,h);

    // Reset coordinate system
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Establish clipping volume (left, right,bottom,top,near,far

    aspectRatio = (GLfloat)w/(GLfloat)h;

    if (w <= h)
     glOrtho (-100.0, 100.0, -100/aspectRatio, 100/aspectRatio,1.0,-1.0);
    else
     glOrtho (-100.0 * aspectRatio, 100.0 * aspectRatio, -100.0, 100.0, 1.0, -1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void main(int argc, char **argv)
{
    glutInit(&argc, argv);

/* Testing basic display functions for now */

    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(1000, 1000);
    glutCreateWindow("falling leaves");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    //glutIdleFunc(treeAnimation);
    //glutDisplayFunc(DrawTree);
    SetupRC();   
    glutMainLoop();
}
A: 

I think your trying to solve too many things at once. You are trying to:

  • Build a formal language for evaluating recursive tree structures.
  • Build a method for specifying a tree rule parameterized on "age".
  • Render a given tree rule.

Before you solve this problem in the greatest level of generality I would solve a special case.

  1. Render a tree with hard coded components
  2. Add parameters to your tree to control those components (length of branches, branch count, etc)
  3. Write a function parameterized by "age" that controls the low level tree components.
  4. Write a conversion function from your L system rules to the low level tree parameters
Jonathan Fischoff
A: 

As Jonathan states it looks like your are trying to do too many things at the same time. Typically with L-systems the tree generation is separate to the rendering.

If i understand your rules correctly :

Axiom: F
F --> G[-F][+F]GF
G --> GG

Then your starting tree is:

tree(0): F

i.e the trunk. You grow the tree by making one application of the rules to your tree, which in this case would yield the following:

tree(1): G[-F][+F]GF

Another iteration would grow it further and yield:

tree(2): GG[-G[-F][+F]GF][+G[-F][+F]GF]GGG[-F][+F]GF

and so on.

Typically you would implement this by iterating through the string by character, and for each character that matches a rule append the rule rhs to a target string, otherwise just append the character.

Rendering the tree is done again by iterating through the tree string, this time interpreting it a set of rendering instructions, namely F as move the cursor a unit forward drawing a line, + as rotate cursor left etc.

If you alternately grow the tree by one iteration and then render it, the tree would appear to grow.

So conceptually you might want to start off with a Tree class which encapsulates the axiom, rules etc and the current tree string. This class would know how to grow the tree but not how to render it. So you would also have a renderer class OpenGLRenderer which would handle that. You then have a loop like thus:

while (someFlag)
{
    tree->grow ();
    renderer->render (tree.stringRep ());
}

Mpst of which is just the basics of L-systems, which you may already know, in which case I still don't understand what exactly it is you're asking.

jon hanson