Oculus Quest Development

All Oculus Quest developers MUST PASS the concept review prior to gaining publishing access to the Quest Store and additional resources. Submit a concept document for review as early in your Quest application development cycle as possible. For additional information and context, please see Submitting Your App to the Oculus Quest Store.

Using VR Compositor Layers

Compositor layers let you render certain forms of content such as text, video, or textures with higher quality than traditional eye-buffer rendering can achieve. To understand the benefits that compositor layers provide, and how you can use OVROverlay to implement them, let’s start by understanding the differences between compositor layers and eye-buffer rendering.

Understanding Differences Between Eye-buffer Rendering and Compositor Layers

Eye-buffer rendering is widely used by Oculus apps to render scenes. The Oculus VR runtime allocates a swap chain, which contains a collection of eye buffers. It is a set of textures, and for each frame, the Unity app simply renders the contents of the scene into one of those textures. Under this scenario, the Unity client app is only responsible for rendering its contents into the swap chain. After that, it is VR runtime’s job to take the eye buffer content from the swap chain and perform the scan out operation to draw that content to the physical screen. This process is known as Timewarp.

Compositor layers are useful for displaying information, text, video, or textures that are intended to be focal objects in your scene. They are also useful for displaying simple environments and backgrounds to your scene.

The reason why compositor layers can provide higher visual quality is that it’s always advantageous to only perform Timewarp by sampling from a layer’s texture directly, as opposed to using the layer texture to first render to the eye buffers, and then performing Timewarp on the resulting eye buffer. A good example is video rendering. Therefore, layers can be thought of as a way of passing a texture directly to Timewarp, as opposed to using the texture to render to the eye buffers.

Objects and textures rendered as compositor layers also render at the frame rate of the compositor, the refresh rate of the HMD, instead of rendering at the application frame rate. Because of this, the compositor layers are less prone to judder and are ray-traced through the lenses. This improves the clarity of the textures or text displayed on them.

Using OVROverlay Script to Add Compositor Layers

OVROverlay is a script available in the Oculus/VR/Scripts folder that enables the compositor layers.

OVROverlay supports up to 15 layers in a single scene. However, each scene cannot contain more than one cylinder and one cubemap layer per scene. If a compositor layer fails to render, only quads fall back and are rendered as scene geometry. Cubemaps and cylinders are not displayed at all. A common example is when you attempt to render more than the maximum number of compositor layers. If you need to support more than 15 objects, you can combine planar elements into a single RenderTexture and use a single OVROverlay layer.

Adding an Overlay or Underlay Layer

  1. In the Hierarchy view of Unity Editor, create an empty GameObject.
  2. Drag the OVROverlay script from the Oculus/VR/Scripts folder on to the GameObject. Note: OVROverlay uses OVRManager.

Understanding OVROverlay Script Configurations

The OVROverlay script contains several configuration settings.

Current Overlay Type

Select the type of overlay. Options available are Overlay, Underlay, and None.

  • Overlay is the default type. It is rendered in front of the eye buffer.
  • Underlay is rendered behind the eye buffer. The Underlay compositor layers are more bandwidth-intensive, as the compositor must punch a hole in the eye buffer with an alpha mask so that underlays are visible. Texture bandwidth is often a VR bottleneck, so use them with caution and be sure to assess their impact on your application.
  • None hides the layer.

Composition Depth

Set the depth of the layer. It is used to determine the ordering of layers in the scene. The overlay/underlay with smaller compositionDepth is composited in the front of the overlay/underlay with larger compositionDepth. For example, a scene with numerous overlays and underlays would be -

[Camera] (Overlay) 2 / 1 / 0 [Eyebuffer] -1 / 0 / 1 (Underlay)

No Depth Buffer Testing

Ignore composition depth. Check the No Depth Buffer Testing checkbox to ignore the composition depth.

You can chose to ignore the depth hierarchy in certain situations, like loading or pausing a screen overlay, and have your OVROverlay layer always render on top of the scene.

Note: It’s possible for an object that should be behind another object, in terms of distance from the camera, to be drawn in front because it is implemented as an overlay and you’ve chosen to ignore the composition depth. This sends conflicting cues about the depth of these objects, which can be uncomfortable.

Overlay Shape

Select the shape of the overlay layer. Options available are Quad, Cubemap, and Cylinder compositor layers.

Equirect and Offcenter Cubemap compositor layers are currently only available on Oculus Go.

  • Quad layers are a flat texture with four vertices. Most commonly used as a panel to display text or information in a scene.

  • Cubemap layers are textures that contain six squares to form a cube to surround an object. Most commonly used for reflections and background or surroundings of a scene. You can also use it for low overhead loading or startup scenes. See the Cubemap Screenshots page for more information about cubemaps.

  • Cylinder layers are a single texture that is wrapped around the camera in a cylinder. Most commonly used for curved UI interfaces.

  • Equirect layers are a single texture that is wrapped into a sphere and projected to surround the user’s view. Most commonly used for 360/180 video playback.

  • Offcenter Cubemap layers are cubemaps where the centroid is moved forward on the z axis 30 degrees, enabling higher fidelity, in terms of more pixels, in front of the user.

Textures

Associate the texture that you’d like to render on the the overlay layer. If you leave it as None, which is the default option, it uses the renderer.material main texture, if available.

Dynamic Texture

Select if the content rendered to the overlay is dynamic, which means if the texture should be updated each frame while the overlay persists. This checkbox is automatically checked when a rendertexture is associated with the layer.

Is Protected Content

Select if you want to protect the layer with HDCP on Rift and L1 Widevine DRM on Oculus Quest.

For Oculus Quest: To enable support on Oculus Quest you must also render the OVROverlay layer as an External Surface and select Protected Content in Player Settings > Virtual Reality > Oculus.

Is External Surface

Select the Is External Surface checkbox to identify that the layer will be used to pass through textures or video from an external Android Surface.

This feature allows the creation of Android Surface and lets Timewarp layer manage it. In your Unity project, you can create a quad overlay and render the Surface texture directly to the TimeWarp layer. For more information about rendering surface texture, go to the Animated Loading Screen tech note.

Use the External Surface Width and External Surface Height to define the size of the output.

Use Default Rects

When you select Cylinder or Offcenter Cubemap layer, you can define a single input texture that consists of both, the left and the right image. Set the texture as Left Texture. Do not set the same texture for both eyes.

Unchecking this box opens the Source Rects dialog where you can define how the left and right texture are positioned in the single input texture. ‘Monoscopic’, ‘Stereo Left/Right’, and ‘Stereo Top/Bottom’ presets are available for quick selection.

Override Color Scale

Override any global color settings for the layer. Select the Override Color Scale checkbox to set a Color Scale and Color Offset input.

Using Underlays

Underlays depend on the alpha channel of the render target. Do the following to add underlays:

  1. Set alpha to 1, if a scene object that should occlude an underlay is completely opaque. If the occluder is transparent, i.e., alpha 0<1), you must use Underlay Transparent Occluder.shader from the VR/Resources folder.

    Note: Overlays do not require any special handling for transparency.

  2. Poke a hole in the texture after all the objects are drawn to the eye buffer.
  3. Use Underlay Imposter.shader from the VR/Resources folder to draw imposters in the delta space. Ensure you perform this operation after all opaque textures are drawn, but before the alpha. This allows the underlay to show through the empty space.

Example

In the following example, most of the scene geometry is rendered to the eye buffer. The application adds a gaze cursor as a quad overlay and a skybox as a cubemap underlay behind the scene.

Take a note of the dotted sections of the eye buffer, indicating where OVROverlay has punched a hole to make the cubemap underlay visible behind scene geometry.

Check if the cubemap in the scene is transparent. If yes, use OVRUnderlayTransparentOccluder, which is required for any underlay with alpha less than 1. If it is stereoscopic, specify two textures and set the size to 2.

Using Cylinder Overlays

The center of a cylinder overlay game objects is used as the cylinder’s center. The dimensions of the cylinder are encoded in transform.scale as follows:

  • [scale.z] cylinder radius
  • [scale.y] cylinder height
  • [scale.x] length of the cylinder arc

To use a cylinder overlay, your camera must be placed inside the inscribed sphere of the cylinder. The overlay fades out when the camera approaches to the inscribed sphere’s surface. Only half of the cylinder may be displayed, so the arc angle must be smaller than 180 degrees.

Using Offcenter Cubemap Overlays

Offcenter cubemap compositor layers are useful for increasing resolution for areas of interest/visible areas by offsetting the cubemap sampling coordinate. They are similar to standard cubemap compositor layers.

Attach the OVROverlay script to an empty game object and specify the texture coordinate offset in the Position Transform field. For more information, see OVROverlay in the Unity Scripting Reference.

World-locked vs Head-locked Layers

Overlay layers should almost always be world-locked, which means that they maintain their position with respect to the world behind it.

  • World-locked overlays use TimeWarp, similar to non-overlay content, and are much less prone to judder.
  • Head-locked overlays bypass TimeWarp and exactly follow head motion. The exception being small UI elements like a gaze cursor or targeting reticle.

Overlays are world-locked by default. To make a head-locked overlay, make the layer (usually a Quad) a child of OVRCameraRig center eye anchor.

Common OVROverlay Use Cases

We have listed a few common use cases for using compositor layers and different OVROverlay features.

Playing High-quality Video Playback

It is extremely important for video playback apps to use compositor layers instead of rendering to the eye buffers that Unity ordinarily renders into.

There are two ways to use OVROverlay to display high quality video:

  • To play video on an overlay layer that is rendered or created in game, you can override the Use Default Rects feature. This allows you to render a single texture, saving the cost of rendering two textures, at a higher resolution.
  • To play high-quality external video, use the Is External Surface feature to use an Android plugin to feed external video directly into the compositor.

Loading Screen

Lightweight loading screens can be added using two OVROverlay layers.

  1. Add a cubemap layer that is the background of the loading screen. If you leave this blank, it displays a black void.
  2. Add another overlay layer, usually a simple quad, with some texture or text that indicates that the user is in a loading interstitial.

For more information, open the OVROverlay sample from the SampleFramework folder.

Gazing cursor or targeting reticle

To add a gaze cursor or targeting reticle (or similar), add an OVROverlay quad to your scene as a child of the OVRCameraRig center eye anchor.

OVROverlay Samples

We have demonstrated OVROverlay features in the OVROverlay Sample documentation. You can open the OVROverlay sample from the SampleFramework folder in Unity Editor.