# 6. Terrain Performance, Mobile and Quest
Part of [[Terrain]]. Previous: [[5. Runtime Terrain Queries and Deformation]]. Next: [[7. Terrain Pitfalls]].
> [!note] Verification status
> `Terrain` properties used (`heightmapPixelError`, `basemapDistance`, `drawInstanced`, `detailObjectDistance`, `detailObjectDensity`, `treeDistance`, `treeBillboardDistance`, `treeMaximumFullLODCount`, `shadowCastingMode`, `ignoreQualitySettings`) exist on the 6000.5 Scripting Reference (2026-11-10). The *numbers* in the budget table are starting points from general mobile practice, **not** Unity-published figures - profile on device.
**VR version note:** Quest builds in this vault target **Unity 6.3 LTS (6000.3.27f2+)** ([[0.Choosing a Unity Version]]). The Terrain API above has been stable across 6.x, but re-check the 6000.3 Scripting Reference if a property is missing.
## 6.1 Where terrain cost comes from
| Cost | Knob | Notes |
|---|---|---|
| Heightmap triangles | **Pixel Error** (`heightmapPixelError`) | Higher = fewer triangles, more popping. 1-5 desktop; 8-20 mobile/VR |
| Splat shading | Number of Terrain Layers, height-blend, per-pixel normal | Each layer is more texture samples per pixel. Keep to **4 layers per tile** on Quest and verify passes in the Frame Debugger |
| Far shading | **Basemap Distance** (`basemapDistance`) | Beyond it, a precomputed low-res basemap replaces the splat shader. Pull it in on mobile |
| Draw calls | **Draw Instanced** (`drawInstanced`) | Instanced terrain renderer; also needed for per-pixel normals |
| Details (grass) | `detailObjectDistance`, `detailObjectDensity`, detail resolution per patch | Biggest mobile cost: overdraw (alpha-tested grass) and vertex count |
| Trees | `treeDistance`, `treeBillboardDistance`, `treeMaximumFullLODCount`, LOD Groups | Billboards are cheap; full-LOD trees near the camera are not |
| Shadows | `shadowCastingMode`, shadow distance in URP asset | Terrain casting into a large cascade is expensive on Quest |
| Memory | Heightmap, alphamap, detail, holes resolutions | Clones for deformation double it (part 5) |
## 6.2 Prefer Quality Settings overrides
`Terrain.ignoreQualitySettings` exists because Quality Settings can override terrain values per quality level. Set terrain overrides on your *Mobile/Quest* quality level so each tile's own settings stay authored for desktop. Use the script below only when you need per-scene control.
## 6.3 Script: terrain quality profile
```csharp
// Assets/Scripts/Terrain/TerrainQualityProfile.cs
using UnityEngine;
using UnityEngine.Rendering;
[CreateAssetMenu(menuName = "Terrain/Quality Profile")]
public class TerrainQualityProfile : ScriptableObject
{
public float heightmapPixelError = 5f;
public float basemapDistance = 1000f;
public bool drawInstanced = true;
public float detailObjectDistance = 80f;
[Range(0f, 1f)] public float detailObjectDensity = 1f;
public float treeDistance = 2000f;
public float treeBillboardDistance = 50f;
public int treeMaximumFullLODCount = 50;
public ShadowCastingMode shadowCastingMode = ShadowCastingMode.On;
public void ApplyTo(Terrain t)
{
t.heightmapPixelError = heightmapPixelError;
t.basemapDistance = basemapDistance;
t.drawInstanced = drawInstanced;
t.detailObjectDistance = detailObjectDistance;
t.detailObjectDensity = detailObjectDensity;
t.treeDistance = treeDistance;
t.treeBillboardDistance = treeBillboardDistance;
t.treeMaximumFullLODCount = treeMaximumFullLODCount;
t.shadowCastingMode = shadowCastingMode;
}
}
```
```csharp
// Assets/Scripts/Terrain/TerrainQualityApplier.cs
using UnityEngine;
public class TerrainQualityApplier : MonoBehaviour
{
public TerrainQualityProfile desktop;
public TerrainQualityProfile mobileOrXR;
void Start() // Start, not Awake: all terrains in the scene are enabled by now
{
TerrainQualityProfile p = Application.isMobilePlatform ? mobileOrXR : desktop;
if (p == null) return;
foreach (Terrain t in Terrain.activeTerrains)
{
// If a tile ignores quality settings, the designer opted out - still apply our profile.
p.ApplyTo(t);
}
}
}
```
Quest 2 is Android, so `Application.isMobilePlatform` is true there.
**Starting profile for Quest 2 (tune on device):** pixel error 12-20, basemap distance 80-150 m, Draw Instanced on, detail distance 20-35 m and density 0.3-0.6 (or no grass at all - use a grass texture and a few clumps), tree distance 150-300 m, billboard distance 25-40 m, max full LOD trees 10-20, terrain shadow casting off with baked lighting.
## 6.4 Quest-specific advice
- **Single Pass Instanced** stereo renders terrain once per eye in one pass - but pixel cost is still per eye. Splat layers and grass overdraw are pixel costs.
- **Alpha-tested grass** is expensive on tile GPUs. Prefer mesh details with opaque materials, short distance, or none.
- **Fixed Foveated Rendering** helps with terrain at the periphery; see [[5.Quest 2 Performance and Rendering]].
- **Bake lighting** ([[6.Mobile and Meta Quest Considerations]]) and disable terrain shadow casting.
- **Small worlds win.** A 250-500 m tile with a strong skyline and fog often reads bigger than a 2 km map.
- **Consider baking terrain to a mesh** for Quest: export the heightmap, build a mesh (or use a mesh-export tool), LOD it, and use a simple 2-4 texture blend shader. You lose terrain painting tools at runtime but gain predictable cost. *(No first-party "terrain to mesh" exporter is documented in 6000.5 Terrain Tools that I could verify - check the Toolbox before relying on one.)*
## 6.5 Profiling checklist
1. **Frame Debugger**: count terrain draws and passes; confirm instancing.
2. **Profiler > Rendering**: batches, SetPass calls, triangles.
3. **On Quest**: OVR Metrics Tool / RenderDoc for GPU time; watch for grass overdraw.
4. Toggle `drawTreesAndFoliage` at runtime to isolate trees/details cost.
## Sources
- `Terrain` API (all properties above): https://docs.unity3d.com/6000.5/Documentation/ScriptReference/Terrain.html
- Terrain settings (Pixel Error, Draw Instanced, Basemap): https://docs.unity3d.com/6000.5/Documentation/Manual/terrain-OtherSettings.html
- URP Terrain Lit (Per-pixel Normal needs Draw Instanced): https://docs.unity3d.com/6000.5/Documentation/Manual/urp/shader-terrain-lit.html