> 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

Render Unity Terrain trees and details with 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-393ce538d8a4d8aa3fca1fe408616cf998b5631d%2Fterrain-trees-6-4-5.webp?alt=media" alt="Tree Effect sample Terrain Provider tree controls and prototypes"><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.

Increasing **Detail Distance** increases the streamed area and 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();
```

Dispose the request after reading its result. Do not copy it; copies share the same pooled storage.

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);
}
```

Results contain the prototype `EntityId`, population `Count` after density scaling, and `Present`. Batch queries write into caller-owned result arrays.

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-3d25d7b547ccc4e7a088f8539368f6cfc4474dff%2Fterrain-details-6-4-5.webp?alt=media" alt="Terrain detail settings with the Fern_A mesh prototype expanded"><figcaption></figcaption></figure>
