> For the complete documentation index, see [llms.txt](https://flora.magneticarcade.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flora.magneticarcade.com/scripts/terrain-provider.md).

# Terrain Provider

A bridge component that links a Terrain object to the Flora.

The **Terrain Provider** lets Flora render a Unity `Terrain`'s trees and details.

> **Auto Register Terrains** adds providers automatically. Disable a provider to opt out that Terrain.
>
> For non-Terrain workflows, use [Instance Container](/scripts/instance-container.md) or [Instance Renderer](/scripts/instance-renderer.md).

## Trees

Trees load when a camera and its far plane enter the Terrain's [`treeDistance`](https://docs.unity3d.com/ScriptReference/Terrain-treeDistance.html).

* **Tree Distance** controls streaming and maximum render distance.
* **Use Prototype Layers** uses each prototype GameObject's layer when enabled. When disabled, every tree uses the Terrain GameObject's layer.
* **Tree Motion Vectors** follows `Terrain.treeMotionVectorModeOverride`; **Inherit From Prototype** uses the prototype renderers.
* **Bake Light Probe Positions** edits `Terrain.bakeLightProbesForTrees`, which controls whether Unity adds tree positions to a legacy light-probe bake.
* **Tree Spatial Cache** controls whether this Terrain's trees participate in [Static Spatial Caching](/rendering/static-spatial-caching.md).

Compatible SpeedTree prototypes animate automatically. Configure shared or per-Terrain sampling in [Scene Settings](/scripts/scene-settings.md#terrainspeedtreewindproxymode); see [SpeedTree Wind](/rendering/speedtree-wind.md) for requirements and performance guidance.

These controls edit the `Terrain` directly and update while it is tracked. **Bake Light Probe Positions** affects baking only; runtime probe use follows the prototype Renderers and LODGroup.

<figure><img src="https://2882982566-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fyo4B7EVXffipTxnJzee6%2Fuploads%2Fgit-blob-329b162be5ed00955927741dacfcdec8b9234ce7%2Fterrain-tree-prototypes.webp?alt=media" alt="Terrain tree distance UI"><figcaption></figcaption></figure>

## Details

Details stream when a camera and its far plane enter the Terrain's [`detailObjectDistance`](https://docs.unity3d.com/ScriptReference/Terrain-detailObjectDistance.html). Flora generates their placements on the GPU.

**Detail Distance** and **Detail Density Scale** edit the Terrain. Motion vectors and layers come from prototype Renderers. Details use APV when available and do not store legacy probe data.

Details remain loaded for [the unload hysteresis](/scripts/scene-settings.md#detailunloadhysteresisseconds) after leaving range. The default is `0.5` seconds.

> **Important:** For large environments, keep **Detail Distance** at a reasonable value to avoid unnecessary memory use.

Flora supports detail meshes with LODGroups. Unity's fallback renderer uses only the first LOD mesh.

Terrain details are transient GPU data. They do not create `FloraInstanceHandle` values, do not appear in instance queries, and do not participate in Static Spatial Caching.

### Query nearby detail prototypes

`FloraTerrainDetailQuery` specifies the prototype `EntityId` to find, a position, a radius, and optionally one Terrain. Use `ScheduleTerrainDetailQuery` for one asynchronous query, `RunTerrainDetailQuery` for one immediate query, or `ScheduleTerrainDetailQueries` with caller-owned `NativeArray` inputs and outputs for a batch.

```csharp
FloraTerrainDetailQuery query = new(grassPrefab.GetEntityId(), player.transform.position, 8f);
FloraTerrainDetailQueryResult queryResult = FloraSystem.GetOrCreate().RunTerrainDetailQuery(query);
if (queryResult.Status == FloraTerrainDetailQueryStatus.Complete && queryResult.Present)
{
    ReactToNearbyDetailPrototype(queryResult.Prototype, queryResult.Count);
}
```

Immediate execution completes outstanding Flora terrain work first. When the result is not required synchronously, overlap the query with independent work:

```csharp
using FloraTerrainDetailQueryRequest request = FloraSystem.GetOrCreate().ScheduleTerrainDetailQuery(query);
JobHandle independentWork = ScheduleIndependentWork();
JobHandle.CombineDependencies(request.Handle, independentWork).Complete();
FloraTerrainDetailQueryResult queryResult = request.Complete();
```

The request references Flora-owned pooled result storage and must be disposed after reading its result. Do not copy a request. Scheduled single queries reuse pooled native result storage instead of allocating a native result container for every call.

For multiple queries, allocate equally sized query and result arrays and schedule the batch directly:

```csharp
JobHandle handle = flora.ScheduleTerrainDetailQueries(queries, results);
handle.Complete();

for (int index = 0; index < results.Length; index++)
{
    FloraTerrainDetailQueryResult result = results[index];
    if (result.Status == FloraTerrainDetailQueryStatus.Complete && result.Present)
        ReactToNearbyDetailPrototype(result.Prototype, result.Count);
}
```

`FloraTerrainDetailQueryResult` contains the requested prototype `EntityId`, its render-scaled population count, and a convenience presence property. Immediate execution allocates no result storage. The batch form uses only the arrays supplied by the caller and samples ready queries in parallel. None of the query paths uses atomic or dynamically growing job output.

Queries inspect resident terrain-detail data and never request missing patches or expand the streaming region. A `NotResident` result has a zero count. Let normal camera streaming make the region resident, or create a terrain streaming sphere for a region that must stream without a camera:

```csharp
FloraStreamingSphereHandle streamingSphere =
    FloraSystem.GetOrCreate().CreateTerrainStreamingSphere(player.transform.position, 16f);

streamingSphere.Update(player.transform.position, 16f);

// When the region no longer needs to remain resident:
streamingSphere.Dispose();
```

Keep the handle for as long as the region should remain streamed, update it when the target moves, and dispose it when finished. Do not copy the handle. The sphere participates in terrain tree and detail streaming. Terrain detail distance caps its detail-patch radius, while tree streaming continues to use the Terrain's tree distance. After streaming has progressed, schedule the query again on a later frame.

Results are aggregated at detail-cell resolution. They do not account for GPU hole or footprint rejection.

<figure><img src="https://2882982566-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fyo4B7EVXffipTxnJzee6%2Fuploads%2Fgit-blob-4434e29322c5e946caabe571da1f03aaea43fa3a%2Fterrain-detail-prototypes.webp?alt=media" alt="Detail mesh preview with LODs"><figcaption></figcaption></figure>
