6 Things You Haven’t Optimised In Your WebVR Content

Michael Andrew
5 min readJan 5, 2018

--

If you’re like me and have been playing around with WebGL and WebVR in the browser, you’ll have run into some nasty performance problems when you’ve added too many complex objects to your scenes. Fortunately, there are 6 ways you can avoid common pitfalls and make your 3D experience buttery smooth for users.

WebGL has been around for a while now, but only in the past few years has it gained enough traction in terms of browser and hardware support to be a viable target for games, experiences and applications on both mobile and desktop. This has made it very accessible for content creators and programmers alike to jump in and start creating, without an extensive background in 3D graphics. Especially with the arrival of WebVR, and its support for mobile devices and multiple users on different platforms, it’s critical that a high and stable FPS count is maintained for the best experience.

The biggest gains in performance involve tweaking the following:

  • Model geometry vertex and face counts
  • The number of objects and lights in the scene
  • UV texture sizes on models
  • The amount of lights
  • Texture sizes and number of cast shadows
  • Complexity of far geometry

1. Vertices & Faces

In your 3D modelling tool you can reduce the number of vertices and faces in your model’s geometry improve performance. Blender has a feature called Decimate which can automatically do this for you with some adjustable parameters.

For models with existing UV textures, you can decimate, preserving UVs using planar dissolve and selecting delimit: UVs so the textures don’t break. While this isn’t quite as optimal as completely re-doing your mesh and UVs, it’s a hell of a lot faster.

2. Object Count

Each object mesh instance creates a draw call (a command that draws each graphical primitive). Each draw call uses CPU time to dispatch to WebGL. You should be keeping the number of draw calls minimal, especially when targeting mobile devices. For low-end mobile devices, aim for 100 to 200 draw calls. High end desktops can process thousands of draw calls every frame and still hit 60FPS.

Geometry Merging

For static objects in the scene, you can get gains in performance by utilising geometry merging within THREE.js, this will reduce the number of draw calls needed as multiple objects get combined into one. Ideally you should merge geometry for objects that will remain non-interactive in the scene, although aframe-geometry-merger-component does support optionally keeping an invisible copy of the original objects for ray-casting against when detecting collisions.

Example with aframe-geometry-merger-component

Example without aframe-geometry-merger-component

Geometry Instancing

William Murphy has a great YouTube Video on performance gains for visualising data with many objects using THREE.InstancedMesh, a high level abstraction for THREE.InstancedBufferGeometry in THREE.js:

A large number of data points can be displayed using instanced geometry buffers

Object Pooling

Sticking your objects in a pool can make it easier to maintain a consistent FPS, as the garbage collector doesn’t need to kick in while your scene is running to recycle old objects. In the case of a bullet being fired from a gun, under the hood, A-Frame will create 5 “bullet” objects when the scene is initialised and recycle them instead of creating brand new objects for each bullet that is fired. Using A-Frame’s pool component make this easy:

Now, whenever you get an entity from the pool component in your scene JavaScript, it will return one of the 10 enemies you set up for the pool in your HTML:

3. Texture Sizes

Use as small a texture size as possible, and max 2048x2048px for all platforms. Mobile devices generally will suffer at sizes over 2048px due to insufficient memory.

Your texture width and height should be a power if 2 (e.g., 128, 256, 512, 1024, etc.). If it’s not, the texture will be resized when the scene loads, increasing load times.

Be sure to compress your textures. Use the .png file format if you require transparency, otherwise stick to .jpg. This will help your scenes load faster as the file sizes will be smaller. There are also some great tools out there to optimise your png and jpg files.

4. Lights

The number of lights in your scene directly impacts performance. Keep these to a minimum and look at ways of baking your lighting into your textures if the lights don’t need to change once the scene loads. If this is combined with simple transparent meshes, this can create the illusion of complex lighting without the expense.

If appropriate you may also wish to utilise a single global “sun” light source, then dynamically toggle visibility on lights as they come into view of the user.

5. Shadows

Including lots of lights that cast shadows in your scene has always been very expensive. In THREE.js you can restrict the number of objects that can receive them by setting object3D.receiveShadow to true, only for key objects. These will recieve cast shadows from lights that have object3D.castShadow set to true. A-Frame is similar:

It’s also smart to look at how far away objects are from the user and automatically set the object3D.receiveShadow property to false for distant objects. Decentraland’s Alpha client currently supports this, as it needs to render many far away objects.

6. Levels of Detail

Historically in game development, setting levels of detail (LOD) has been a staple of achieving performance in complex levels and environments, especially ones with long draw distances. There’s no point rendering high quality objects that are far from the player, so these are swapped out with a combination of 2D geometry or lower poly 3D models.

What Next?

Make sure to keep these techniques in mind, especially when building large, complex scenes or creating content for mobile devices. They’re sure to give you an edge on your next project!

Thanks

Special thanks to William Murphy for his contributions to this article.

More Resources

--

--

Michael Andrew

VR developer, focusing on mobile virtual reality powered by Unity.