Skip to content

08b - Statistical vegetation (TurbidBoundary)

When the number of leaves in the scene is very large, TurbidBoundary can be used to describe the space occupied by the canopy, and leaf area density, leaf inclination angle distribution, and leaf optical properties can be used to describe the internal leaves. It is suitable for large-scale forests, crop groups, and scenarios that require simultaneous calculation of optical, thermal infrared, and physiological processes.

When to use statistical vegetation

Expression Applicable scenarios
Mesh Requires explicit leaf shape, veins or local geometric details
TurbidBoundary The number of leaves is large, focusing on canopy-scale radiation and physiological quantities
Mesh + TurbidBoundary Mesh is used for trunks and branches, and statistical vegetation is used for leaf clusters

The boundary grid only specifies the spatial extent of the medium. It is the statistical leaves inside the boundary that are really involved in the calculations of scattering, absorption, thermal emission and physiology.

Prepare to close the border

The boundary OBJ must satisfy:

  • Triangular surfaces form a closed, non-self-intersecting volume;
  • The faces are facing the same direction;
  • No openings, repeating faces or zero-area triangles;
  • Still within the valid scene range after placement and scaling.
import less

crown = less.TurbidBoundary(
    less.examples.asset_path("mixed_canopy.obj"),
    group="crown",
    sampling=less.TurbidSampling(
        quality="standard",
        seed=7,
    ),
)

Set internal blades

leaf = less.Fluspect(
    cab=40,
    car=10,
    cw=0.012,
    cm=0.009,
    fqe=0.012,
)

vegetation = less.OpticalVegetation(
    leaf=leaf,
    leaf_area_density=1.25,
    leaf_angle_distribution="spherical",
    leaf_size=(0.08, 0.04),
    leaf_shape="ellipse",
)

The unit of leaf_area_density is m² leaf area / m³ canopy volume. Commonly used leaf inclination angle distribution is:

Name Blade direction characteristics
spherical Spherical distribution, often used in canopies that lack measured information
uniform Uniform inclination angle
planophile More horizontal leaves
erectophile More upright leaves
plagiophile More medium-inclined leaves
extremophile More horizontal and upright leaves

Build a hybrid Mesh / Turbid scene

plant = less.Object("mixed_plant")
plant.add_component("crown", crown)
plant.add_component(
    "stem",
    less.Mesh(less.examples.asset_path("mixed_canopy.obj"), group="stem"),
)

plant.set_property("crown", vegetation)
plant.set_property("stem", less.Lambertian(reflectance=0.10))

scene = less.Scene(backend="optix")
scene.size = (20.0, 20.0)
scene.terrain = less.Terrain(property=less.Lambertian(reflectance=0.15))
scene.illumination = less.Illumination(source=less.Sun(zenith=30, azimuth=150), atmosphere=less.SimpleSpectralAtmosphere(turbidity=2.5))
scene.add(plant, positions=[(5, 5, 0), (10, 10, 0), (15, 15, 0)])

The same light path will handle explicit mesh surfaces, statistical leaves, terrain, and multiple scattering, so there is no need to simulate them separately and then superimpose them.

Optical imaging

image = scene.simulate(
    less.OpticalImager(
        projection=less.Orthographic(image_size=256),
        bands=[550, 680, 850],
        quality=64,
    ),
    scattering_order=8,
)
image.to_brf().save("turbid_brf.tif")

The resulting band order is consistent with bands. Radiance products can be converted to BRF using to_brf().

LAI and leaf area

lai = scene.simulate(less.LAIMeasurement(group_by="component"))
print(lai)

The leaf area of ​​statistical vegetation is determined by the boundary effective volume and leaf_area_density. Scaling the boundary changes the volume and therefore the total leaf area.

Energy balance and leaf temperature

Add thermal, biophysical, and stomatal conductance models to the canopy:

plant.set_property(
    "crown",
    less.ThermalProperty(emissivity=0.98, temperature="air"),
)
plant.set_property(
    "crown",
    less.BiophysicalProperty(
        leaf_width=0.04,
        stomatal_resistance=100.0,
        stomata_side="bottom",
    ),
)

microclimate = less.Microclimate(
    air_temperature=27.0,
    humidity=60.0,
    wind_speed=2.0,
)

energy = scene.simulate(
    less.EnergyBalanceProcess(quality="standard"),
    microclimate=microclimate,
)

The results preserve both sun and shade leaf condition temperatures and provide leaf temperature and energy closure information aggregated by component.

Photosynthesis

plant.set_property(
    "crown",
    less.Farquhar(Vcmax25=60.0, Jmax25=120.0),
)

photo = scene.simulate(
    less.PhotosynthesisProcess(
        temperature_mode="dynamic",
        quality="standard",
    ),
    microclimate=microclimate,
)

for key, apar, assimilation in zip(
    photo.component_keys, photo.APAR, photo.An
):
    print(key, apar, assimilation)

The unit of APAR is µmol photons m^-2 leaf s^-1, and the unit of An is µmol CO2 m^-2 leaf s^-1. The dynamic temperature model jointly solves for leaf temperature, stomatal conductance, and net photosynthetic rate.

SIF Source term and imaging

sif_source = scene.simulate(
    less.SIFProcess(mode="dynamic", photo=photo)
)

sif_image = scene.simulate(less.SIFImager(
    projection=less.Orthographic(image_size=256),
    bands=[687, 740, 760],
    quality=128,
    sif_result=sif_source,
))
sif_image.save("turbid_sif.tif")

SIF The image unit is W m^-2 sr^-1 nm^-1. mode="dynamic" uses photosynthetic results; mode="static" uses leaf fluorescence quantum yield.

Thermal infrared imaging

thermal = scene.simulate(less.ThermalImager(
    projection=less.Orthographic(image_size=256),
    bands=[10600],
    quality=64,
    mode="precomputed",
    eb_result=energy,
))
thermal.save("turbid_thermal.tif")

mode="precomputed" Sun and shade leaf temperatures obtained using energy balance. If you only set the fixed ThermalProperty, you can use the default mode="auto".

Sampling accuracy

TurbidSampling controls the accuracy of statistical blade pools and spatial fields:

sampling = less.TurbidSampling(
    quality="high",
    sample_budget=16384,
    seed=42,
    orientation_theta_bins=4,
    orientation_phi_bins=8,
    max_samples_per_leaf_cell=64,
)
Parameters Function
quality Preset sampling quality; optional preview, standard, high
sample_budget Target number of samples per placement instance; determined by quality preset when omitted
seed Seed of repeatable random sequence
orientation_theta_bins / orientation_phi_bins Discrete number of blade direction
max_samples_per_leaf_cell Sample upper limit of adaptive spatial unit

Use preview to check the scene and parameters first, then use standard or high to generate official results. Identical seeds and configurations keep sample prefixes stable, making it easier to compare different quality settings.

Save and reuse

TurbidSampling will be serialized with Scene/Project. There is no need to rebuild the geometry when only lighting, optical properties, or microclimate are modified; after modifying boundaries, instance positions, leaf area density, leaf inclination, or sample seeds, the statistical leaf field is updated on the next build.

See scripts/08b_turbid_medium.py for a complete example.

  • less.TurbidBoundaryless.TurbidSampling
  • less.OpticalVegetationless.Fluspectless.Lambertian
  • less.Meshless.Objectless.Sceneless.Terrain
  • less.LAIMeasurementless.OpticalImagerless.BRFSensor
  • less.ThermalPropertyless.BiophysicalPropertyless.Farquhar
  • less.Microclimateless.EnergyBalanceProcessless.PhotosynthesisProcess
  • less.SIFProcessless.SIFImagerless.ThermalImager

The next chapter covers multispectral and hyperspectral simulations.