VR Compositor Layers & OVROverlay

OVROverlay is a script in Oculus/VR/Scripts that renders to VR Compositor Layers (a kind of TimeWarp layer) instead of drawing directly to the eye buffer.

Objects and textures rendered as compositor layers 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 raytraced through the lenses. This improves the clarity of the textures or text displayed on them.

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

OVROverlay supports up to 15 layers in a single scene. However, each scene may have no more than one cylinder and one cubemap layer per scene.

If a compositor layer fails to render (e.g., you attempt to render more than the maximum number of compositor layers), only quads will fall back and be rendered as scene geometry, cubemaps and cylinders will not display at all.

If you need to support more than 15 objects, you can combine planar elements into a single RenderTexture and use a single OVROverlay layer.

Add an Overlay (or Underlay) Layer

In the Hierarchy view of the Unity Editor, create an empty GameObject then drag the OVROverlay script (Oculus/VR/Scripts) on to the GameObject you created.

Note: OVROverlay requires the use of OVRManager.

The script contains the following configurations:

Current Overlay Type

The type of overlay layer. Options are ‘Overlay’, ‘Underlay’, and ‘None’. ‘Overlay’ is the default and will be rendered in front of the eye buffer. ‘Underlay’ will be rendered behind the eyebuffer. ‘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’ will hide the layer.

Composition Depth

Set the depth of the layer. Will be used to determine the ordering of layers in the scene. The overlay/underlay with smaller compositionDepth would be 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

To ignore composition depth simply check the No Depth Buffer Testing checkbox.

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

Be aware that 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’s been implemented as an overlay and ‘No Depth Buffer Testing’ has been selected. This sends conflicting cues about the depth of these objects, which can be uncomfortable.

Overlay Shape

Select the shape of the overlay layer. Quad, Cubemap, and Cylinder compositor layers are supported by Rift, Oculus Go, and Gear VR. Equirect and Offcenter Cubemap compositor layers are currently only available on Oculus Go and Gear VR.

  • Quad layers are a flat texture with four vertices. Commonly used as a panel to display text or information in a scene.
  • Cubemap layers are textures comprised of six squares that form a cube to surround an object. Commonly used for reflections and background/surroundings of a scene. Cubemaps can also be used 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. Cylinder layers are commonly used for curved UI interfaces.
  • Equirect layers are single textures that are 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 (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’ (default), it will use the renderer.material main texture, if available.

Dynamic Texture

Select if the content rendered to the overlay will be dynamic, 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 (Rift development only)

Select the Is Protected Content checkbox to protect the layer with HDCP.

Is External Surface (Android development only)

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

This feature allows an Android Surface to be created and managed by the timewarp layer. In your Unity project you can create a quad overlay and render the Surface texture directly to the TimeWarp layer. The Animated Loading Screen tech note contains a sample script that demonstrates how to do this.

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

Use Default Rects (Android development only)

When a Cylinder or Offcenter Cubemap layer is selected the “Texture Rects” section with a Use Default Rects option. This is selected by default.

This feature allows you to define a single input texture that consists of both the left and right image. Set this texture as the Left Texture. Do not set the same texture to both eyes.

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

Override Color Scale

Selecting the Override Color Scale checkbox opens a Color Scale and Color Offset input. These inputs allow you to override any global color settings for the layer.

Using Underlays

Underlays depend on the alpha channel of the render target. If a scene object that should occlude an underlay is completely opaque, set its alpha to 1. If the occluder is transparent (alpha 0<1), you must use the the Underlay Transparent Occluder.shader provided (VR/Resources). Overlays do not require any special handling for transparency.

After all the objects have been drawn to the eyebuffer you should “poke a hole” in the texture. Use the Underlay Imposter.shader (VR/Resources) on your to draw imposters in the delta space after all opaque textures are drawn, but before the alpha. This allows the underlay to show through the “empty” space.

Example

In the example below, 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.

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

Note that if the cubemap in our scene were transparent, we would need to use the OVRUnderlayTransparentOccluder, which is required for any underlay with alpha less than 1. If it were stereoscopic, we would need to specify two textures and set Size to 2.

Cylinder and Offcenter Cubemap Overlays (Android development only)

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 will fade 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.

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. For more information, see OVROverlay in our Unity Scripting Reference.

World-locked vs Head-locked Layers

Overlay layers should almost always be world-locked, meaning 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 the OVRCameraRig center eye anchor.

Common OVROverlay Use Cases

Loading Screen

Lightweight loading screens can be added using two OVROverlay layers. First add a cubemap layer that will be the background of the loading screen. You may choose to leave this blank, it will display as a black void. Then add another overlay layer, usually a simple quad, with some texture or text that indicates that the user is in a loading interstitial.

See the OVROverlay sample in the SampleFramework for an example.

High-quality video / animation (Android development)

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

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

Gaze 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 as described in the Head-Locked Layers section above.

OVROverlay Samples

See the OVROverlay Sample in the Sample Framework for a demonstration of the differences in overlays and for some sample code you can use in your project.