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.
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.
The script contains the following configurations:
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.
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)
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.
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.
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.
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.
Select the Is Protected Content checkbox to protect the layer with HDCP.
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.
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.
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.
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
OVRCameraRig 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.
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.
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:
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.
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.
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.
There are two ways to use OVROverlay to display high quality video/animation:
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.
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.