aframevr / aframe

:a: Web framework for building virtual reality experiences.
https://aframe.io/
MIT License
16.62k stars 3.95k forks source link

Rendering to a 2d canvas while XR mode enabled #4937

Open jquery404 opened 3 years ago

jquery404 commented 3 years ago

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.

cabanier commented 3 years ago

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)

jquery404 commented 3 years ago

@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.)

cabanier commented 3 years ago

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

jquery404 commented 3 years ago

@cabanier I was trying to store the framebuffer and then set it to old framebuffer. but from aframe component both bindXRFramebufferand _framebufferis 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 commented 3 years ago

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);
}