Capturing a screenshot with post effect on camera

Hi everyone,

I was playing with the tutorial for capturing a screenshot:

https://developer.playcanvas.com/en/tutorials/capturing-a-screenshot/

and after some tries I realized that if you try to add a post effect like the bloom effect on the camera that is used for the screenshot, after the first screenshot made, all the next ones are the same of the first, you can try to move the camera but nothing change.

There is any workaround that could be apply?

Thanks

delete the camera and recreate it again, so that each screenshot is the first one?

Ah, that trick reminded me that I may have done that to fix a similar issue when taking a screenshot. It makes sense.

@FabrizioV give that a try.

Thank you guys, I tried like you suggested but the bloom seems to not be reapplied correctly, so I simply called the method “createNewRenderTexture” from the tutorial, then launched a timeout and call the screenshot method and it works like a charm.

I have three more questions.

1- If you scale the window to a mobile resolution the screenshot seems to be too zoomed. You can try it here Capturing screenshot on mobile seems zoomed - PLAYCANVAS

2- There is any way to add to the screenshot also any UI visible in scene?

3- I’m trying to make a sharing process with the screenshot. Right now I’m using a code like this:

this part is from the method “takeScreenshot”:

// first, create a new ImageData to contain our pixels

    var imgData = this.context.createImageData(colorBuffer.width, colorBuffer.height); // width x height

    var data = imgData.data;

    // Get a pointer to the current location in the image.

    var palette = this.context.getImageData(0, 0, colorBuffer.width, colorBuffer.height); //x,y,w,h

    // Wrap your array as a Uint8ClampedArray

    palette.data.set(new Uint8ClampedArray(pixels)); // assuming values 0..255, RGBA, pre-mult.

    // Repost the data.

 this.context.putImageData(palette, 0, 0);
this.context.drawImage(this.canvas, 0, 0);

var image = this.canvas.toDataURL('image/png');
var b64 = this.canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");

this.shareFile(image);

and this is the method that I’ve created to share the image:

ShareManager.prototype.shareFile = function (image) {
    var filesArr = [];
    var file = new File([image], "image.png", {
        type: 'image/png',
    }); 
    filesArr.push(file);
    if (navigator.canShare && navigator.canShare({files: filesArr})) {
        navigator.share({
            files: filesArr,
            title: 'Pictures',
            text: 'Our Pictures.',
        })
            .then(() => console.log('Share was successful.'))
            .catch((error) => console.log('Sharing failed', error));
    } else {
        console.log(`Your system doesn't support sharing files.`);
    }
};

I don’t receive any error but It seems to share only the text “Our Pictures”.

Another update guys. I finally find the way to share the screenshots captured from camera, by changing the shareFile function like this:

async function asyncShareFile(image) {
    const blob = await (await fetch(image)).blob();
    const filesArray = [
        new File(
            [blob],
            'screenshot.png',
            {
                type: blob.type,
                lastModified: new Date().getTime()
            }
        )
    ];
    const shareData = {
        files: filesArray,
    };
    navigator.share(shareData);
}

I’m still trying to understand how to remove the “zoom” effect and how to show the UI in the screenshot.

try setting app.scene.layers.logRenderActions to true, use the debug engine. And give your entity with camera a name - then when you render it, it should log out what it renders - that might point you to what’s going on - including what render targets are used and when UI renders. Perhaps post it here as well.

This is what the MainCamera renders:

0 Cam: MainCamera       Lay: World            OPAQUE ENABLED  Meshes:  2 RT: MainCamera-posteffect-0   Clear: Color Depth Stencil Lights: (0/1) CAM-FIRST DirLights: 1
1 Cam: MainCamera       Lay: World            TRANSP ENABLED  Meshes:  0 RT: MainCamera-posteffect-0   Clear: ..... ..... ....... Lights: (0/1)           
2 Cam: MainCamera       Lay: Depth            OPAQUE DISABLED Meshes:  0 RT: -                         Clear: Color Depth Stencil Lights: (0/0)           
3 Cam: MainCamera       Lay: Skybox           OPAQUE ENABLED  Meshes:  0 RT: MainCamera-posteffect-0   Clear: ..... ..... ....... Lights: (0/0)           
4 Cam: MainCamera       Lay: Immediate        OPAQUE ENABLED  Meshes:  0 RT: MainCamera-posteffect-0   Clear: ..... ..... ....... Lights: (0/0)           
5 Cam: MainCamera       Lay: Immediate        TRANSP ENABLED  Meshes:  0 RT: MainCamera-posteffect-0   Clear: ..... ..... ....... Lights: (0/0) POSTPROCESS
6 Cam: MainCamera       Lay: UI               TRANSP ENABLED  Meshes:  2 RT: -                         Clear: ..... ..... ....... Lights: (0/0)          

And this is what the Screenshot Camera renders when I click the button:

0 Cam: ScreenshotCamera Lay: World            OPAQUE ENABLED  Meshes:  2 RT: ScreenshotCamera-posteffect-0 Clear: Color Depth Stencil Lights: (0/1) CAM-FIRST DirLights: 1
1 Cam: ScreenshotCamera Lay: World            TRANSP ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/1)           
2 Cam: ScreenshotCamera Lay: Depth            OPAQUE DISABLED Meshes:  0 RT: -                    Clear: Color Depth Stencil Lights: (0/0)           
3 Cam: ScreenshotCamera Lay: Skybox           OPAQUE ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/0)           
4 Cam: ScreenshotCamera Lay: Immediate        OPAQUE ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/0)           
5 Cam: ScreenshotCamera Lay: Immediate        TRANSP ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/0) POSTPROCESS
6 Cam: ScreenshotCamera Lay: UI               TRANSP ENABLED  Meshes:  2 RT: MainCamera-posteffect-0   Clear: ..... ..... ....... Lights: (0/0)   

It seems that the UI gets rendered back into the main camera’s render target.

I wonder - when you’re about to render the screenshot … try to disable the MainCamera first, render the screenshot … and then enable it back. It might help with the UI rendering to screenshot.

I tried but if I disable camera component before the shot and enabled it again after, the screen turns black and it gives me this error:

playcanvas.dbg.js?version=1.49.4:17493 Uncaught TypeError: Cannot read properties of undefined (reading 'width')
    at RenderTarget.get (playcanvas.dbg.js?version=1.49.4:17493)
    at CameraComponent.calculateAspectRatio (playcanvas.dbg.js?version=1.49.4:50024)
    at CameraComponent.frameBegin (playcanvas.dbg.js?version=1.49.4:50029)
    at ForwardRenderer.cullComposition (playcanvas.dbg.js?version=1.49.4:24593)
    at ForwardRenderer.renderComposition (playcanvas.dbg.js?version=1.49.4:24660)
    at Application.render (playcanvas.dbg.js?version=1.49.4:71186)
    at playcanvas.dbg.js?version=1.49.4:71802

this is what the Camera renders:

0 Cam: ScreenshotCamera Lay: World            OPAQUE ENABLED  Meshes:  2 RT: ScreenshotCamera-posteffect-0 Clear: Color Depth Stencil Lights: (0/1)            CAM-FIRST DirLights: 1
1 Cam: ScreenshotCamera Lay: World            TRANSP ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/1)           
2 Cam: ScreenshotCamera Lay: Depth            OPAQUE DISABLED Meshes:  0 RT: -                         Clear: Color Depth Stencil Lights: (0/0)           
3 Cam: ScreenshotCamera Lay: Skybox           OPAQUE ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/0)           
4 Cam: ScreenshotCamera Lay: Immediate        OPAQUE ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/0)           
5 Cam: ScreenshotCamera Lay: Immediate        TRANSP ENABLED  Meshes:  0 RT: ScreenshotCamera-posteffect-0 Clear: ..... ..... ....... Lights: (0/0)            POSTPROCESS
6 Cam: ScreenshotCamera Lay: UI               TRANSP ENABLED  Meshes:  2 RT: -                         Clear: ..... ..... ....... Lights: (0/0)

It seems correct, but the image downloaded doesn’t have the UI yet.

Fair enough. I’m out of ideas … this would require somebody to debug and see what happens, and possibly fix it. Perhaps create an issue here with some small simple repro project if possible: https://github.com/playcanvas/engine/issues

one more options is perhaps try and use priority on the camera to change the order in which they render - it might help.

https://developer.playcanvas.com/api/pc.CameraComponent.html#priority

Likely both default to 0 … try 0 and 1, or 1 and 0 to see if that makes any difference.

Also, perhaps with combination of disabling the main camera too.

I don’t receive any errors and the render seems correct, but still no UI. Thank you anyway, I’ll open an issue. Do you have any ideas for the “zoom” issue?

No idea about that, sorry

What is this zoom effect? What do you mean by zoom?

I noticed this issue also in the tutorial project. If you try to scale the window, for example mobile aspect ratio, the screenshot is like “zoomed”.

Ah, that’s because the orbit camera has some code that changes the FOV axis based on the aspect ratio.

I’ve just fixed the tutorial project for taking snapshots in portrait

Great, now it works thank you @yaustar !!

After some other tries on the UI issue, I found out that if the screenshot camera has the bloom effect the UI disappears

If you can set up a simple project that reproduces the issue, it will really help for people that want to try and help debug

Sure, created it: Screenshot captured from camera with bloom effect makes any UI disappear

1 Like