Skip to content

Provide Access to WebXR camera feed when camera-access feature is enabled. #26891

@connorgmeehan

Description

@connorgmeehan

Description

I would like to be able to get a Texture class that references the camera feed from an XR session.

Solution

User API

Proposal would be to be able to request the camera texture from the WebXRManager class, however this glosses over a lot of implementation detail and may not map to the WebXR access patterns very well.

const texture = renderer.xr.getCameraTexture();

Proposed Internal changes

I am currently having a stab implementing this, I have little experience with the internals of three.js so everything is open to change.

Would require the creation of a new THREE.js Texture class that receives the underlying WebGLTexture instead of initialising it. Lets call it ExternalTexture. In an ExternalTexture THREE.js is not responsible for creating / deleting the GPU data, only binding it and tracking its state. As this could introduce a lot of footguns it may be best to keep this class for internal use for now.

const glTexture = gl.createTexture();
const texture = new ExternalTexture(glTexture);

Additionally, the texture provided by the WebXR api has some limitations. It is what the WebXR specs call an opaque texture. In summary it is:

  • Only a valid texture from within the requestAnimationFrame() callback of the XRSession
  • Calling deleteTexture on this texture will result in an INVALID_OPERATION error.
  • Must be unbound and detached from all WebGLShader objects at the end of the requestAnimationFrame()
  • Changes to dimensions or format is not allowed and any gl call that could change these parameters will fail with an INVALID_OPERATION error.

This will probably require a second class that extends from ExternalTexture, lets call it ExternalOpaqueTexture. To navigate the requirement that the texture is only valid from within an XRSession's requestAnimationFrame callback, from what I see there are two options.

Option 1: Manually passing in the new opaque texture each frame.
const threeOpaqueTexture = new ExternalOpaqueTexture(null);
// Later on, user manually updates it.
const animate = () => {
  const glOpaqueTexture = ...;
  threeOpaqueTexture.image.source = glOpaqueTexture;
  threeOpaqueTexture.needsUpdate = true;
}
Option 2: Passing in a getter for the opaque texture in the constructor.
const getGLOpaqueTexture = () => {
  // ... interact with the XR session to get the camera feed texture
  return glOpaqueTexture;
}
const threeOpaqueTexture = new ExternalOpaqueTexture(getGLOpaqueTexture);
// Three.js internals will automatically handle re-fetching it when needed.

User API Usage

There are two ways the api might have to be used based on the limitations of an opaque texture (see above). These access patterns map to option1 and option 2 of how the underlying ExternalOpaqueTextureClass might work.

  1. User must call getCameraTexture within requestAnimationFrame() of the XR session or it will error. This object is valid only for the requestAnimationFrame that it was called within and will error/warn if used otherwise.
  2. User can call it at any time and receive a ExternalOpaqueTexture that will be managed by three.js, Three.js internals will call the function to get the texture inside of textures.setTexture2D. If this is called from outside of an XR sessions requestAnimationFrame it will be black.

Edited for formatting and a bit of extra information

Alternatives

I have attempted to get the camera access texture using raw webgl binds and use three.resetState to clean the three state but it doesn't work.

Additional context

Draft proposal: WebXR Raw Camera Access Module
Raw WebGL Example
Raw WebGL Example, source code
#26452

Our sales person sold a project that depends on this feature so I am going to try implement it to this spec (on r151 however). I would appreciate any advice, I know almost nothing about how three.js tracks the state internally so any help or advice would be much appreciated. If i can get it working for our project I can PR on the latest threejs version in my free time.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions