Color Mapping Techniques
The Color Control feature provides a number of different techniques to map each input color to a different output color. The following options are available:
- None: Display passthrough images unchanged.
- Color Adjustment: Adjust the image’s brightness, contrast, and saturation. Saturation adjustment only has an effect on devices that support color passthrough.
- Grayscale: Adjust brightness and contrast and apply a posterization effect to grayscale passthrough images. Color passthrough images are converted to grayscale first if this option is chosen.
- Grayscale To Color: Colorize grayscale passthrough images, adjust brightness and contrast, and apply a posterization effect. Color passthrough images are converted to grayscale first if this option is chosen.
- Color LUT: Apply a color look-up table (LUT), which maps each RGB input color into an arbitrary RGB(A) in the passthrough image stream.
- Blended Color LUTs: Apply the blend between two color LUTs to the passthrough image stream. This option can be used to smoothly transition between two color LUTs.
The options
Grayscale and
Grayscale To Color are mainly provided for compatibility reasons. The
Color Adjustments,
Color LUT, and
Blended Color LUTs options let you build apps that can leverage color passthrough. You can check if the current device supports color passthrough using the
SupportsColorPassthrough flag, which is obtained from
OVRManager.GetPassthroughCapabilities, and adjust the styling accordingly.
Color Look-Up Tables (LUTs)
A color LUT is a 3D array which maps each RGB color to an arbitrary new RGB(A) color. Color LUTs enable a wide range of effects, ranging from subtle color grading to stylizations such as posterization, selective coloring, and chroma keying.
To apply a color LUT to an OVRPassthroughLayer component, follow these steps:
- In the OVRPassthroughLayer component, under Color Control, select Color LUT.
- Under LUT, select a 2D texture that represents a color LUT. See Creating Color LUTs for more information on supported formats and how to generate them.
- Check Flip Vertically if the LUT has black (RGB values 0, 0, 0) in the top-left corner of the texture, otherwise uncheck it.
- The Blend slider controls the mix between the original and the replacement color. Leave it at 1 to fully apply the LUT.
To apply a color LUT via scripting interface, do the following:
- Create an instance of
OVRPassthroughColorLut. The LUT data can be passed as a 2D texture or as 3D array of color values. Refer to the API reference for all constructor signatures. - Call
SetColorLut on the instance of OVRPassthroughLayer the color LUT should be applied to, passing the OVRPassthroughColorLut instance as the first parameter. The weight parameter corresponds to the Blend value specified in the inspector. - Optionally, you can apply an
OVRPassthroughColorLut instance to multiple passthrough layers by passing it to SetColorLut calls on multiple layers.
This excerpt demonstrates the essential statements discussed in this section:
public class PassthroughColorLUTController : MonoBehaviour
{
Private Texture2D _2dColorLUT;
OVRPassthroughColorLut ovrpcl;
// other code...
GameObject ovrCameraRig = GameObject.Find("OVRCameraRig");
passthroughLayer = ovrCameraRig.GetComponent<OVRPassthroughLayer>();
ovrpcl = new OVRPassthroughColorLut(_2dColorLUT, false);
passthroughLayer.SetColorLut(ovrpcl, 1);
}
Animating Color LUT Transitions
OVRPassthroughLayer.SetColorLut is a lightweight operation that doesn’t add a lot of overhead and can be called in every frame. To fade a color LUT in or out, call
with a varying value for weight during the transition. To transition between two different color LUTs, call
SetColorLut(lutSource, lutTarget, weight)
with a varying value for weight during the transition.
Animate Color LUT Contents
Some use cases require color LUTs to change continuously beyond linear interpolation. For example, an app could dynamically adjust the saturation of different color hues based on the state of the app or external input (such as audio).
Call
UpdateFrom on an instance of
OVRPassthroughColorLut to update the LUT data of an existing color LUT. The updated data will automatically be used on all passthrough layers that are currently using that
OVRPassthroughColorLut instance. There is no need to call
OVRPassthroughLayer.SetColorLut to propagate the changes.
For high-resolution color LUTs (especially 64), calling UpdateFrom in every frame can have a notable impact on app performance. In such cases, try to keep the LUTs as small as possible - a resolution of 32 or lower is recommended.
- There is a constraint on the maximum resolution allowed for color LUTs, which can be queried using
OVRManager.GetPassthroughCapabilities. On current Meta Quest devices, the maximum resolution is 64. - The color LUT resolution impacts memory usage and GPU performance. For that reason, it is advisable to keep the resolution as small as possible given use case and quality constraints. For example, start with a color LUT of resolution 16, then check if increasing the resolution to 32 significantly improves the visual quality.
- For high-resolution color LUTs (especially 64), constructing an
OVRPassthroughColorLut object can take a few milliseconds and is best done in advance. OVRPassthroughColorLut instances occupy an amount of memory that is proportional to the LUT data size. Dispose can be called to free the memory immediately.- An instance of
OVRPassthroughColorLut can be applied to multiple passthrough layers by passing it to SetColorLut on multiple layers. Doing so reduces the memory usage (compared to creating a separate OVRPassthroughColorLut instance per layer).