[SOLVED] Assigning Cubemaps to Materials at Runtime

Hello everyone,
after my post from yesterday (Dynamic Cubemaps / Reflection Probes / Render To Texture in 2020) I decided to bite the bullet and render my cubemaps in Blender instead of, dynamically, at runtime. So far so good.
I looked at the ‘Orange Room’ example (https://playcanvas.com/project/345310/overview/orange-room) and felt inspired to bascially assign the pre-rendered Cubemaps at runtime.

(Explanation on what I want to achieve: Let’s say I have 5 rooms with 6 or so materials each [walls, ceiling, floor, etc.]. I could technically duplicate each material 5 times and assign 5 different sets of Lightmaps and Cubemaps. But then, if I wanted to change, say, the color on one of my materials, I would have to change it on the other 4, too -> NOT ideal)

So I wrote a script:

var CustomCubemap = pc.createScript('customCubemap');

CustomCubemap.attributes.add('customCubemap', {type: 'asset', assetType: 'cubemap', description: 'Custom cubemap'});
CustomCubemap.attributes.add('cubeMapCenter', {type: 'vec3', default: [0,0,0], description: 'Cubemap projection offset'});
CustomCubemap.attributes.add('cubeMapHalfExtends', {type: 'vec3', default: [0.5,0.5,0.5], description: 'Cubemap half extends'});

CustomCubemap.prototype.initialize = function () {
    var meshes = this.entity.model.meshInstances;   // get all materials assigned
    for (var i = 0; i < meshes.length; i++) {
        var material = meshes[i].material;    
        material.useSkybox = false;     // make sure the material doesn't use the global skybox       
        material.cubeMap = this.customCubemap.resources[1]; // use mipmap level 1 of prefiltered cubemaps
        // set cubemap to projection box; set center and half extends       
        material.cubeMapProjection = pc.CUBEPROJ_BOX;
        material.cubeMapProjectionBox = new pc.BoundingBox (this.cubeMapCenter, this.cubeMapHalfExtends);
        material.update();  // update material

It should go through each material of an object (room) and clone each material. Then assign a custom cubemap to each material.

This is what it should look like (I manually assigned the Cubemap in the Editor) - notice the material’s glossiness is 50 -> somewhat diffuse reflection

This is what it does look like when the project is launched -> reflection is extremely sharp, as if the glossiness were 100

(Yes, I checked, the glossiness doesn’t change in the material before and after assigning the cubemap)

Here’s the link to a test project with the script: https://playcanvas.com/project/739534/overview/cubemap-test

What am I doint wrong? Someone please enlighten me :wink:

Hi @twe,

This part of the playcanvas engine sorely needs updating.

To get the prefiltered lighting to work (i.e. roughness) you must do this:

        material.prefilteredCubemap128 = this.customCubemap.resources[1];
        material.prefilteredCubemap64 = this.customCubemap.resources[2];
        material.prefilteredCubemap32 = this.customCubemap.resources[3];
        material.prefilteredCubemap16 = this.customCubemap.resources[4];
        material.prefilteredCubemap8 = this.customCubemap.resources[5];
        material.prefilteredCubemap4 = this.customCubemap.resources[6];

and make sure you’re using a cubemap with prefiltered lighting data.

Please be aware though this is not public API and so might be break in future. Hopefully it’ll break for the better, but you may be forced to update this code if/when that happens.



Thanks @slimbuch for the quick reply! It seems to work now, thanks a bunch.
If anyone in their future encounters this problem, please be aware that it has to be

.prefilteredCubeMap128 ...

(and 64, 32, 16, 8 ,4) with a capital M (which is consistent to how it is spelled elsewhere in PC)

1 Like

Hey, I see that there is probably an issue with loading cubemaps.
When I download material from editor with attached cubemap and then use it with engine directly, it doesn’t load it.