Closed ghost closed 3 years ago
Does the screenshot works in VR or Chrome?
Notice that even if it worked the ar.js video feed won't be captured since that's handled outside of the canvas used to render WebGL.
Does the screenshot works in VR or Chrome?
Yes, it works on Chrome, Samsung Internet and Edge (Chromium), VR as well.
I was trying to reproduce this on Fiferox's desktop version, but I've got another issue, with my webcam.
Notice that even if it worked the ar.js video feed won't be captured since that's handled outside of the canvas used to render WebGL.
I have that covered. I'm using a modified version of this code snippet with my wasm module to merge AR.js and Aframe canvases together.
If it works in all browsers except Firefox it looks like a browser bug. Flipping the image is an expensive operation. Maybe some issue with Firefox memory management on mobile.
FWIW, screen capture works fine for me on Firefox Desktop with any of the examples
If it works in all browsers except Firefox it looks like a browser bug. Flipping the image is an expensive operation. Maybe some issue with Firefox memory management on mobile.
Yes, I agree. I was going to close this issue with a similar statement.
Sorry about the noise and thanks.
From https://github.com/mozilla-mobile/fenix/issues/17058 :
Though it is still an issue in 84.1.2, I've updated the code that provides the screenshot without errors, for my use case.
Since I've solved my issue and updated the production code, I'm going to close this. If the FF Fenix team want to have a reproducible code, I can provide a zip file containing the old version.
The current code doesn't improve the performance, it still takes a considerable amount of time, compared to other browsers, to process the image.
Here's a walkthrough if anyone stumble on this issue:
Copy the code that flips the image vertically and put it in a inline Worker:
const flipper = (() => {
const flipPixelsVertically = (msg) => {
const {pixelsBuffer, width, height} = msg.data;
const pixels = new Uint8Array(pixelsBuffer);
const flippedPixels = pixels.slice(0);
for (let x = 0; x < width; ++x) {
for (let y = 0; y < height; ++y) {
flippedPixels[x * 4 + y * width * 4] = pixels[x * 4 + (height - y) * width * 4];
flippedPixels[x * 4 + 1 + y * width * 4] = pixels[x * 4 + 1 + (height - y) * width * 4];
flippedPixels[x * 4 + 2 + y * width * 4] = pixels[x * 4 + 2 + (height - y) * width * 4];
flippedPixels[x * 4 + 3 + y * width * 4] = pixels[x * 4 + 3 + (height - y) * width * 4];
}
}
self.postMessage(flippedPixels.buffer, [flippedPixels.buffer]);
};
const blob = new Blob(['self.onmessage = ', flipPixelsVertically.toString()], { type: 'text/javascript' });
const workerURL = URL.createObjectURL(blob);
return new Worker(workerURL);
})();
Copy the getCanvas
method, applying some changes (hopefully the changes are obvious):
// `this` is the scene component.
const screenshotComponent = this.el.components.screenshot;
let isVREnabled;
const flipScreenshotPixelsVertically = () => { // Save the state. isVREnabled = this.el.renderer.xr.enabled; this.el.renderer.xr.enabled = false;
screenshotComponent.quad.visible = false;
const camera = this.data.camera ? this.data.camera.components.camera.camera : this.el.camera; const [width, height] = [screenshotComponent.data.width, screenshotComponent.data.height]; const autoClear = this.el.renderer.autoClear; const renderer = this.el.renderer; // Create rendering target and buffer to store the read pixels. const output = screenshotComponent.getRenderTarget(width, height); const pixels = new Uint8Array(4 width height); // Resize quad, camera, and canvas. screenshotComponent.resize(width, height); // Render scene to render target. renderer.autoClear = true; renderer.clear(); renderer.setRenderTarget(output); renderer.render(this.el.object3D, camera); renderer.autoClear = autoClear; // Read image pizels back. renderer.readRenderTargetPixels(output, 0, 0, width, height, pixels); renderer.setRenderTarget(null);
// send to the inline worker. flipper.postMessage({ pixelsBuffer: pixels.buffer, width, height }, [pixels.buffer]);
// wait for the message. return new Promise((resolve) => { flipper.onmessage = msg => { const imageData = new ImageData(new Uint8ClampedArray(msg.data), screenshotComponent.data.width, screenshotComponent.data.height); // Hide quad after projecting the image. screenshotComponent.quad.visible = false; // Copy pixels into canvas. screenshotComponent.ctx.putImageData(imageData, 0, 0); this.el.renderer.xr.enabled = isVREnabled; resolve(); } }); };
3. Use where it is needed. Example:
```javascript
async function screenshotOnClick() {
await flipScreenshotPixelsVertically();
//... your code.
}
Description: When trying to take screenshot from one scene, firefox reports a termination by timeout.
I'm using AR.js with Aframe.
Debugging logs (where
$0
is the scene):Image (where
$0
is the scene):From the link provided, you can just click on the middle button to take a screenshot.