CubeTexture WebGL error only after build compilation

Hello, I have a weird issue since I have updated my BJS version to one of the last (5.0.0-beta.4 => 5.32.2). Unfortunately, I can’t reproduce it in a playground as the issue happen only after building the code.

The error I have is with the CubeTexture class and here are the results I have before and after building the code for production:


You can see that we have an error, particularly on the metallic parts.
In the console I have this error warning which also appeared only with the production code:

[.WebGL-0x12003d98700] GL_INVALID_FRAMEBUFFER_OPERATION: Draw framebuffer is incomplete

If I remove the CubeTexture of the scene, the warning stops showing that is why I am pretty sure the error comes from there. Plus the visual error we see in the images above also matches with a CubeTexture issue.

I tried to play with a lot of typescript parameters but none worked. I removed all the options like scope hoisting and other optimizations from our compilator parcel but also no change at all.
I tried different versions of parcel but still the same result. I tried some different versions of BJS also but unless I go back to 5.0.0-beta.4, I will have the issue. I can’t tell you exactly with which version it stops working as I wanted to ask you before testing every version :grinning:

I also tried to see if it could come from missing import of BJS feature but no clue so far. Plus normally it wouldn’t work even before the build.

Thanks for your help in figuring out what is happening! :wink:

Do you have the error a single time?

If yes, it could mean that something is used before being ready in the first frame… Do you happen to have a live link so that we can have a deeper look with Spector?

Hi @Evgeni_Popov, I thought about that too but after adding a timeout on the CubeTexture creation, I still have the issue and the console warning even after a 5-second delay.
Here is a link to the issue: Bob AR v1.51

Thanks !!

Are you able to call scene.render() each frame even if there’s no user interactions? Spector can’t record a frame if no gl commands are issued (or at least I don’t know how to do it)…

I modified the code to have the rendering launched before loading all assets.
Tell me if you need something else to use Spector :wink:

In fact, what I need is that scene.render() be called on each frame and not only when the camera moves. That’s because Spector can’t record a frame if nothing happens, and I can’t move the camera when the Spector window is opened because doing so closes the Spector window, preventing me to hit the “Record” button…

Ok thanks for the clarification.
scene.render() is now constantly called!

Thanks for the updated link.

So, it’s definitely the env texture which is not ok:

It’s empty.

So, it looks like the texture is used before being fully created. Are you sure to wait for the file to be downloaded (texture.isReady) before going on with whatever processing you are doing with the cube?

I tried to debug a bit but it’s not easy because the code is quite unreadable as it is minified. One thing which is a bit strange is that the CubeTexture.CreateFromPrefilteredData method is not called, whereas your env texture is a .env file (https://d2uret4ukwmuoe.cloudfront.net/environment_v4/4.env): normally you should call CubeTexture.CreateFromPrefilteredData to create the cube texture for this env file?

Thank you @Evgeni_Popov for digging into this issue and for your analysis!

So this is how I load and use the texture:

const texture = new CubeTexture(url, scene, null, false, null, () => {
        texture.gammaSpace = false;
        scene.environmentTexture = texture;

        skyboxMaterial.reflectionTexture = texture.clone();
        skyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
});

As you can see I do not use CreateFromPrefilteredData, but I tried it and I have the same result.

I also added some logs to check when the error occurs, and this is before the CubeTexture onload event:
Screenshot 2022-12-02 at 10.48.13

Hope that helps!

Ok, I got it: Parcel generates bugged code!

It’s in UploadLevelsAsync where we create some promises which will upload the data into the face+mipmap(lod) of the cube.

Parcel is using a global variable for the lod, but at the time the promises run the lod value is the same for all promises and is the highest lod value (9).

For context, the relevant code from UploadLevelsAsync as generated by Parcel is:

var _loop = function(face) {
    // Constructs an image element from image data
    var bytes = imageData[i1][face];
    var blob = new Blob([
        bytes
    ], {
        type: imageType
    });
    var url = URL.createObjectURL(blob);
    var promise = void 0;
    if (typeof Image === "undefined" || engine._features.forceBitmapOverHTMLImageElement) promise = engine.createImageBitmap(blob, {
        premultiplyAlpha: "none"
    }).then(function(img) {
        return _OnImageReadyAsync(img, engine, expandTexture, rgbdPostProcess, url, face, i1, generateNonLODTextures, lodTextures, cubeRtt, texture);
    });
    else {
        var image = new Image();
        image.src = url;
        // Enqueue promise to upload to the texture.
        promise = new Promise(function(resolve, reject) {
            image.onload = function() {
                _OnImageReadyAsync(image, engine, expandTexture, rgbdPostProcess, url, face, i1, generateNonLODTextures, lodTextures, cubeRtt, texture).then(function() {
                    return resolve();
                }).catch(function(reason) {
                    reject(reason);
                });
            };
            image.onerror = function(error) {
                reject(error);
            };
        });
    }
    promises.push(promise);
};
var promises = [];
for(var i1 = 0; i1 < imageData.length; i1++)// All mipmaps up to provided number of images
    for(var face = 0; face < 6; face++)_loop(face);// All faces

i1 is the global variable which is reused in _loop(). _OnImageReadyAsync is the method which will upload the data into the face+lod of the cube.

So, I don’t really know what you can do except maybe asking in some Parcel forums in case it’s a known problem or trying with another packager?

2 Likes

Ok thanks again.

Yep, we thought about using another packager but Parcel is really convenient for a lot of reasons and is fully integrated with our current processes so this is easier to keep it for now.

Now that I know what the problem is exactly, I will ask the parcel community how I could fix that. I guess with some configuration changes, this is doable.

Have a great weekend!

I submitted an issue to the parcel Github:

Your help was more than appreciated @Evgeni_Popov to figure out what was the real issue.