Trying to access a cubemap by its resource property but its giving null:
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:
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!
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);
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!
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();
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);
A post was split to a new topic: How to change many materials environment map?