**Report: Trees** Ben Drews, Diego Gonzalez, Lylia Li bfd2@williams.edu drg4@williams.edu ll5@williams.edu ![Only in computer graphics does one tree beget a forest. [#glDev] [#UVQ] ](evocativeScene.jpg) Introduction ================================== Our program procedurally generates tree models that are composed of cylinders connected to each other, with texture-mapped bark and leaves. Users can choose to generate trees using an L-system generation algorithm or a space colonization generation algorithm. Trees of different shapes and sizes can be generated by changing various parameters. Within the L-system generation algorithm, users can vary the recursion depth, initial height, number of circle points within each cylinder, number of branch sections, phenotype, and branch callback function of their trees. There is also an option to generate “autumn” trees with leaves that are red, orange, and yellow instead of green. Within the space colonization algorithm, users can vary the number of anchor points, height, radius, number of circle points within each cylinder, tree node distance, kill distance, branch initial radius, radius growth, attraction radius, leafiness, and discount rate of their trees. With all the different parameter options, a near infinite number of unique trees can be generated. Users have the additional option to generate an orchard with the tree models they create and grow different "fruit" from the trees. Specification ================================== **Features of the program:** 1. A user interface with the following tabs: 1. L-system tab 1. Recursion depth: Number of levels of recursion we will take our L-system through 2. Initial height of tree 3. Circle points: How round the cylinders that make up the tree will be 4. Branch sections: How many cylindric sections are added to each branch 5. Phenotype: What type of tree is generated 6. Generate button to run the program 2. Space colonization tab 1. Anchor count: Number of initial anchor points 2. Height: Total height of the tree 3. Radius: Radius of the area the anchor points will be generated in 4. Circle points: How round the cylinders that make up the tree will be 5. Distance between tree nodes 6. Kill distance for anchor nodes 7. Initial branch tip radius: Each branch radius is defined by the radii of its children, so we add a parameter to specify the radius of a branch with no children 8. Branch radius growth factor: Specific constant in definition of branch radius used by space colonization algorithm; higher constants lead to slower growth 9. Attraction radius: Radius within which anchor points can attract nodes 10. Leafiness 11. Generate button to run the program 3. Orchard tab 1. Number of rows in the orchard 2. Trees per row of orchard 3. Generation type: Whether we are using L-system or space colonization trees 4. Fruit type: Drop down list to choose which fruit the tree grows 5. Generate button to run the program 2. In all tabs, when the "Generate" button is pressed, the program: 1. Immediately displays a waiting screen 2. Generates a tree/orchard with the specificed parameters 3. Saves the generated model/scene to a file and loads the scene 3. L-system tree generation entry points 1. method `App::makeLSkeleton()`: Generates a tree skeleton based on an L-system, with the parameters specified in the GUI 2. method `App::skeletonToMeshL`: Converts the generated tree skeleton to an OBJ mesh 4. Space colonization tree generation entry points 1. method `App::makeSCSkeleton()`: Generates a tree skeleton based on the space colonization algorithm, with the parameters specified in the GUI 2. method `App::skeletonToMeshSC`: Converts the generated tree skeleton to an OBJ mesh 5. Orchard generation entry points 1. method `App::generateOrchard()`: Generates a Scene.Any file containing an orchard of fruit trees with the parameters specified in the GUI **Program evaluation metric:** - Graph of the time it took to generate an L-system tree model with normal phenotype, straight spine curve, 5 cirlce points, and 1 branch section versus recursion depth:  - Graph of the time it took to generate a space colonization tree model versus the number of anchor points used:  - Graph of the time it took to generate a space colonization tree model versus the tree node distance:  - Graph of the time it took to generate a space colonization tree model versus the kill distance:  - Graph of the time it took to generate a space colonization tree model versus the discount rate:  Topic Overview ================================== **Tree Generation using L-Systems** L-systems provide an easy way to generate plantlike structures. Nature often encorporates fractal patterns in how plants grow and branch, which translates easily into recursive method calls which mirror such growth on a mesh (1). ![Fractals in Nature [#Wikipedia]](plantFractal.jpg width=800) In order to set up this generation, a set of simple recusive rules must be written. These generally replace or grow a set of smaller branches off of a parent branch, and can be applied repeatedly to get increasingly detailed results. [#Wikipedia] ![Products of L-Systems [#Wikipedia]](L-SystemProducts.jpg width=800) **Tree Generation using Space Colonization** Space Colonization is an algorithm that attempts to model the competition by branches for space on a tree in its generation. It does a better job than L-Systems at modeling mature trees, since as plant mature, the factors limiting their growth start to weigh more heavily on how branches are placed than the factors creating opportunites for growth (2). ![Tree generated with Space Colonization [#Runions]](SpaceColonizationTree.jpg width=800) The algorithm works by randomly seeding a volume with anchor points, which pull on tree nodes, spawning adjacent tree nodes in the average direction of the anchor points pulling on that node. Once a tree node gets too close to an anchor node, than anchor is destroyed. This process repeats until all anchors are destroyed. [#Runions] ![Space Colonization Iteration [#Runions] ](SpaceColIter.jpg width=400) Design ==================================  **Major functions of App** Function | Description ---------------------|------------------------------------------------------------ makeLTree | Creates Meshes for a tree and the leaves of the tree, constructs an LGenerator to create the skeleton of the tree and write the skeleton to an OBJ file, handles logic of passing the right phenotype and branch callback function based on chosen parameters in GUI generateOrchard | Generates and displays a Scene.Any file of multiple fruit trees based on the parameters in GUI customOrchard | Generates the orchard used for our quality image generateForest | Generates the forest used for our quality image **Major functions of LGenerator** Function | Description ---------------------|------------------------------------------------------------ [makeLTreeSkeleton](../build/doc/class_l_generator.html#aa89c792dda28ee0307de9278ec2bc315) | Makes a tree skeleton out of an L-system, defining where tree nodes are located [skeletonToMeshL](../build/doc/class_l_generator.html#ab79bbb355f23f667839a375ab82eeb42) | Takes tree skeleton produced by makeLTreeSkeleton and writes it to a Mesh class [addLeaf / addLeaves](../build/doc/class_l_generator.html#a7bdf8b4a1060d5202c3d35dbc40b09e5) | Given a Mesh, adds two-sided triangle(s) to the Mesh [addFruits](../build/doc/class_l_generator.html#a600be256c3b3dded835102116ba22c8b) | Populates an array with Point3 locations of where fruits should be added in relation to the CoordinateFrame of the base of a tree [addCylindricSection](../build/doc/class_l_generator.html#ac540c72687ca77db7863cc1fab817b62) | Given a Mesh and an initial circle, adds an additional circle to the mesh underneath the initial circle and adds faces between the circles **Major functions of SCGenerator** Function | Description ---------------------|------------------------------------------------------------ [makeSCTreeSkeleton](../build/doc/class_s_c_generator.html#a407dce858717c9f41662cee510ef8ce9) | Makes a tree skeleton using the space colonization algorithm [skeletonToMeshSC](../build/doc/class_s_c_generator.html#ab67dbb1f8bf279b1e747622f1330e2b0) | Takes tree skeleton produced by makeSCTreeSkeleton and writes it to a Mesh class [generateAnchorPoints](../build/doc/class_s_c_generator.html#afd3dbaf6dc253db30a15eb02045d0ca7) | Returns a randomly distributed set of points inside the volume specified by the `envelopePerimeter` parameter [addIntermediateAnchors](../build/doc/class_s_c_generator.html#a8c78e82c8c5ead0f1de9a5c2af468e9e) | Generates a new set of anchors within the envelope and adds them to an existing set of anchors [findClosestNodes](../build/doc/class_s_c_generator.html#a330cd2da2229b6784c2bc4b6069298ce) | Selects the closest tree node to each anchor [growTreeNodes](../build/doc/class_s_c_generator.html#a5346d1e64a8b8f2cbeb3325e2920c1f6) | Grows selected nodes in the right directions [killAnchors](../build/doc/class_s_c_generator.html#a3a4af4f7886e84b58eb6f99dd178b6bf) | Deletes anchors too close to the tree [addCylindricSection](../build/doc/class_s_c_generator.html#a60da8995608bf468d72fe9f5a8c6d12f) | Given a Mesh and an initial circle, adds an additional circle to the mesh underneath the initial circle and adds faces between the circles [addLeaf](../build/doc/class_s_c_generator.html#ac68744f7d3cd6cd323c85871201b98e1) | Given a Mesh, adds a two-sided triangle to the Mesh [addFruits](../build/doc/class_s_c_generator.html#a4dc104e603613cce58339d15600f7a7b) | Populates an array with Point3 locations of where fruits should be added in relation to the CoordinateFrame of the base of a tree **Major functions of Mesh** Function | Description ---------------------|------------------------------------------------------------ addVertex | Adds a vertex to the Mesh addFace | Adds a face (three indices of the vertices array) to the Mesh numVertices | Returns the size of the vertices array addMesh | Adds a given Mesh to the end of the current Mesh toOFF | Writes the Mesh to an OFF file toOBJ | Writes the Mesh to an OBJ file **Major functions of Face** Function | Description ---------------------|------------------------------------------------------------ increment | Increments all of the points of the face by a given number To avoid having a lengthy App class, we abstracted our tree generation into two different classes, LGenerator, which generates an L-system tree, and SCGenerator, which generates a space colonization tree. The LGenerator has two main functions for tree generation, `makeLTreeSkeleton` and skeletonToMeshL. `makeLTreeSkeleton` creates a Tree with nodes determined by the phenotype and spine curve callback functions we pass to it. This function is recursive, calling `phenotype` for each branch. `phenotype` will return an array of child branches that determine the L-system structure. `skeletonToMeshL` takes a Tree skeleton and creates a Mesh for it, which can then be written to an OBJ or OFF file. The SCGenerator class holds all of the logic for generating a tree with the space colonization algorithm. It has two main methods, `makeSCTreeSkeleton` which generates the set of points that will form the skeleton of the tree, and `skeletonToMeshSC` which adds the vertices and faces that correspond to the given skeleton. The goal of the space colonization algorithm is to model the structure of a mature tree through the competition of branches for space. This is accomplished by generating a set of anchor points that pull on nearby tree nodes, and deleting anchors when they get too close to the tree. The process is divied up into the following methods: `generateAnchors`, `findClosestNode`, `growTreeNodes`, and `killAnchors`. To add a greater density of small twigs and branches in our trees, we give the option of continuously adding new anchor points at each iteration, which uses the `intermediateAnchors` method. To handle the logic of adding vertices and faces to a Mesh and writing the Mesh to a file in OFF format, we used Ben’s Mesh class from the Meshes lab. A `Vector` of `Point3`s is used to store the vertices and a `Vector` of `SmallArray`s of three `int`s, is used to store the faces. We also added a Face class to Mesh, which stores all the information we need to know about the faces of a mesh, including its points as well as its texture points. By having these classes, we do not have to write OFF or OBJ files of generated trees directly in our App class, which would make things messy and bulky. To handle the logic of adding vertices and faces to a Mesh and writing the Mesh to a file, we used Ben’s Mesh class from the Meshes lab. A `Vector` of `Point3`s is used to store the vertices and a `Vector` of `SmallArray`s of three `int`s, is used to store the faces. We also added a Face class to Mesh, which stores all the information we need to know about the faces of a mesh, including its points as well as its texture points. By having these classes, we do not have to write OFF or OBJ files of generated trees directly in our App class, which would make things messy and bulky. Correctness Results ================================== These images showcase the ability of our algorithms to generate a wide variety of trees, realistic and otherwise, controllable through the various parameters provided. These images of trees with wireframe shown demonstrate proper branch generation:   For the L-system generation, the main parameters are recursion depth, phenotype, and spine curve. As recursion depth increases, the complexity and density of the trees increases. The phenotype and spine curves are categorical variables and vary the appearence of the tree uniquely. The default parameters for the L-system tree are as follows: 1. Recursion Depth = 5 2. Phenotype = Normal 3. Spine Curve = Straight  These images show the effect of varying each parameter on the default tree:          For the Space Colonization generation, the main parameters are number of anchor points, distance between tree nodes, anchor point kill distance, initial branch radius, radius growth factor, attraction radius, leafiness, discount rate, and envelope. As anchor points increases, the tree gets more dense. As the tree node distance increases, the branches get more segmented. As the kill distance increases, the branches have larger empty area around them. As initial branch radius increases the radius of the branches increases. As the radius growth factor increases, the growth of the branch radii decreases. As the attraction radius decreases, the tree becomes more gnarled. As leafiness increases the branch sections that spawn leaves occur further down the branches. As the discount rate increases, the tree spawns more small twigs and branches to fill out the tree. The envelope perimeter function is categorical and varys the appearence of the tree uniquely. The default parameters for the space colonization tree are as follows: 1. Anchor Points = 1000 2. Tree Node Distance = 0.5 3. Kill Distance = 2 4. Initial Branch Radius = 0.01 5. Radius Growth Factor = 2 6. Attraction Radius = 100 7. Leafiness = 10 8. Discount Rate = 0.9 9. Envelope = Bulb  These images show the effect of varying each parameter on the default tree:                            Quality Results ==================================  ![This image of an orchard shows that we can use our program to easily generate a scene with tree models that have varying characteristics by changing the parameters of our tree generation. It also showcases the "orchard" feature of our program. The positions of some of the dollar stacks were modified in the scene editor to look less awkward. [#3DGold] ](orchard.jpg) ![This image shows the branch density of our space colonization trees through the use of lighting and shadows. [#haloedrain] ](bookTree.jpg)          *These images demonstrate how much variation exists in a single phenotype. These examples use our bush tree phenotype.* Evocative Result ================================== ![Because we incorporated so many parameters, as well as randomness, to our tree generation, it was easy to create a forest with different trees. The scene has dramatic lighting and showcases the warm colors of autumn. [#glDev] [#UVQ] ](evocativescene.jpg) Schedule ================================== Task | Description |Date | ---------------------|------------------------------------------------------------|--------------:| Report Draft (BDL)| Basic answers/placeholders inputted | 10/06 | Code Draft (BDL)| Code with basic format and structure done | 10/07 | fix CFrame bug (D)| Cylinders won't generate at an angle, fix | 10/08 | fix floating tree bug (BD)| Branches are floating above their parents, fix | 10/09 | Add Leaves (D)| Add leaf generation | 10/10 | Report MVP (BDL)| Get to Report MVP | 10/12 | Add Space Colonization (B)| Add space colonization tree generation algorithm | 10/14 | Add realistic radius (D)| Add realistic tree radius function | 10/13 | Specific makeBranch functions | Write standard makeBranch and helper methods to create different tree "phenotypes" (L) | 10/13 | Generate OBJ files (D)| Write tree models in OBJ format in addition to OFF format | 10/13 | Add spine curve callback function | Add functionality to default spine curve function so our branches curve | 10/14 | Add branch sections functionality | Be able to determine how many sections in a branch | 10/14 | Add texture (B) | Map texture coordinates to leaves and branches | 10/14 | Add bump map (B) | Map bump coordinates to leaves and branches | 10/14 | Add GUI Functionality (L)| Add elements from specification to the GUI | 10/14 | Add fruit trees (L) | Write function to add fruits to a scene where they would be growing on a tree | 10/16 | Add tree skeleton for L-system (D)| Rewrote L-system algorithm to use Ben's Tree class| 10/17 | Add generate orchard (L)| Add function to generate orchards of fruit trees | 10/18 | Make more phenotypes (D)| Write different callback functions to generate different looking trees | 10/18 | Make more spine curves (B)| Write different callback functions to generate trees with branches curving differently | 10/18 | Clean up code (B) | Abstract methods into separate classes, add comments, fix bugs| 10/18 | Change Log ================================== 1. Broke up L-system generation and space colonization generation into different classes - Ben, 10/18. 2. Modified L-system generation algorithm to use Ben's tree class - Diego, 10/17. 3. Added a new tree generation algorithm, **space colonization**, to the specification - Ben, 10/11. **Works Cited** ==================================== [#wikipedia]: “L-system,” *Wikipedia*, accessed 19 Oct 2016. https://en.wikipedia.org/wiki/L-system [#Runions]: Adam Runions, Brendan Lane, and Przemyslaw Prusinkiewicz, “Modeling Trees with a Space Colonization Algorithm,” Eurographics Workshop on Natural Phenomena (2007). http://algorithmicbotany.org/papers/colonization.egwnp2007.pdf [#glDev]: glDev (Dec 11, 2013) "Wooden Cabin" [3D model] turbosquid.com http://www.turbosquid.com/3d-models/free-wooden-cabin-3d-model/786883 Accessed 10/21/2016. [#UVQ]: UVQ (Oct 1, 2012) "Well" [3D model] turbosquid.com http://www.turbosquid.com/3d-models/free-max-model-well-bucket/697082 Accessed 10/21/2016. [#haloedrain]: haloedrain (Sep 12, 2006) "book" [3D model] turbosquid.com http://www.turbosquid.com/3d-models/book-3d-model/321013 Accessed 10/21/2016. [#3DGold]: 3DGold (Sep 12, 2006) "Free Dollar Bill" [3D model] turbosquid.com http://www.turbosquid.com/3d-models/free-dollar-bill-3d-model/501923 Accessed 10/21/2016.