# 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