Screenshot alpha

Hi folks,

I’ve come across this screenshot example:
https://developer.playcanvas.com/en/tutorials/capturing-a-screenshot/

I’m wondering if it’s possible to export the screenshot with transparency (instead of clear color being the background)?

I’ve attempted setting the clear color’s alpha 0 and setting the canvas to be transparent without much luck. Any thoughts?

Hi @left,

It’s definitely possible, if you were taking the screenshot from the whole canvas and not only from the active layer what you did should be enough.

There is a small change you need to do in code to extend the render target to support alpha, in screenshot.js, line 129 change the colorbuffer format:

    var colorBuffer = new pc.Texture(device, {
        width: device.width,
        height: device.height,
        format: pc.PIXELFORMAT_R8_G8_B8_A8,
        autoMipmap: true
    });

Together with setting the clear color of Screenshot Camera to have alpha 0.0.

That should be enough though now that I am trying it myself I see that the layer isn’t fully cleared before taking the screenshot (which makes sense since we set it to alpha 0.0).

@mvaligursky what would be the ideal/easiest solution here?

1 Like

Thanks @Leonidas ,

That was the result I came to as well. Not entierly sure how to clear it.

1 Like

Not sure what the problem is, what you suggest should be enough.

Try setting app.scene.layers.logRenderActions to true, and use the debug engine … it should log out to debug console what it renders and if it clears - that might help to debug it.

Hmm, checking the render actions logs I think everything seems right:

Here is the public project if you would like to take a look:

https://playcanvas.com/editor/scene/1195198

yeah that seems all good, the screenshot camera renders first and clears color and depth - so as long as color is cleared to alpha 0, all should work?
Hopefully alpha write is not disabled when the clear takes place, but should not be.

1 Like

Have you tried toggling “Preserve Drawing Buffer” in Settings > Rendering?
image

Not directly helpful, but at the moment I’m working on a code that renders some data to texture, and I read it back from texture (not framebuffer), and that is working without a problem - I get alpha back as well… Code for reference:

createTexture(width, name) {
        const texture = new Texture(this.device, {
            width: width,
            height: 1,
            format: PIXELFORMAT_R8_G8_B8_A8,
            mipmaps: false,
            minFilter: FILTER_NEAREST,
            magFilter: FILTER_NEAREST,
            addressU: ADDRESS_CLAMP_TO_EDGE,
            addressV: ADDRESS_CLAMP_TO_EDGE
        });
        texture.name = name;

        return texture;
    }

        // create texture and render target for rendering into
        const texture = this.createTexture(numSamples, "EnvBakeLightRT");
        const renderTarget = new RenderTarget({
            colorBuffer: texture,
            depth: false
        });

        // shader
        const shader = createShaderFromCode(this.device, sampleCubemapVertexShader, sampleCubemapFragmentShader, "BakeLightEnvironment_SampleCubemap");

        drawQuadWithShader(this.device, renderTarget, shader);

        // read back the rendered cubemap colors
        const device = this.device;
        const oldRt = device.renderTarget;
        device.setRenderTarget(renderTarget);
        device.updateBegin();

        this.colors = new Uint8Array(numSamples * 4);
        this.device.gl.readPixels(0, 0, texture.width, texture.height, this.device.gl.RGBA, this.device.gl.UNSIGNED_BYTE, this.colors);

        this.device.setRenderTarget(oldRt);
        this.device.updateBegin();

        // release resources
        dirTexture.destroy();
        renderTarget.destroyTextureBuffers();
        renderTarget.destroy();


Oh, I think I know what’s going on. After moving the camera around, I notice the area where it’s transparent is a vertically rendered mirror

There’s a bit of code that rotates the image to make it the right way up:

    this.canvas.width = cb.width;
    this.canvas.height = cb.height;

    // The render is upside down and back to front so we need to correct it
    this.context.setTransform(1, 0, 0, 1, 0, 0);
    this.context.scale(1,-1);
    this.context.translate(0,-this.canvas.height);
    
    this.pixels = new Uint8Array(colorBuffer.width * colorBuffer.height * 4);

Commenting that out

This gives the correct alpha-ed background image but upside down

@mvaligursky With the change to texture orientation next week, will this be a problem we don’t have to worry about?

2 Likes

that’s one for @slimbuck perhaps

Not sure I understand how flipping the image transform would make the alpha work correctly?

The engine’s new texture orientation change shouldn’t impact this.

We could just rotate (scale negatively) the screenshot camera, seems to work:

image

3 Likes

That’s the best solution @Leonidas. :+1:

What’s happening is this script copies the pixels from the backbuffer into the 2d canvas, then invokes a canvas ‘drawImage’ call (which respects the transform @yaustar found) to flip the image.

If you place the following before the drawImage call:
this.context.globalCompositeOperation = "copy";
then drawImage won’t blend and create a mirror copy.

However flipping the camera and removing the ‘drawImage’ call is a better option!

3 Likes

@yaustar do you think we should update the example to flip the camera as @Leonidas suggests and also have the example export alpha correctly?

Yep yep, thinking about doing that this morning

I couldn’t do the camera flip trick because it also flip the X so it’s mirror horizontally. I’ve added the globalCompositeOperation code instead

Updated now: Capturing a screenshot | Learn PlayCanvas

2 Likes