PNG Image downloaded from server loads with black background instead of transparent

Hi, im trying to make a simple house decoration game on PlayCanvas. It gets pngs from a server and places them onto a plane’s material texture.

When I do this manually inside editor, transparency works fine (after setting up opacity maps and setting blending mode to alpha). But when I try to do the same thing via server, the images come with a black background.

check the build link below. In the link, im passing links of the downloadable image as a url parameter. Open this, wait for 5 seconds. It will replace the pic of the chair, with same exact pic but downloaded from the server. The background of chair will become black.

here is the relevant code:

    for (var i = 0; i < renders.length; ++i) {
        var meshInstances = renders[i].meshInstances;
        for (var j = 0; j < meshInstances.length; j++) {
            var material = meshInstances[j].material;
            material.diffuseMap = texture;
            material.emissiveMap = texture;
            material.opacityMap = texture;
            material.blendType = 'alpha';
            //material.alphaToCoverage = true;
            material.update();
        }
    }  

project link:
https://playcanvas.com/project/913048/overview/furnituredemo

Hi @M_Saad_Jumani and welcome,

Debugging with the browser dev tools I can see that you are trying to use the following image file:

Note that that is a JPG, meaning it doesn’t have an alpha (transparency) channel.

Also, I think you need to refactor your code to wait for the image to load, before using it as a texture. That’s the reason you are seeing only black, the texture wasn’t ready. Something like this:

    var image = new Image();
    image.crossOrigin = "anonymous";

    image.onload = () => {

        texture.setSource(image);

        var renders = this.entity.findComponents('render');
        for (var i = 0; i < renders.length; ++i) {
            var meshInstances = renders[i].meshInstances;
            for (var j = 0; j < meshInstances.length; j++) {
                var material = meshInstances[j].material;
                material.diffuseMap = texture;
                material.emissiveMap = texture;
                material.opacityMap = texture;
                material.blendType = 'alpha';
                //material.alphaToCoverage = true;
                material.update();
            }
        }
    };

    image.onerror = (e) => {
        console.log(e);
    };

    image.src = this.url;   

Check also if you have any server issues with that image url, since it seems the image file isn’t loading. I’ve added an onerror event handler to catch those errors, and it fires (GET 400 error).

2 Likes

Thanks for getting back to me over this. You answer was helpful, but not quite exactly there. Putting this here for anyone who might run into the issue in future.

First of all, yes I needed to refactor the code and have it wait for texture to load. But that wasn’t the problem here. Texture did load. If not right away then in the next function call (which happens every 5 seconds). So that wasn’t the issue.

Problem was that transparency didn’t work.

This is what I was seeing:

The image im trying to download from server is this one:

It shows up in your debugger as marked in blue (the one you selected is just used to initialize the texture with a hardcoded image first. So that it can be replaced later with server image):

It was actually this part that got me thinking. I was downloading a PNG image with alpha. But the texture was getting initialized with a JPEG, so even when it did get PNG image later, it did not recognize the alpha channel. That’s what was causing my problem. I replaced the JPEG initialization image with a transparent PNG and my problem was solved.