Table of Contents

Turning a QSM into a growable model

In the following tutorial we will take a small QSM file, transform the existing cylinders into modules and add additional organs(Buds, Needles) in order to simulate simple growth based on a measured dataset.

Shoots

In order to add more variables or functions to the individual shoots, we first turn our imported shoots into our own kind of shoots. For now the module MyShoot can be very simple (basically just a brown cylinder):

module MyShoot(super.length, super.diameter) extends F{{setShader(EGA_6);}}

To use these new shoots we need a rule to turn all imported F's into MyShoot's of the same length and diameter.

f:F ==> MyShoot(f.length,f.diameter);

Yet there is an important addition here, that is different to normal L-System rule: we need to keep the local transformation that keeps the cylinders in place.

We can do this by applying an expression directly to the newly created shoot using '.()'. In this expression we set the transform value of the new object(represented by the $ sign) to the value of the old object.

f:F ==> MyShoot(f.length,f.diameter).($[transform]=f[transform]);

This is for now the core of our update function, which we can also extend by using the qsm library function jumpAllAxis(); to minimize the gaps between the imported shoots:

step1.rgg
import static de.grogra.qsm.utils.Library.*;
module MyShoot(super.length, super.diameter) extends F{{setShader(EGA_6);}}
 
public void update()[
{ jumpAllAxis();}
 f:F ==> MyShoot(f.length,f.diameter).($[transform]=f[transform]);
]

Adding buds

In order to create new shoots we first need new buds, therefore the module “MyBud” is created:

module MyBud(int order, float length) extends Sphere(0.002){{setShader(EGA_3);}}

Apical

step2.rgg
import static de.grogra.qsm.utils.Library.*;
import static de.grogra.qsm.utils.Descriptors.*;
module MyShoot(super.length, super.diameter) extends F{{setShader(EGA_6);}}
module MyBud(int order, float length) extends Sphere(0.002){{setShader(EGA_3);}}
public void update()[
	{
 jumpAllAxis();
	}
	f:F,(f[RTREND]==0) ==> MyShoot(f.length,f.diameter).($[transform]=f[transform])MyBud(f[BO],f.length*0.7);
	f:F ==> MyShoot(f.length,f.diameter).($[transform]=f[transform]);
]
 
 
public void grow()[
	MyBud(o,l),(o<2) ==> MyShoot(l,l/25) MyBud(o,l*0.7);
 
]

Lateral

Adding needles