Tips and Tricks for Oculus Quest Development with Unreal Engine 4(.25.3) — Part 1, Level Composition

Andrew Omernik
7 min readJan 21, 2021

So you want to be a virtual reality developer. Me too! And while it has a number of idiosyncrasies, it can be fun, rewarding, and ultimately some of the coolest development you may get to do.

Quick aside about me: I got into Unreal 4 in 2014, as some friends and myself began a company that provided high quality simulation training to some of the world’s largest humanitarian aid organizations. We were even featured at the World Humanitarian Summit in Istanbul in 2016. Since then, company turnover and my military obligations (I am a National Guardsman and proud to be) led me to shuttering the company and deploying overseas. As a project, I decided to learn how to develop in virtual reality, and chose the Oculus Quest (more on that below). The following article(s) represent the tips and tricks I’ve learned on this journey, and hopefully some that can help you (because the virtual reality sector is better if we build it together).

I chose Oculus Quest for my project overseas for a number of reasons. Cost, features, support, and the fact that it is untethered all play into that. Some potential developers have expressed some reservation regarding Facebook’s policy of tying it to an account, but I honestly haven’t noticed any issues with that, nor do I see a huge influence on my Facebook ad feed, so I consider that a non-issue. Lastly, its ongoing support (yes, I am aware that Quest 2 is out, and that it is more powerful than Quest 1) and feature sets made it very attractive indeed. This feature-set does come with a number of development considerations however, particularly in the performance department.

This article will cover eight major tips, level composition, particle effects, settings, landscape issues, Oculus branch of UE4, mesh reduction, visual debugging, and some common errors.

Level Composition

Part of the inspiration for this set of posts is that I’ve received a great deal of interest on my level composition workflow. The amount of detail I’ve been able to include and still be performant (on a physics demanding application) has impressed some people, and thus I wanted to share the concept.

Level Building for Oculus Quest is demanding and requires constant focus on optimization. I have extensively experimented with this concept, and have settled on a workflow that meets framerate requirements (constant above 60 or 72, depending on settings) and also provides the visual fidelity I seek.

Key to this is the gray box stage, or level block out stage. As many level designers can attest, the first step to actually working on a level is blocking out the concept, making the sure the size and scale work, particularly if you are doing a larger, more adventure based level versus a stationary level one would find in games like Beat Saber. Gray boxing often relies on basic meshes, from a blockout kit or just using the built in Unreal 4 basic shape primitives (or BSPs, which are basic geometry shapes with some rudimentary functionality built in, such as UV panning, add/subtract functions, and resizing). You first need to identify the basic level shapes you will be working with. From there use the BSPs to carve out those shapes, keeping an eye on modularity.

Basic shape modeled out of BSPs

Notice the BSPs in the picture above (which include a block out castle) are carved out for the gatehouse and walls. Materials are applied and UVs are adjusted to minimize lines and breaks. From here, group everything together that you want to comprise “that” object, and Alt-copy the group off to the side. Do a good examination to ensure that all carved out areas are appropriate and that the group includes everything you need.

If this is a shape I will use alot, I will take the copy and move it to the side in a sort of “palette” area for my level (see below).

Palette for finished BSP brushes

This palette area has BSPs that are literally ready to go, but have not been made into static meshes just yet. There is a reason for this! As I am working on a ruined castle, I need more areas subtracted out from my finished meshes, and the BSP stage is the best way to manage that. Going back to my in-place BSP, I will add those subtraction brushes to match ruined pieces from my kitbash set (full disclosure, I am not an artist so my art assets come from the Unreal Marketplace). The next stage looks like the below picture:

Holes, all the holes

Mesh Settings

Now that we have our spaces made, I like to group those subtraction brushes, select the main object, and regroup so everything is together. Then I convert the mesh to a static mesh, save to my worldmeshes folder, and change some settings. First, I set the Lightmap settings to force surface. This ensures proper lighting quality while minimizing the cost (for the most part, all of your lighting should be static). Then I go into the static mesh editor itself and change two sets of settings (pay attention, these are CRITICAL for proper rendering):

Static Mesh Settings

First, set the lightmap resolution to an appropriate number. For simple meshes I use 128, and for larger, more complex ones I will use 256. All lightmap resolutions should be a power of 2. The default setting will have been set to 4. Then set the Light Map Coordinate Index to 1, from its default setting of zero. This ensures its inclusion to the proper UV coordinate channel.

MOAR Static Mesh Settings

Set the LOD for Occluder Mesh to 0 (yes you want this big, basic mesh to work as an occluder mesh). And finally, unless the object is simple enough for you to generate simple convex collision (anything with doorways will likely not work out so well) use complex collision as simple. This is important for VR as invisible walls tend to be VERY immersion breaking.

From here, we go back to our kitbash, and start pulling out our detail meshes.

Detail Work

These meshes fit right in, and provide much needed visual or narrative pops to our level. That said, this amount of visual detail is still extremely optimized, as the majority of that scene (the gatehouse and wall) we just made, which comprises roughly 3/4 of the render-able pixels, is a scant 940 triangles, and uses the same material as the rest of the detail meshes. This beats the heck out of instancing or HLODs on small wall sections, as to construct this same, base scene, the bare sections of walls might include as many as twenty individual meshes, each of which compounds the draw calls and hurts FPS. For comparison, the scene with the twenty instanced meshes may have 4,000 triangles just counting all of the straight, regular shaped walls, not counting any of the doorways, or archs, or arrow slits we’ve built in. Those might add anywhere from 2,000 to 10,000 additional triangles. While its tough to see a final touch from this angle (given the unfinished castle in the background), a prior ruined tower and gate are below:

Ruined tower and gate angle 1
Ruined tower and gate angle 2

This scene here, despite being visually complex, runs at full frames per second, even when viewed from the previous gate tower at a distance. Use of LODs for detail meshes, the simplified base meshes, and shared materials all contribute heavily to the scene’s good performance. The proper intent of this scene will be gameplay at night, so that will be a different setting all together, but visualizing during the day helps us track down and eliminate lighting artifacts before it becomes a problem.

Profiling

For the tech nerds out there, the performance benchmarks are as follows. Similar (actually less detailed scene) using the kitbash objects with LODs turned down:

Draw Calls : 350

Frames per Second : 45(this is showing stuttering on the Oculus Quest, as well as screen tearing)

Observable graphical artifacts : 13

Kitbashing
Comparative Scene

This comparative scene (a bit more fleshed out from the above, including another tower) is fully 4x the size of the kitbash scene. It has more complexity, more things to do, more everything. It was also profile from a distance, resulting in alot of other parts of the scenery (other buildings etc) being drawn in. The stats:

Draw Calls : 560 (yes this is higher, but again, MUCH larger scene)

Frames per Second : 72 (aka buttery smooth)

Observable graphical artifacts : 1

Additionally, and harder to show, is that this performance stays even when engaging in gameplay (which for a physically based melee combat game, is GPU intensive).

Thanks for following along with Part 1 of the Oculus Tips and Tricks Guide. I stream on weekends showing off this and other workflows (and sometimes just gameplay streams because sometimes, stress relief is beating evil henchmen around with claymores in VR). Take care, and happy development!

--

--

Andrew Omernik

Unreal Developer, machine-learning neophyte, learning with Oculus Quest and working on making the switch from simulation to game development.