Unity Terrain performances on Oculus Quest 2

I am using Unity Terrain to create some basic landscape but I have the impression that the performance impact is significant (or at least, way more than I was expecting):

  1. This is the situation with a simple plane, this scene uses 4k tris, with a GPU at L2 the app time is 7.4ms

  2. This second scene uses 24k tris, the GPU goes to L3 with an app time of 9.5ms

  3. This third scene uses 24k tris but the plane is now textured, the GPU goes at L3 with a considerable load and the app time is almost 11ms:

These are my terrain settings. I have used no trees or grass, it’s just the terrain. All light is baked, shadows are disabled. LOD is set to 80 with a generous pixel error.

The scene is just: static skybox, 1 directional light (baked), 1 random floating monolith and the terrain 250x250x100.

Is this amount of workload expected or am I doing something horribly wrong? With terrain in place I have just about 3ms of GPU budget left that doesn’t sound too appealing.

Thank you

1 Like

Yes, Unity terrain is expensive.

But what is that FPS display you’re showing there? That looks like it’s providing some very interesting and useful details.

It’s a bit too expensive, I am preparing a repro project to file a bug as, after consulting with other people, it sounds like there might be something wrong and it shouldn’t be so expensive.

The tool is OVRMetrics and it’s indeed very helpful for early detection of performance problems - such as the one I’m having - and super simple to use. You might want to read the explainer page as well as it details how to interpret all the various fields.

1 Like

How many layers are you using? Are you using normal maps?

The unity terrain material samples 4 diffuse and normal maps. Using more than 4 layers causes the terrain to be rendered a 2nd time with blending for more four layers. That can be quite a lot for the Quest.

As shown in the screencap, the performance is very poor even with no textures (no normal maps) and a single base layer. Meanwhile I filed a bug, I’ll update this post when Unity support replies.

Even if you only use one layer, the shader will perform at least 5 texture sample operations (6 if you are using instanced terrain).

Then if that’s the case, I’ll have to find some other solution to landscape that doesn’t eat up so much GPU time. Thanks for your input!

Have you ensured that at this stage you’ve tuned you camera FOV and culling distance too?

You will find performance drops with occlusion culling at this stage too, so if you have it, remove it.

Also split your terrain into 4 and just run one segment you’re looking at, see if there is a performance gain chance for asynchronous loading in one scene or using scene additives.
If yes you might be able to look in that direction too.

A recent game built on Unity Genshin Impact is certainly worth the research into, they attained 30km2 using the terrain system and so great async loading ideas. No VR in that case but It may help create and idea for a solution for you.

1 Like

I have done several experiments with FOV and culling distance (which is currently very short at just 80m) but still the impact remains very high. I didn’t split the terrain as it’s just 250x250 with 0 objects on it, but I’ll give it a try and split it in smaller chunks. Although an equally large terrain made in blender works absolutely fine, in fact for now I’m doing just that since I’m still prototyping.

Thanks for your input.

1 Like

You’re most welcome, sorry to hear you still haven’t found a suitable solution, I Will have another look myself at some of our work, because we’re running 25km2 terrains at only 1.2-7ms no split, on either GPU/CPU. Granted we’re not targeting the oculus here so it could be a chip architecture limit there.

We’ve found negligible terrain tiling/Async uses until after certain sizes to especially if you’re budgeting for calls/GPU bottlenecks.

Terrain systems is certainly is tricky to balance.

If look again at your terrain core defaults ( just your height data in.

With everything solid, lights/shaodws at real-time, simple directional without post etc and just add in piece by piece your like pixel error. I’ve certainly seen massive increases in performance there just from going from 5-9 but then after more increases the gains just fall.

But yeah, add your occlusion culling, camera culling etc in last, just to see the gains on cons on MS, FPS, Batches. There might be something you can tweak just a smidge.

Occlusion culling I believe does add to the CPU and memory cost so you, may get a little more back by NOT using it in the case.

Hope you find more luck anyway!

1 Like

Hey, I work on Unity terrain and yes, there are significant performance issues on mobile platforms which we are actively investigating.

Some questions for you:

Could you describe how you are profiling?
Is this from the editor or a build?
If it’s a build, is it release or dev?
Are you using Oculus Link?
Is this SteamVR, OculusVR or OpenXR?

Have you tried cranking the pixel error all the way up? Could you share perf numbers with different pixel error values?

Also, could you share the perf numbers you are seeing with instancing disabled vs enabled?

For transparency, our current understanding of the problem is the device is CPU limited, due to our quadtree traversal algorithm which runs during culling. This is implemented in C++ and runs extremely fast on a desktop CPU, but a combination of memory access and the hot loop on mobile CPUs ends up causing issues.

1 Like

Hi Jeremy,

Thanks for providing feedback, I opened a bug in Unity support and included my entire test project, so you should easily be able to run tests with one single click, to address your questions:

  1. The reduced framerate was very obvious (I added and patch of grass and I got nausea in seconds ;), first I did a quick run with OVR Metrics then I profiled using Unity profiler directly as on Mac I can’t run RenderDoc
  2. Screenshot and numbers were from a build of course
  3. I did tests both in Debug and Release, the difference was negligible
  4. I am not using Oculus Link (not supported on Mac)
  5. When I posted it was OculusVR, I then ported the project to OpenXR with the same results, at that point I removed the terrain altogether.

Anyway I got the impression that my app was GPU bound more than CPU bound in that specific example. For the other numbers: I haven’t saved that branch and I moved ahead quite a lot. If there’s a way to recover it from the bug I filed, I’d be happy to run those tests and report back the result.

Thank you

Hi, I am having very similar issues with terrain using Oculus Quest 2. At first, my terrain did not render at all although the mesh was there and my character controller was able to travel on it (I fixed it by turning off “Draw Instanced” in the terrain settings). However, now I have another issue where my Speedtrees do not render their shadow on the terrain mesh. It renders the shadows on the terrain just fine on my pc but whenever I build into the Oculus Quest 2 the shadows do not render on the terrain mesh anymore.
Not sure if anyone have had a similar issue with shadows and terrains before but any feedback would be super helpful!

Are you on URP with baked lights? It sounds like you might be trying to use real-time lights.

Go with microsplat. It’s free and runs well on mobile. It’s a drop in replacement for the urp terrain shader if you buy the urp version. It got my game running on oculus quest 1 with it

2 Likes

@Alixar You guessed it! my terrain was set to static and I had a baked lightmap assigned to it. I set it to non-static and re-baked my lighting. problem solved! now I can see my trees shadows on the terrain in VR. However, the performance is still pretty heavy on the headset.
@RogueStargun Thank you for sharing the asset! I might give it a try once all my other task list items are checked :slight_smile:

If anyone ends up trying microsplat, I’d be interested to hear back how performance compares to Unity built-in terrain

@Alixar thank you for filing the bug! QA has already contacted me and we will continue working to improve the perf situation

Thanks @jeremyco for your feedback, if you need my help just let me know!

@alttabb I’m happy you solved it, but as you noticed the performance impact is quite significant on the headset. My suggestion is to use as many static objects as possible, disable real-time shadows and avoid real-time lights. I know it doesn’t sound appealing, but there’s only so much we can do on the headset :slight_smile:

We do a lot with terrain, and I’d suggest that if you want really good performance, you need to write your own shaders. Use the Unity shaders as a base, and strip out absolutely everything you don’t use. Granted, our use-case is lots of relatively simple terrain, but we are running at full FPS on Quest 2 and - I have to say - it is awesome. For reference, we are using 8 texture units (a global color map, 4 splats used as details, splat control map, shadow map and… something else I forgot.) One light, fog, no normal mapping.

Figure out what you really want/need, throw away everything else, and see where you are.

I was the one who recommended microsplat in an earlier post.

I can confirm that the default Unity Terrain shader for URP suffers extreme frame rate drops on the oculus quest even when I strip out the normal map from every texture.

Microsplat on the other hand has a setting to turn off normals in the shader itself (which allows me to author terrain and potentially improve the terrain art in the future for releases on higher end platforms).

An example of microsplat in action (with disabled normal maps) can be seen in this video:

https://www.youtube.com/watch?v=uICfXO9CHGI

I can confirm that my game (with post-processing effects turned off) runs smoothly with microsplat terrain, but turns into a slideshow with standard unity urp terrain.

1 Like