Here we gooooo!
-
The first thing you want to do is dig into Project Settings and (i just click ‘All Settings’ and use the search bar) find ‘Forward Renderer’. You want to enable Forward Shading and Vertex Fogging for Opaque, but the big one you should enable is Forward Shading. This changes the engine’s renderer to a ‘forward’ rendering method instead of a ‘deferred’ rendering method where (and this is a massively simplified explanation) it renders fewer buffers faster and pushes the frame once it’s done, rather than waiting for all the render buffers to be calculated before assembling the frame and pushing it to the displays. You won’t be able to access a few buffers like Scene Depth, but you’ll see somewhere around a 20% performance increase.
-
Next, hit up Engine>Rendering>Mobile and enable Disable Vertex Fogging (tick the box, this is phrased oddly), set the max number of CSM Cascades to 2 or 1, set Mobile MSAA to 4x or lower (use your best judgement in testing) and enable Use Legacy Shading Model. None of this will kneecap your visual quality, but will improve performance at least a bit, and will be handy if you deploy to Quest/2 as a standalone package.
-
Enable Occlusion Culling and Round Robin Occlusion Culling. Occlusion culling will stop oobjects and meshes from being rendered if theyre not visible to the player, and Round Robin Occlusion Culling means that in VR, this occlusion testing is done in one eye at a time, which lowers a bit more overhead.
-
In Engine>Rendering>Default Settings, disable Bloom, Ambient Occlusion, Motion Blur and Lens Flares. Each of these is an additional render pass, and expensive, so disable for more performance boosts. Ill get to materials in a bit, but ill note here that you can create materials in such a way that objects will generate AO as baked, static lighting which is a handy alternative to real-time AO. While we’re here, set Anti-Aliasing Method to MSAA; its the best tradeoff between performance and visual fidelity.
-
In Engine>Rendering>VR, disable Mobile HDR and enable Instanced Stereo. This is also where RR Occlusion Queries is, for reference. I haven’t tested performance with Mobile Multi-View enabled, but this may reduce some overhead in standalone Quest/2 projects. It’s the instanced stereo option that’s critical to enable, as this will instance draw calls per-eye, which should give you a performance boost of around 30-45%.
-
In your level’s World Settings, find an option under VR called Mono Culling Distance. This is the distance from the camera at which the engine stops rendering in stereoscopic and will only render in monoscopic. This means that beyond a certain distance, the engine only needs to render everything once and pipe it to both eyes, which is ideal for background assets. By default this is disabled (set to 0.0) but start with like 500 and see how it looks.
-
Practices. Try to avoid using post-processing, as this means an additional render pass, but if this is unavoidable, at least try to use a naked PP volume without any PP materials. Don’t use dynamic lighting if you can avoid it; dynamic lights are a disaster for performance in the best of circumstances, so get used to wrangling lighting builds. Don’t use fog. Don’t use translucency (or at least as little as possible) and avoid complex materials with lots of instructions.
-
There’s an adage in VR development that states “Code like its 1999”, and it rings true. You want to be using simple materials, optimized meshes, static lighting, and minimal complex calculations such as physics. LOD aggressively. I’ll repeat, LOD AGGRESSIVELY. You can either import your own LOD meshes for props or let the engine generate them for you, but either way the most meaningful way to reduce quad overdraw and therefore per-frame processing time is to use LODs.
-
Materials. As I mentioned, just avoid translucency if possible. Masked materials (with dithered translucency) are better, but ideally you just want to not use translucent or masked materials. You can add static AO to your materials, and after a lighting build, you can manipulate that AO like any other texture mask. Speaking off, mathematical calculations require way less memory than texture lookups, so if you can, either pack your textures or try to use colors and simple greyscale pngs. Furthermore, you should create a single master material for all your textured objects and use instances to shade your scene - this is a huge way to reduce GPU overhead, due to the engine only needing to reference one material, instead of a different material for each object. Lastly, there’s an option in the material settings called ‘Fully Rough’ which basically forces a roughness of 1 and saves a heap of material instructions. You can use fresnel nodes and normal maps to get some kind of shine back on surfaces. Beware normal maps, however, because in some cases they can display differently in each eye.
Apologies for the long essay! This is by no means exhaustive and Im sure others here will have more notes, but this should get you started