PyHelios 0.1.11
Loading...
Searching...
No Matches
Weber-Penn Tree Plugin Documentation



DependenciesNone
Python Importfrom pyhelios import WeberPennTree
Main ClassWeberPennTree

System Requirements

DependenciesNone
PlatformsWindows, Linux, macOS
GPUNot required

Quick Start

from pyhelios import Context, WeberPennTree, WPTType
from pyhelios.types import vec3
with Context() as context:
with WeberPennTree(context) as wpt:
# Build a lemon tree
tree_id = wpt.buildTree(WPTType.LEMON, origin=vec3(0, 0, 0))
# Query tree components
trunk_uuids = wpt.getTrunkUUIDs(tree_id)
leaf_uuids = wpt.getLeafUUIDs(tree_id)
print(f"Tree has {len(trunk_uuids)} trunk segments and {len(leaf_uuids)} leaves")

Known Issues

  • The following parameters described in Weber and Penn (1995) are not implemented: nCurveBack, Flare.

Introduction

This plugin implements the Weber-Penn 3D procedural tree generation model, which generates a 3D leaf- and branch-resolved model of a tree. Click here for the publication describing the model. The method has many different parameters that can be adjusted to create arbitrary tree architectures. The plugin adds geometric primitives to the Helios context that defines the geometry of the generated tree.

WeberPennTree Class Constructor

Constructors
WeberPennTree(context)

The WeberPennTree class is initialized by passing the Helios context as an argument to the constructor. This gives the class the ability to automatically add geometry to the context.

Using the Weber-Penn Tree Plug-in

The XML Tree Library File

The parameters that define various tree geometries are specified in an XML file, which is loaded by the plug-in. When the WeberPennTree constructor is called, the defalut tree library is loaded. A list of trees in the default library is listed in the table below. Default tree parameters can be modified by the user, or custom tree libraries can be added, which is detailed in Section Custom Tree Library Files. An example tree definition is given below. The tree definition is encapsulated by the <WeberPennTree label="...">...</WeberPennTree> tag, where label gives a handle used to reference that specific tree geometry. Other tags define various parameters that determine the structure of the tree, which are detailed in the sections below.

Tree typeSample Image
Almond
Apple
Avocado
Lemon
Olive
Orange
Peach
Pistachio
Walnut
<?xml version=1.0?>
<helios>
<WeberPennTree label="Almond">
<Shape> 3 </Shape>
<BaseSize> 0.2 </BaseSize>
<BaseSplits> 2 </BaseSplits>
<BaseSplitSize> 0.2 </BaseSplitSize>
<Scale> 6 </Scale>
<ScaleV> 1 </ScaleV>
<ZScale> 1 </ZScale>
<ZScaleV> 0 </ZScaleV>
<Ratio> 0.02 </Ratio>
<RatioPower> 1.3 </RatioPower>
<Lobes> 5 </Lobes>
<LobeDepth> 0.1 </LobeDepth>
<Flare> 0.25 </Flare>
<Levels> 3 </Levels>
<nSegSplits> 0 0 0 0 </nSegSplits>
<nSplitAngle> 40 10 10 0 </nSplitAngle>
<nSplitAngleV> 0 0 0 0 </nSplitAngleV>
<nCurveRes> 8 5 3 1 </nCurveRes>
<nCurve> -60 -40 10 </nCurve>
<nCurveV> 0 0 0 0 </nCurveV>
<nCurveBack> 0 -70 0 0 </nCurveBack>
<nLength> 1 0.6 0.4 0.3 </nLength>
<nLengthV> 0 0 0 0 </nLengthV>
<nTaper> 1 1 1 1 </nTaper>
<nDownAngle> 0 50 30 0 </nDownAngle>
<nDownAngleV> 0 0 0 0 </nDownAngleV>
<nRotate> 95 95 95 95 </nRotate>
<nRotateV> 0 10 10 0 </nRotateV>
<nBranches> 0 50 30 20 </nBranches>
<Leaves> 16 </Leaves>
<LeafFile> plugins/weberpenntree/leaves/AlmondLeaf.png </LeafFile>
<LeafScale> 0.2 </LeafScale>
<LeafScaleX> 0.3 </LeafScaleX>
<WoodFile> plugins/visualizer/textures/wood2.jpg </WoodFile>
</WeberPennTree>
</helios>

Adding Trees from the Tree Library

The WeberPennTree member function buildTree() is used to add and instance of a tree from the library. This function takes two required arguments in addition to one optional argument. The user must specify 1) the label for the tree as defined in the tree library XML file (see above), and 2) the (x,y,z) position to place the tree (note that this position is with respect to the base of the trunk). A third optional argument specifies a scaling factor to apply to the tree, where scale<1 makes the tree smaller, and scale>1 makes the tree bigger. The buildTree() function returns a uint that gives an identifier for the particular instance of the tree. This can be used later to reference the tree.

The tree building process involves adding primitives to the Helios context that comprise a particular tree geometry. The UUIDs for the primitives that comprise trees can be queried via the functions getTrunkUUIDs(), getBranchUUIDs(), and getLeafUUIDs() along with the identifier of the tree.

Tree Building Functions
buildTree(treename, origin)
buildTree(treename, origin, scale)
from pyhelios import Context, WeberPennTree
from pyhelios.types import vec3
with Context() as context:
# Create an instance of the WeberPennTree class
wpt = WeberPennTree(context)
# Create an almond tree at the point (0,0,0)
ID_almond = wpt.buildTree("Almond", vec3(0, 0, 0))
# Create an orange tree at the point (10,0,0)
ID_orange = wpt.buildTree("Orange", vec3(10, 0, 0))
# Retrieve UUIDs for context primitives making up the almond tree's leaves
leafUUIDs_almond = wpt.getLeafUUIDs(ID_almond)

Custom Tree Library Files

User-specified XML tree library files can be utilized via the loadXML() function. The argument to this function is an absolute or relative path to the XML file to be loaded. Note that relative file paths are relative to the current working directory.

Creating Custom XML Files

General Overview

The general idea behind the tree geometries is by specifying parameters that define the growth pattern of recursive branching levels (see figure above). The base structure of the tree is the trunk, which is the 0th recursive level. Braches are considered "children" of their "parent", which in this case is the trunk. The first branching level is dependent on the size and orientation of the trunk. Further levels of recursion are created by generating branches that are children of the previous branching level. Each branching level follows the same set of rules but has different parameters that define the way they grow. The number of recursion levels is given by the parameter Levels. Importantly, the last level of recursion always corresponds to leaves, which follows the same general rules as branches. So setting Levels = 3 would give a trunk, two branching levels, plus leaves.

Many parameter names are prepended with the letter "n", which indicates that these parameters vary with recursion level. For example, the parameter Scale is a scaling factor applied to the whole tree, and thus it does not depend on the recursion level. The parameter nBraches gives the maximum number of branches for each recursion level (note the "n" in the name), and therefore can have a different value for each recursion level. Below, each recursion level will be referred to by replacing "n" by the level number (e.g., 0Branches, 1Branches, 2Branches, etc.).

Many parameter names are appended with the letter "V", which indicates that the parameter indicates a random range over which a value varies. For example, if Scale = 10 and ScaleV = 1, the scale factor would randomly vary between 9 and 11. Setting ScaleV to 0 would mean that there is no variation and the scale factor is always 10.

Trunk and general tree shape

Parameters related to the trunk and overall tree shape.
ParameterDescription
ScaleScaling factor to specify overall tree size. Scale is generally the height of the tree.
0LengthLength of the tree trunk as a fraction of scale. Usually, 0Length is set to 1 (i.e., 100%).
BaseSizePercentage of the tree height before vegetation/branches start (0<BaseSize<1). For a tree with no trunk, BaseSize=0. For a tree where vegetation is only present in the upper half of the tree, BaseSize=0.5.
RatioSpecifies the trunk radius at the base as a fraction of the length of the trunk. So Ratio=0.01 would have a trunk with radius at base of 1% of the trunk length.
0TaperReduction factor for trunk radius moving away from base (0<=0Taper<=1). Setting 0Taper to 0 results in a cylindrical trunk, setting 0Taper to 1 results in a conical trunk, and setting 0Taper between 0 and 1 gives a combination of the two.
FlareExpansion of the trunk radius at the base by a factor of 1+Flare.
ShapeFlag corresponding to desired tree crown shape. See table below for available tree crown shapes.
BaseSplitsNumber of trunk splits. For example, BaseSplits=1 gives on split and two distinct "scaffolds" or secondary trunks. BaseSplits=2 gives three distinct secondary trunk branches.
BaseSplitSizeIf BaseSplits>0, BaseSplitSize is the distance from the base of the tree to the split as a fraction of the height of the tree (0<=BaseSplitSize<=1).
0SplitAngleAngle from vertical (degrees) of the split branch with respect to vertical.

Creating new tree geometries typically starts by considering the overall size and shape of the tree. The above image shows a schematic sketch of the relevant parameters used to define these features.

The height of the tree in meters is given by the ‘Scale/ScaleV’. The height of the trunk portion with no branches is given by ‘BaseSize’, which is a fraction of the whole tree height. For example, if Scale=10 and BaseSize=0.4, the first 4 meters of the tree trunk would have no branches.

The trunk radius at the base is given as a fraction (Ratio) of the total height of the tree. For example, Ratio = 0.05 gives a trunk radius that is 5% of the total height of the tree. The trunk radius can taper along its lenght according to the parameter ‘0Taper’, with 0<=0Taper<=1. 0Taper=0 gives no tapering, and 0Taper=1 tapers the trunk to a point (i.e., radius=0).

The shape of the tree is given by the ID parameter 'Shape'. There are 8 supported tree shapes, which are given in the table below. One important caveat is when BaseSplits is greater than 0, in which case the shape applies to each individual split branch and not necessarily to the tree as a whole. So BaseSplits=0 and Shape=1 (spherical) would result in one split and two spherical crown sub-shapes.

Available tree crown shapes
ShapeDescriptionSketch
0Conical
1Spherical/Ellipsoidal
2Hemispherical
3Cylindrical
4Tapered Cylindrical
5Flame
6Inverse Conical
7Tend Flame

Recursive Branches

Leaves

Leaf mask

The tree model uses a PNG texture mask to visualize leaves. This is a PNG image of the leaf with a transparent background. An example leaf mask is given in the image below. New leaf masks can be created using Gimp fairly easily. Simply find an image of the leaf, open in Gimp, add an alpha channel to the image, use the ‘Fuzzy Select Tool’ to select the background, then go to Edit->Clear, and export in .png format. There are many tutorials online describing how to do this in more detail. Note that the leaf should be oriented as shown in the image below for consistency: petiole pointing to the left. Also note that the petiole is typically cropped out of the image.

User-Defined Leaf Angle Distribution Functions

By default, the Weber-Penn tree model will create a semi-random leaf angle distribution by rotating leaves around its parent branch according to the parameters set for that particular tree. However, this is typically not realistic for how leaves arrange themselves in nature, and it is often desirable to specify a leaf angle distribution based on actual data. A custom leaf angle (inclination) distribution function can be specified for a given tree type in the tree library XML file using the tag '<LeafAngleDist> ... </LeafAngleDist>'. The elements within the tag should be probability densities of leaf inclination for discrete angle classes ranging from \(\theta_L=0\) to \(\theta_L=\pi\) rad.

Here is an example: Imagine that we wanted to have N=18 discrete leaf angle bins in our leaf angle PDF \(g_L\). The width of one discrete bin would be \(\Delta \theta_L=\pi/18\approx 0.1795\) rad. Each of the 18 bins of our PDF \(g_L\) should give the probability density that we have a leaf inclination angle that falls within that bin. By definition, the following should hold for our PDF:

\(\sum\limits_{i=1}^N\,g_{L,i}\Delta \theta_L=1\)

If this condition is not met by the PDF input by the user, the program will ignore it and revert to the default behavior.

As a simple example, imagine we had only one leaf with an inclination of \(\theta_L=0.1\) rad. This leaf would fall in the first discrete bin of \(g_L\), which would have a value of \(1/\Delta \theta_L\) and all other bins would be zero.

For a typical almond tree, the PDF for N=18 is tabulated below. Note that we have the capability to have leaves pointing upward from their base ( \(\theta_L<\pi/2\)) or leaves pointiing downward from their base ( \(\theta_L>\pi/2\)). For simplicity, the distribution below considers only upward-facing normals.

Typical leaf angle distribution for almond
\(\theta_L\) bin (degrees)\(g_L(\theta_L)\)
0-100.229
10-200.665
20-300.917
30-400.945
40-500.865
50-600.745
60-700.619
70-800.424
80-900.315
90-1000
100-1100
110-1200
120-1300
130-1400
140-1500
150-1600
160-1700
180-1800

This data would be input into the tree library XML file as follows:

<?xml version=1.0?>
<helios>
<WeberPennTree label="Almond">
<!--
Many other parameters here
-->
<LeafAngleDist>0.2290 0.6650 0.9170 0.9450 0.8650 0.7450 0.6190 0.4240 0.3100 0 0 0 0 0 0 0 0 0</LeafAngleDist>
</WeberPennTree>
</helios>

Troubleshooting

Plugin Not Available

If you see "WeberPennTree not available" errors:

# Check plugin status
python -c "from pyhelios.plugins import print_plugin_status; print_plugin_status()"
# Rebuild with plugin
build_scripts/build_helios --clean --plugins weberpenntree

Asset Loading Errors

WeberPennTree requires asset files (leaf textures, wood textures, XML definitions). If you encounter asset errors, verify assets are present:

# Check asset location
ls pyhelios_build/build/plugins/weberpenntree/

Custom XML Loading Issues

If loadXML() fails, verify:

  • XML file exists and has .xml extension
  • XML follows WeberPennTree schema (see examples above)
  • All required parameters are specified for each tree definition

References

Weber, J., and Penn, J. (1995). "Creation and rendering of realistic trees." In Proceedings of the 22nd annual conference on Computer graphics and interactive techniques (SIGGRAPH '95). Association for Computing Machinery, New York, NY, USA, 119–128. DOI: https://doi.org/10.1145/218380.218427