Tree Generation

Today I found this website about generating trees via Space Colonization: http://www.sea-of-memes.com/LetsCode26/LetsCode26.html
And here is the result in Jmonkey with simple cubes for the position of the branches:

Leave.java
[java]public class Leave {

private Vector3f position;
private Branch closestBranch;

public Leave(Vector3f position)
{
    this.position=position;
}

/**
 * @return the position
 */
public Vector3f getPosition() {
    return position;
}

/**
 * @return the closestBranch
 */
public Branch getClosestBranch() {
    return closestBranch;
}

/**
 * @param closestBranch the closestBranch to set
 */
public void setClosestBranch(Branch closestBranch) {
    this.closestBranch = closestBranch;
}

}[/java]

Branch.java
[java]public class Branch {

private Branch parent;
private Vector3f position;
private Vector3f growDir;
private int growCount;



public Branch(Branch parent, Vector3f position, Vector3f growDir)
{
    this.parent=parent;
    this.position=position;
    this.growDir=growDir;
}

/**
 * @return the parent
 */
public Branch getParent() {
    return parent;
}

/**
 * @return the position
 */
public Vector3f getPosition() {
    return position;
}

/**
 * @return the growDir
 */
public Vector3f getGrowDir() {
    return growDir;
}

/**
 * @return the growCount
 */
public int getGrowCount() {
    return growCount;
}

public void grow(Vector3f v3f) {
    growDir.addLocal(v3f.normalize());
    growCount++;
}

public void reset()
{
    growCount=0;
    growDir = new Vector3f();
}

}[/java]

TreeGenerator.java
[java]public class TreeGenerator {

private float growDist = 3;
private float maxDist = 25;
private float minDist = 5;
private int numberLeaves = 300;
private Vector3f crownFrom = new Vector3f(-50, 50, -50);
private Vector3f crownTo = new Vector3f(50, 150, 50);
private Set<Leave> leaves = new HashSet();
private Set<Branch> branches = new HashSet();
private Branch root;

public void generateTree() {
    generateLeaves();
    Branch branch = generateRoot();
    branches.add(branch);

    
    boolean addedBranches=true;
    
    int skip=0;
    
    while(addedBranches && skip <= 150)
    {
      //  System.out.println("Grow branches");
        growBranches();
      //  System.out.println("Add branches");
        addedBranches=newBranches();
        skip++;
    }
    
    
    while(branch.getParent() != null)
    {
        branch = branch.getParent();
        branches.add(branch);
    }
}


private boolean newBranches()
{
    boolean addedBranches=false;
    
    Set<Branch> newBranches = new HashSet();
    
    for (Branch b : branches) {
        if(b.getGrowCount() > 0)
        {
            Vector3f pos = b.getPosition().add((b.getGrowDir().normalize().mult(growDist)));
            Branch newBranch = new Branch(b, pos, new Vector3f());
            newBranches.add(newBranch);
            
            addedBranches=true;
            
            b.reset();
        }
    }
    
    branches.addAll(newBranches);
    
    return addedBranches;
}

private void growBranches()
{
    Set<Leave> removeLeaves = new HashSet();
    
    for(Leave l : leaves)
    {
        
        Branch closestBranch = null;
        float cloestDist = Float.MAX_VALUE;
        Vector3f dir = null;
        

        for (Branch b : branches) {

            float dist = b.getPosition().distance(l.getPosition());

            if (dist < minDist) {
                removeLeaves.add(l);
                break;
            } else if (dist < maxDist) {
                if (dist < cloestDist) {
                    dir = l.getPosition().subtract(b.getPosition());
                    cloestDist = dist;
                    closestBranch = b;
                }
            }
        }

        if (closestBranch != null) {
            closestBranch.grow(dir);
        }
    } 
    
    for(Leave l : removeLeaves)
    {
        leaves.remove(l);
    }
}



private  Branch generateRoot() {
    


    root = new Branch(null, Vector3f.ZERO, Vector3f.UNIT_Z);
    Branch lastBranch = root;
    float lastDist = Float.POSITIVE_INFINITY;

    while (lastDist >= maxDist) {
        
        
        
        Leave nearestLeave = null;
        float nearestDistance = Float.MAX_VALUE;
         for (Leave l : leaves) {
            float dist = l.getPosition().distance(lastBranch.getPosition());
            if (dist < nearestDistance) {
                nearestDistance = dist;
                nearestLeave = l;
            }
        }
        
        lastDist = nearestDistance;
        
        System.out.println("GROW");
        Branch newBranch = new Branch(lastBranch, lastBranch.getPosition().add(0, growDist, 0), Vector3f.UNIT_Z.clone());
        lastBranch = newBranch;
    }

    return lastBranch;
}



private void generateLeaves() {
    for (int i = 0; i < numberLeaves; i++) {
        float x = crownFrom.x + (float) Math.random() * (crownTo.x-crownFrom.x);
        float y = crownFrom.y + (float) Math.random() * (crownTo.y-crownFrom.y);
        float z = crownFrom.z + (float) Math.random() * (crownTo.z-crownFrom.z);

        leaves.add(new Leave(new Vector3f(x, y, z)));
    }
}


public Branch getRoot()
{
    return root;
}

public Set<Leave> getLeaves()
{
    return leaves;
}

 public Set<Branch> getBranches()
{
    return branches;
}

}[/java]

Main.java
[java]public class Main extends SimpleApplication {

public static void main(String[] args) {
    Main app = new Main();
    app.start();
}

@Override
public void simpleInitApp() {
    
    flyCam.setMoveSpeed(50);
    
    TreeGenerator gen = new TreeGenerator();
    gen.generateTree();
    
    drawBranches(gen.getBranches());
}



public void drawBranches(Set<Branch> branches)
{
    Box box = new Box(Vector3f.ZERO, 0.5f, 0.5f, 0.5f);
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Red);
    

    for(Branch b : branches)
    {
        Geometry geom = new Geometry("Box", box);
        geom.setMaterial(mat);
        geom.setLocalTranslation(b.getPosition());
        
        rootNode.attachChild(geom);
    }   
}



@Override
public void simpleUpdate(float tpf) {
    //TODO: add update code
}

@Override
public void simpleRender(RenderManager rm) {
    //TODO: add render code
}

}[/java]

6 Likes

Ah, now it actually looks like a tree:

3 Likes

cool :slight_smile: I found that site a while ago, and follow some of that guys stuff :slight_smile: