XR_ANDROID_light_estimation_cubemap
Name String
XR_ANDROID_light_estimation_cubemap
Extension Type
Instance extension
Registered Extension Number
722
Revision
1
Ratification Status
Not ratified
Extension and Version Dependencies
XR_ANDROID_light_estimation
Last Modified Date
2025-08-06
IP Status
No known IP claims.
Contributors
Salar Khan, Google
Scott Chung, Google
Jared Finder, Google
Spencer Quin, Google
Levana Chen, Google
Nihav Jain, Google
Jürgen Sturm, Google
Overview
This extension builds upon the basic XR_ANDROID_light_estimation extension. It adds support for getting cubemap lighting estimates, which provides more detailed estimates about the lighting in the physical environment.
Note
The mechanism for getting the light estimate data is the same as the basic extension, except that XrCubemapLightEstimatorCreateInfoANDROID has to be chained to the XrLightEstimatorCreateInfoANDROID when creating the light estimator handle.
Inspect system capability
typedef struct XrSystemCubemapLightEstimationPropertiesANDROID {
XrStructureType type;
void* next;
XrBool32 supportsCubemapLightEstimation;
} XrSystemCubemapLightEstimationPropertiesANDROID;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.supportsCubemapLightEstimationis anXrBool32, indicating if the current system supports cubemap light estimation.
An application can inspect whether the system is capable of supporting cubemap light estimation by extending XrSystemProperties with XrSystemCubemapLightEstimationPropertiesANDROID structure when calling xrGetSystemProperties .
If the runtime returns XR_FALSE for supportsCubemapLightEstimation and XrCubemapLightEstimatorCreateInfoANDROID has been chained to XrLightEstimatorCreateInfoANDROID , the runtime must return XR_ERROR_FEATURE_UNSUPPORTED from xrCreateLightEstimatorANDROID .
Valid Usage (Implicit)
- The
XR_ANDROID_light_estimation_cubemapextension must be enabled prior to using XrSystemCubemapLightEstimationPropertiesANDROID -
typemust beXR_TYPE_SYSTEM_CUBEMAP_LIGHT_ESTIMATION_PROPERTIES_ANDROID -
nextmust beNULLor a valid pointer to the next structure in a structure chain
Getting supported cubemap resolutions
XrResult xrEnumerateCubemapLightingResolutionsANDROID(
XrInstance instance,
XrSystemId systemId,
uint32_t resolutionCapacityInput,
uint32_t* resolutionCountOutput,
uint32_t* resolutions);
Parameter Descriptions
instanceis an XrInstance created previously.systemIdis theXrSystemIdretrieved previously by xrGetSystem for which to get the supported cubemap resolutions.resolutionCapacityInputis auint32_tindicating the maximum number of elements that can be stored in theresolutionsarray.resolutionCountOutputis a pointer to auint32_twhich is set by the runtime indicating the number of elements written to theresolutionsarray by the runtime.resolutionsis an array ofuint32_twhich is populated by the runtime with the supported cubemap resolutions.
A cubemap resolution indicates the width and height of each face of the cubemap in pixels. 2-call idiom The application can then choose to use one of the supported resolutions in XrCubemapLightEstimatorCreateInfoANDROID :: cubemapResolution when creating the light estimator handle. The application must allocate the appropriate amount of memory for the image buffer members of XrCubemapLightingDataANDROID based on the resolution chosen and the color format.
Valid Usage (Implicit)
- The
XR_ANDROID_light_estimation_cubemapextension must be enabled prior to calling xrEnumerateCubemapLightingResolutionsANDROID -
instancemust be a valid XrInstance handle -
resolutionCountOutputmust be a pointer to auint32_tvalue - If
resolutionCapacityInputis not0,resolutionsmust be a pointer to an array ofresolutionCapacityInputuint32_tvalues
Return Codes
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_RUNTIME_FAILUREXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_SYSTEM_INVALIDXR_ERROR_VALIDATION_FAILURE
Getting supported cubemap color formats
The XrCubemapLightingColorFormatANDROID enumeration identifies to the runtime, the color format of cubemap lighting to use.
typedef enum XrCubemapLightingColorFormatANDROID {
XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R32G32B32_SFLOAT_ANDROID = 1,
XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R32G32B32A32_SFLOAT_ANDROID = 2,
XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R16G16B16A16_SFLOAT_ANDROID = 3,
XR_CUBEMAP_LIGHTING_COLOR_FORMAT_MAX_ENUM_ANDROID = 0x7FFFFFFF
} XrCubemapLightingColorFormatANDROID;
The enums have the following meanings:
Enum Description
XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R32G32B32_SFLOAT_ANDROID
A color format with 3 channels where each channel is a 32-bit floating point value.
XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R32G32B32A32_SFLOAT_ANDROID
A color format with 4 channels where each channel is a 32-bit floating point value.
XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R16G16B16A16_SFLOAT_ANDROID
A color format with 4 channels where each channel is a 16-bit floating point value.
XrResult xrEnumerateCubemapLightingColorFormatsANDROID(
XrInstance instance,
XrSystemId systemId,
uint32_t colorFormatCapacityInput,
uint32_t* colorFormatCountOutput,
XrCubemapLightingColorFormatANDROID* colorFormats);
Parameter Descriptions
instanceis an XrInstance created previously.systemIdis theXrSystemIdretrieved previously by xrGetSystem for which to get the supported cubemap resolutions.colorFormatCapacityInputis auint32_tindicating the maximum number of elements that can be stored in thecolorFormatsarray.colorFormatCountOutputis a pointer to auint32_twhich is set by the runtime indicating the number of elements written to thecolorFormatsarray by the runtime.colorFormatsis an array of XrCubemapLightingColorFormatANDROID which is populated by the runtime with the supported cubemap color formats.
2-call idiom The application can then choose to use one of the supported color formats in XrCubemapLightEstimatorCreateInfoANDROID :: colorFormat when creating the light estimator handle. The application must allocate the appropriate amount of memory for the image buffer members of XrCubemapLightingDataANDROID based on the color format chosen.
Valid Usage (Implicit)
- The
XR_ANDROID_light_estimation_cubemapextension must be enabled prior to calling xrEnumerateCubemapLightingColorFormatsANDROID -
instancemust be a valid XrInstance handle -
colorFormatCountOutputmust be a pointer to auint32_tvalue - If
colorFormatCapacityInputis not0,colorFormatsmust be a pointer to an array ofcolorFormatCapacityInputXrCubemapLightingColorFormatANDROID values
Return Codes
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_RUNTIME_FAILUREXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_SYSTEM_INVALIDXR_ERROR_VALIDATION_FAILURE
Create a cubemap light estimator handle
typedef struct XrCubemapLightEstimatorCreateInfoANDROID {
XrStructureType type;
const void* next;
uint32_t cubemapResolution;
XrCubemapLightingColorFormatANDROID colorFormat;
XrBool32 reproject;
} XrCubemapLightEstimatorCreateInfoANDROID;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain.cubemapResolutionis auint32_tindicating the resolution of the cubemap lighting to use.colorFormatis an XrCubemapLightingColorFormatANDROID indicating the color format of the cubemap lighting data to use.reprojectis anXrBool32indicating whether the cubemap lighting should be reprojected to the application base space.
The XrCubemapLightEstimatorCreateInfoANDROID structure describes the information to create an XrLightEstimatorANDROID handle to be capable of providing cubemap lighting estimates. The XrCubemapLightEstimatorCreateInfoANDROID :: cubemapResolution member must be set to one of the resolutions returned by xrEnumerateCubemapLightingResolutionsANDROID . The XrCubemapLightEstimatorCreateInfoANDROID :: colorFormat member must be set to one of the color formats returned by xrEnumerateCubemapLightingColorFormatsANDROID . If the application does not set to the resolution to one of the supported resolutions or the color format to one of the supported color formats, the runtime must return XR_ERROR_FEATURE_UNSUPPORTED from xrCreateLightEstimatorANDROID .
Valid Usage (Implicit)
- The
XR_ANDROID_light_estimation_cubemapextension must be enabled prior to using XrCubemapLightEstimatorCreateInfoANDROID -
typemust beXR_TYPE_CUBEMAP_LIGHT_ESTIMATOR_CREATE_INFO_ANDROID -
nextmust beNULLor a valid pointer to the next structure in a structure chain -
colorFormatmust be a valid XrCubemapLightingColorFormatANDROID value
Cubemap light estimates
typedef struct XrCubemapLightingDataANDROID {
XrStructureType type;
void* next;
XrLightEstimateStateANDROID state;
uint32_t imageBufferSize;
uint8_t* imageBufferRight;
uint8_t* imageBufferLeft;
uint8_t* imageBufferTop;
uint8_t* imageBufferBottom;
uint8_t* imageBufferFront;
uint8_t* imageBufferBack;
XrQuaternionf rotation;
XrTime centerExposureTime;
} XrCubemapLightingDataANDROID;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain. Valid structures are XrAmbientLightANDROID , XrSphericalHarmonicsANDROID , XrDirectionalLightANDROID .stateis the XrLightEstimateStateANDROID representing the state of the light estimate.imageBufferSizeis auint32_tindicating the byte size of each face image buffer in the cubemap.imageBufferRightis auint8_tbuffer containing the right face image of the cubemap.imageBufferLeftis auint8_tbuffer containing the left face image of the cubemap.imageBufferTopis auint8_tbuffer containing the top face image of the cubemap.imageBufferBottomis auint8_tbuffer containing the bottom face image of the cubemap.imageBufferFrontis auint8_tbuffer containing the front face image of the cubemap.imageBufferBackis auint8_tbuffer containing the back face image of the cubemap.rotationis an XrQuaternionf indicating the rotation of the cubemap.centerExposureTimeis anXrTimeindicating the time the cubemap was captured.
This structure can be chained to the XrLightEstimateANDROID . The runtime must only populate this structure in xrGetLightEstimateANDROID if the XrCubemapLightEstimatorCreateInfoANDROID was used to create the light estimator handle. The application must allocate the appropriate amount of memory for the image buffers which is dependent on the values set in XrCubemapLightEstimatorCreateInfoANDROID :: cubemapResolution and XrCubemapLightEstimatorCreateInfoANDROID :: colorFormat when creating the light estimator handle. The application must set XrCubemapLightingDataANDROID :: imageBufferSize to the capacity of each face image buffer in bytes. If the application is not using cubemap light estimation or if XrCubemapLightingDataANDROID :: imageBufferSize is not large enough for the runtime to populate the image buffers, the runtime must set XrCubemapLightingDataANDROID :: state to XR_LIGHT_ESTIMATE_STATE_INVALID_ANDROID .
If the application set XrCubemapLightEstimatorCreateInfoANDROID :: reproject to XR_TRUE when creating the light estimator handle, the runtime must set XrCubemapLightingDataANDROID :: rotation to the identity rotation and ensure the internal rotated cubemap is reprojected onto the faces of an identity cubemap in the application base space.
The layout of the lighting cubemap is same as OpenGL cubemap layout, as shown in the following image
Figure 24. Cubemap layout.
Valid Usage (Implicit)
- The
XR_ANDROID_light_estimation_cubemapextension must be enabled prior to using XrCubemapLightingDataANDROID -
typemust beXR_TYPE_CUBEMAP_LIGHTING_DATA_ANDROID -
nextmust beNULLor a valid pointer to the next structure in a structure chain -
statemust be a valid XrLightEstimateStateANDROID value -
imageBufferRightmust be a pointer to an array ofimageBufferSizeuint8_tvalues -
imageBufferLeftmust be a pointer to an array ofimageBufferSizeuint8_tvalues -
imageBufferTopmust be a pointer to an array ofimageBufferSizeuint8_tvalues -
imageBufferBottommust be a pointer to an array ofimageBufferSizeuint8_tvalues -
imageBufferFrontmust be a pointer to an array ofimageBufferSizeuint8_tvalues -
imageBufferBackmust be a pointer to an array ofimageBufferSizeuint8_tvalues - The
imageBufferSizeparameter must be greater than0
Example code for light estimation
The following example code demonstrates how to get all possible light estimation quantities from the runtime
XrSession session; // Created at app startup
XrInstance instance; // Created at app startup
XrSpace appSpace; // Created previously.
XrSystemId systemId; // Retrieved previously by xrGetSystem
PFN_xrCreateLightEstimatorANDROID xrCreateLightEstimatorANDROID; // Created previously.
PFN_xrDestroyLightEstimatorANDROID xrDestroyLightEstimatorANDROID; // Created previously.
PFN_xrGetLightEstimateANDROID xrGetLightEstimateANDROID; // Created previously.
PFN_xrEnumerateCubemapLightingResolutionsANDROID xrEnumerateCubemapLightingResolutionsANDROID; // Created previously.
PFN_xrEnumerateCubemapLightingColorFormatsANDROID xrEnumerateCubemapLightingColorFormatsANDROID; // Created previously.
XrSystemCubemapLightEstimationPropertiesANDROID props = {
.type = XR_TYPE_SYSTEM_CUBEMAP_LIGHT_ESTIMATION_PROPERTIES_ANDROID};
XrSystemProperties base = {.type = XR_TYPE_SYSTEM_PROPERTIES,
.next = &props};
CHK_XR(xrGetSystemProperties(instance, systemId, &base));
if (!props.supportsCubemapLightEstimation) {
// Cubemap light estimation is not supported
}
uint32_t cubemapResolution = 0;
std::vector<uint32_t> supportedCubemapResolutions;
uint32_t resolutionCount;
CHK_XR(xrEnumerateCubemapLightingResolutionsANDROID(
instance, systemId, 0, &resolutionCount, nullptr));
supportedCubemapResolutions.resize(resolutionCount);
if (resolutionCount == 0) {
// No cubemap lighting supported
} else {
CHK_XR(xrEnumerateCubemapLightingResolutionsANDROID(
instance, systemId, 0, &resolutionCount, supportedCubemapResolutions.data()));
cubemapResolution = supportedCubemapResolutions[0];
}
uint32_t pixelCount = cubemapResolution * cubemapResolution;
XrCubemapLightingColorFormatANDROID colorFormat;
std::vector<XrCubemapLightingColorFormatANDROID> supportedColorFormats;
uint32_t colorFormatCount;
CHK_XR(xrEnumerateCubemapLightingColorFormatsANDROID(
instance, systemId, 0, &colorFormatCount, nullptr));
supportedColorFormats.resize(colorFormatCount);
if (colorFormatCount == 0) {
// No supported color formats for cubemap lighting. Cannot use cubemap
// light estimation.
} else {
CHK_XR(xrEnumerateCubemapLightingColorFormatsANDROID(
instance, systemId, 0, &colorFormatCount, supportedColorFormats.data()));
colorFormat = supportedColorFormats[0];
}
uint32_t pixelSize = 0;
switch (colorFormat) {
case XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R32G32B32_SFLOAT_ANDROID:
pixelSize = 3 * sizeof(float);
break;
case XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R32G32B32A32_SFLOAT_ANDROID:
pixelSize = 4 * sizeof(float);
break;
case XR_CUBEMAP_LIGHTING_COLOR_FORMAT_R16G16B16A16_SFLOAT_ANDROID:
pixelSize = 4 * sizeof(uint16_t);
break;
default:
// Should not happen since the color format was validated previously.
break;
}
uint32_t perFaceImageBufferSize = pixelCount * pixelSize;
XrLightEstimatorANDROID estimator;
XrCubemapLightEstimatorCreateInfoANDROID cubemapCreateInfo = {
.type = XR_TYPE_CUBEMAP_LIGHT_ESTIMATOR_CREATE_INFO_ANDROID,
.cubemapResolution = cubemapResolution,
.colorFormat = colorFormat,
.reproject = XR_TRUE
};
XrLightEstimatorCreateInfoANDROID basicCreateInfo = {
.type = XR_TYPE_LIGHT_ESTIMATOR_CREATE_INFO_ANDROID,
.next = &cubemapCreateInfo};
CHK_XR(xrCreateLightEstimatorANDROID(session, &basicCreateInfo, &estimator));
std::vector<uint8_t> cubemapBuffer(perFaceImageBufferSize * 6); // 6 faces * perFaceImageBufferSize
// Every frame
XrTime updateTime; // Time used for the current frame's simulation update.
XrLightEstimateGetInfoANDROID info = {
.type = XR_TYPE_LIGHT_ESTIMATE_GET_INFO_ANDROID,
.space = appSpace,
.time = updateTime,
};
XrCubemapLightingDataANDROID cubemap = {
.type = XR_TYPE_CUBEMAP_LIGHTING_DATA_ANDROID,
.next = nullptr,
.imageBufferSize = perFaceImageBufferSize,
.imageBufferRight = cubemapBuffer.data() + 0 * perFaceImageBufferSize,
.imageBufferLeft = cubemapBuffer.data() + 1 * perFaceImageBufferSize,
.imageBufferTop = cubemapBuffer.data() + 2 * perFaceImageBufferSize,
.imageBufferBottom = cubemapBuffer.data() + 3 * perFaceImageBufferSize,
.imageBufferFront = cubemapBuffer.data() + 4 * perFaceImageBufferSize,
.imageBufferBack = cubemapBuffer.data() + 5 * perFaceImageBufferSize,
};
XrDirectionalLightANDROID directionalLight = {
.type = XR_TYPE_DIRECTIONAL_LIGHT_ANDROID,
.next = &cubemap,
};
XrSphericalHarmonicsANDROID totalSh = {
.type = XR_TYPE_SPHERICAL_HARMONICS_ANDROID,
.next = &directionalLight,
.kind = XR_SPHERICAL_HARMONICS_KIND_TOTAL_ANDROID,
};
XrSphericalHarmonicsANDROID ambientSh = {
.type = XR_TYPE_SPHERICAL_HARMONICS_ANDROID,
.next = &totalSh,
.kind = XR_SPHERICAL_HARMONICS_KIND_AMBIENT_ANDROID,
};
XrAmbientLightANDROID ambientLight = {
.type = XR_TYPE_AMBIENT_LIGHT_ANDROID,
.next = &ambientSh,
};
XrLightEstimateANDROID estimate = {
.type = XR_TYPE_LIGHT_ESTIMATE_ANDROID,
.next = &ambientLight,
};
XrResult result = xrGetLightEstimateANDROID(estimator, &info, &estimate);
if (result == XR_SUCCESS &&
estimate.state == XR_LIGHT_ESTIMATE_STATE_VALID_ANDROID) {
// use cubemap, directionalLight, totalSh, ambientSh, and
// ambientLight if each struct has a valid state field
if (cubemap.state == XR_LIGHT_ESTIMATE_STATE_VALID_ANDROID) {
// use cubemap
if (cubemapCreateInfo.reproject == XR_TRUE) {
XrQuaternionf identityQuaternion = {0.0f, 0.0f, 0.0f, 1.0f};
assert(memcmp(&cubemap.rotation, &identityQuaternion, sizeof(XrQuaternionf)) == 0);
}
}
}
// When you want to disable light estimation
CHK_XR(xrDestroyLightEstimatorANDROID(estimator));
New Commands
New Structures
Extending XrLightEstimateANDROID :
Extending XrLightEstimatorCreateInfoANDROID :
Extending XrSystemProperties :
New Enums
New Enum Constants
XR_ANDROID_LIGHT_ESTIMATION_CUBEMAP_EXTENSION_NAMEXR_ANDROID_light_estimation_cubemap_SPEC_VERSIONExtending XrStructureType :
XR_TYPE_CUBEMAP_LIGHTING_DATA_ANDROIDXR_TYPE_CUBEMAP_LIGHT_ESTIMATOR_CREATE_INFO_ANDROIDXR_TYPE_SYSTEM_CUBEMAP_LIGHT_ESTIMATION_PROPERTIES_ANDROID
Issues
Version History
Revision 1, 2025-12-05 (Salar Khan)
- Initial extension description