aframe icon indicating copy to clipboard operation
aframe copied to clipboard

Rendering to a 2d canvas while XR mode enabled

Open jquery404 opened this issue 4 years ago • 5 comments

I am trying to take a screenshot of the player's current camera view. I'm using the following code:

document.querySelector('a-scene').components.screenshot.capture('perspective')

It works in normal mode but when entering VR mode it doesn't work. It still saves the same image and ignores what VR camera looking at. Because as soon as it enters VR mode, it stops rendering the canvas, either freezes or turns black. Here's my scene:

<a-scene>
<a-sky src="puydesancy.jpg" rotation="0 -130 0"></a-sky>
<a-text font="kelsonsans" value="Puy de Sancy, France" width="6" position="-2.5 0.25 -1.5" rotation="0 15 0"></a-text>
</a-scene>

how to keep rendering inline canvas while on vr.

  • A-Frame Version: 1.2.0
  • Platform / Device: web

jquery404 avatar Sep 27 '21 07:09 jquery404

During a WebXR session, the browser doesn't render to the canvas anymore. You need to do a manual texture copy if you want to get the pixels. (This will likely slow down your experience)

cabanier avatar Sep 27 '21 14:09 cabanier

@cabanier could you show me how I can do the manual texture copy? (I'll only run this in specific cases, so performance shouldn't be a big issue.)

jquery404 avatar Sep 27 '21 15:09 jquery404

Make sure that the WebXR framebuffer is the one that is bound, then call readPixels

cabanier avatar Sep 27 '21 15:09 cabanier

@cabanier I was trying to store the framebuffer and then set it to old framebuffer. but from aframe component both bindXRFramebuffer and _framebuffer is returning null. Here's what i have tried-

AFRAME.registerComponent('spectator',{
    schema: {
       isPresenting:{default:false}
    },
    update: function(oldData) {
        var data = this.data
        if (oldData.cid !== data.cid) {
            // Find canvas element to be used for rendering
            var canvasEl = document.getElementById(this.data.cid);
            // Create renderer
            this.renderer = new THREE.WebGLRenderer({
                antialias: true,
                canvas: canvasEl
            });
            this.renderer.setPixelRatio( window.devicePixelRatio );
            this.renderer.domElement.crossorigin = "anonymous";
        };
        if (oldData.width !== data.width || oldData.height !== data.height) {
            this.renderer.setSize(data.width, data.height);
            this.renderer.domElement.height = data.height;
            this.renderer.domElement.width = data.width;
        };
        if (oldData.fps !== data.fps) {
            this.tick = AFRAME.utils.throttleTick(this.tick, 1000 / data.fps , this);
        };
    },
    tick: function(time, timeDelta) {
        this.renderer.render( this.el.sceneEl.object3D , this.el.object3DMap.camera );

        if(this.data.isPresenting){
            this.renderer.xr.enabled = false;
            let oldFramebuffer = this.renderer._framebuffer; // this returns null ... :(
            this.renderer.state.bindXRFramebuffer( null );
            this.renderer.render( this.el.sceneEl.object3D , this.el.object3DMap.camera );
            this.renderer.xr.enabled = true;
            this.renderer.state.bindXRFramebuffer(oldFramebuffer);
        }
      }
});

jquery404 avatar Sep 27 '21 22:09 jquery404

in my aframe component this.renderer._framebuffer returns null. How do i get the renderer framebuffer in aframe

Here is the part where I am trying to render the canvas when the immersive vr mode is active -

if(this.data.isPresenting){
            this.renderer.xr.enabled = false;
            let oldFramebuffer = this.renderer._framebuffer; // this returns null ... :(
            this.renderer.state.bindXRFramebuffer( null );
            this.renderer.render( this.el.sceneEl.object3D , this.el.object3DMap.camera );
            this.renderer.xr.enabled = true;
            this.renderer.state.bindXRFramebuffer(oldFramebuffer);
}

jquery404 avatar Sep 30 '21 00:09 jquery404