[SOLVED] Cubemap gives null when accessing its resource

Trying to access a cubemap by its resource property but its giving null:
image

Project:
https://playcanvas.com/editor/scene/1182408

Hi @Saad_Haider ,

For a cubemap I think you should be accessing resources instead of resource, for the list of all face textures (since it’s a multi-resource asset).

Edit: though it’s odd that the first entry on the list is null, not sure if that’s normal.

I see @Leonidas , but if I apply any of the MIP levels from the resources, it looks like the prefiltering is not applied on the model materials: Example:
Left side has the cubemap applied in the editor while the right side materials are being applied cubemap at run time

Project:
https://playcanvas.com/editor/scene/1182419

And Code:
https://playcanvas.com/editor/code/807201?tabs=50305976

@slimbuck is the guy to advise here … I think there was a similar thread on the forum recently as well, see if you can find a solution there perhaps?

Cannot find the thread you described on the forum, I cannot seem to find a workaround for this unless you just apply the cubemap as a skybox in settings and disturb the overall scene setup lighting.

@Saad_Haider this may be of help:

1 Like

Hi @Saad_Haider,

Unfortunately you’re seeing a strange quirk of the cubemap system. The cubemap handler will only load the faces (asset.resources[0] or asset.resource) if the asset has asset.loadFaces = true.

I believe this was done in order to skip unnecessarily downloading face textures when only prefiltered lighting data is required (the lighting data is stored in asset.resources[1]asset.resources[7]).

This is usually not an issue, because the application class deals with this for the global skybox (see here).

For now you can do the same:

asset.loadFaces = true;
this.app.assets.load(asset);

and listen for load event.

We are hoping to overall the cubemap and lightprobe API in the engine soon and then we can deal with these sorts of issues.

Thanks!

3 Likes

Hi @slimbuck , setting the loadface = true does indeed let me access the resource of it but if I apply that to the cubemap property of a material, the lighting is not being applied to the material correctly it seems:

Doing this:

    this.cubemap.loadFaces = true;

    this.cubemap.once('load', ()=> {
        for(let i = 0; i < avatarModel.model.meshInstances.length; i ++) {
            avatarModel.model.meshInstances[i].material.cubeMap = this.cubemap.resource;
            avatarModel.model.meshInstances[i].material.update();
        }
    });
    this.app.assets.load(this.cubemap);

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

Hi @Saad_Haider,

If it’s just prefiltered lighting data you’re after (and not the faces) then you can actually skip setting loadFaces entirely and do the following in the once(‘load’) handler:

avatarModel.model.meshInstances[i].material.prefilteredCubeMap128 = this.cubemap.resources[1];
avatarModel.model.meshInstances[i].material.prefilteredCubeMap64 = this.cubemap.resources[2];
avatarModel.model.meshInstances[i].material.prefilteredCubeMap32 = this.cubemap.resources[3];
avatarModel.model.meshInstances[i].material.prefilteredCubeMap16 = this.cubemap.resources[4];
avatarModel.model.meshInstances[i].material.prefilteredCubeMap8 = this.cubemap.resources[5];
avatarModel.model.meshInstances[i].material.prefilteredCubeMap4 = this.cubemap.resources[6];

Thanks!

1 Like

Thank you! @slimbuck

Hi @slimbuck I have noticed that this way of setting the prefiltered lighting data on the model does not work anymore,
Test project:
https://playcanvas.com/editor/scene/1182419

Anyway I found out the way, (nothing is in the docs regarding this area @yaustar )
I just looked through Slimbuck’s recent project and luckily he done some tests regarding this, so this works now

const lighting = pc.EnvLighting.generateLightingSource(this.cubemap.resource);
const envAtlas = pc.EnvLighting.generateAtlas(lighting);
material.envAtlas = envAtlas;
material.update();
3 Likes

Hi @Saad_Haider,

I should have mentioned at the time, but the solution I gave you before was not public API and we changed the internal properties on the material.

It is actually still possible to set the prefilteredCubemaps, but using material.prefilteredCubemaps array property instead of the individual 128/64/32 etc sized textures.

However, the following code will do the job you’re after and is much more efficient:

const modelName = "Runtime Cubemap Character";

this.cubemap.once('load', () => {
    // generate environment atlas
    const envAtlas = pc.EnvLighting.generatePrefilteredAtlas(this.cubemap.resources.slice(1));

    // apply to mesh instances
    const meshInstances = this.app.root.findByName(modelName).model.meshInstances;
    meshInstances.forEach((mi) => {
        mi.material.envAtlas = envAtlas;
        mi.material.update();
    });
});
this.app.assets.load(this.cubemap);
2 Likes