| <!DOCTYPE html> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script>let additionalChromiumResources = ["../resources/xr-internal-device-mocking.js"];</script> |
| <script src="/webxr/resources/webxr_util.js"></script> |
| <script src="/webxr/resources/webxr_test_constants.js"></script> |
| <script src="/webxr/resources/webxr_test_asserts.js"></script> |
| |
| <script> |
| // Because light estimation is not yet in the core webxr spec, this is an internal-chrome only test. |
| |
| function assert_defined(v, description) { |
| assert_not_equals(v, undefined, description); |
| } |
| |
| // Verifies the structure of |XRLightEstimate| |
| // Defined in 'third_party/blink/renderer/modules/xr/xr_light_estimate.idl' |
| function verifyXRLightEstimate(lightEstimate) { |
| assert_true(lightEstimate instanceof XRLightEstimate); |
| |
| assert_defined(lightEstimate.sphericalHarmonicsCoefficients, "sphericalHarmonicsCoefficients was not defined on XRLightEstimate"); |
| assert_array_equals(Array.from(lightEstimate.sphericalHarmonicsCoefficients), new Array(9).fill().map((x, i) => [i, i, i]).flat()); |
| |
| assert_defined(lightEstimate.primaryLightDirection, "primaryLightDirection was not defined on XRLightEstimate"); |
| assert_equals(lightEstimate.primaryLightDirection.x, 0); |
| assert_equals(lightEstimate.primaryLightDirection.y, 1); |
| assert_equals(lightEstimate.primaryLightDirection.z, 0); |
| assert_equals(lightEstimate.primaryLightDirection.w, 0); |
| |
| assert_defined(lightEstimate.primaryLightIntensity, "primaryLightIntensity was not defined on XRLightEstimate"); |
| assert_equals(lightEstimate.primaryLightIntensity.x, 1); |
| assert_equals(lightEstimate.primaryLightIntensity.y, 1); |
| assert_equals(lightEstimate.primaryLightIntensity.z, 1); |
| assert_equals(lightEstimate.primaryLightIntensity.w, 1); |
| } |
| |
| // Verifies the behavior of querying reflection cube maps |
| // Defined in 'third_party/blink/renderer/modules/xr/xr_webgl_binding.idl' |
| function verifyReflectionCubeMap(session, lightProbe) { |
| // Currently reflection cube maps only work on WebGL 2. |
| const gl2Canvas = document.createElement('canvas'); |
| const gl = gl2Canvas.getContext('webgl2'); |
| if (!gl) { |
| return; |
| } |
| |
| return gl.makeXRCompatible().then(() => { |
| const glBinding = new XRWebGLBinding(session, gl); |
| |
| assert_true(glBinding instanceof XRWebGLBinding); |
| |
| assert_defined(glBinding.getReflectionCubeMap, "getReflectionCubeMap was not defined on XRWebGLBinding"); |
| |
| // Bind a different cube map prior to fetching the reflection cube map so we |
| // can ensure the binding is preserved. |
| const tmpCubeMap = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_CUBE_MAP, tmpCubeMap); |
| |
| // Make sure we get back a valid cube map |
| const cubeMap = glBinding.getReflectionCubeMap(lightProbe); |
| assert_true(cubeMap instanceof WebGLTexture); |
| |
| const boundCubeMap = gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP); |
| assert_equals(boundCubeMap, tmpCubeMap); |
| |
| // Ensure that we can't bind the returned cube map to the TEXTURE_2D bind |
| // target but can bind it to the TEXTURE_CUBE_MAP bind point. This effectively |
| // tests that the texture was created as a cube map. |
| gl.bindTexture(gl.TEXTURE_2D, cubeMap); |
| assert_equals(gl.getError(), gl.INVALID_OPERATION); |
| |
| gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeMap); |
| assert_equals(gl.getError(), gl.NO_ERROR); |
| }); |
| } |
| |
| // Verifies the structure of |XRFrame| (as it relates to light estimation) |
| // for a session that's expected to suppot light estimation. |
| // Defined in 'third_party/blink/renderer/modules/xr/xr_frame.idl' |
| function verifyXRLightEstimateExists(t, resolve, count, session, frame, lightProbe, localSpace) { |
| t.step(() => { |
| assert_not_equals(count, 0, "Did not get light estimate with a reasonable number of frames"); |
| assert_defined(frame.getLightEstimate, "getLightEstimate was not defined on XRFrame"); |
| |
| const lightEstimate = frame.getLightEstimate(lightProbe); |
| const lightProbePose = frame.getPose(lightProbe.probeSpace, localSpace); |
| |
| if (lightEstimate === null) { |
| // Check if we get a lighting estimate next frame |
| session.requestAnimationFrame((time, frame) => { |
| verifyXRLightEstimateExists(t, resolve, count - 1, session, frame, lightProbe, localSpace); |
| }); |
| } else { |
| verifyXRLightEstimate(lightEstimate); |
| |
| // Reflection cube maps may be enabled separately from the other lighting values. |
| if ('XRWebGLBinding' in window) { |
| verifyReflectionCubeMap(session, lightProbe).then(() => { |
| // If the light probe is providing valid results it should also have a |
| // valid space. |
| assert_not_equals(lightProbePose, null); |
| resolve(); |
| }); |
| } else { |
| // If the light probe is providing valid results it should also have a |
| // valid space. |
| assert_not_equals(lightProbePose, null); |
| resolve(); |
| } |
| } |
| }); |
| } |
| |
| // Verifies the structure of |XRLightProbe| |
| // Defined in 'third_party/blink/renderer/modules/xr/xr_light_probe.idl' |
| function verifyXRLightProbe(lightProbe) { |
| assert_true(lightProbe instanceof XRLightProbe); |
| |
| assert_true(lightProbe.probeSpace instanceof XRSpace); |
| assert_not_equals(lightProbe.probeSpace, null); |
| } |
| |
| const lightingInformationExistsName = "Ensures lighting estimation feature works when enabled"; |
| function lightingInformationExists(session, fakeDeviceController, t, sessionObjects) { |
| t.step(() => { |
| assert_defined(session.requestLightProbe, "requestLightProbe was not defined on XRSession"); |
| }); |
| |
| return new Promise(async (resolve, reject) => { |
| const lightProbe = await session.requestLightProbe(); |
| verifyXRLightProbe(lightProbe); |
| |
| const localSpace = await session.requestReferenceSpace("local"); |
| |
| session.requestAnimationFrame((time, frame) => { |
| verifyXRLightEstimateExists(t, resolve, 10, session, frame, lightProbe, localSpace); |
| }); |
| }); |
| } |
| |
| const lightingInformationDoesNotExistName = "Ensure lighting estimation feature does not work when not explicitly enabled"; |
| function lightingInformationDoesNotExist(session, fakeDeviceController, t, sessionObjects) { |
| t.step(() => { |
| assert_defined(session.requestLightProbe, "requestLightProbe was not defined on XRSession"); |
| }); |
| |
| return promise_rejects_dom(t, "NotSupportedError", DOMException, session.requestLightProbe()); |
| } |
| |
| xr_session_promise_test( |
| lightingInformationExistsName, |
| lightingInformationExists, |
| IMMERSIVE_AR_DEVICE, |
| 'immersive-ar', |
| { 'requiredFeatures': ['light-estimation'] } |
| ); |
| xr_session_promise_test( |
| lightingInformationDoesNotExistName, |
| lightingInformationDoesNotExist, |
| IMMERSIVE_AR_DEVICE, |
| 'immersive-ar', |
| {} |
| ); |
| |
| </script> |