Change the cubemap of a material by code

Hello Friends, I am trying to change the cubemap of the environment tab of a material, I am using a script that works very well for diffuse textures, opacity, etc but it does not work here.

The diffuse code (it works perfectly)

var Changemoons = pc.createScript('BEIGE');

// Reference a list of textures that we can cycle through
Changemoons.attributes.add("textures", {type: "asset", assetType: "texture", array: true, title: "Textures"});

// initialize code called once per entity
Changemoons.prototype.initialize = function() {
    var self = this;
    
    // Keep track of which texture in the array we are currently using
    this.textureIndex = 0;

    // Change textures on button press
  var myMoons = this.app.root.findByName('ButtonTopBaseABeigeColor01');
    myMoons.element.on('mouseup', this.onMoonsBtnPressed, this);
    };
 

Changemoons.prototype.onMoonsBtnPressed = function(dt) {
    // Index the next texture in the list, wrapping around if we reach the end
    this.textureIndex = (this.textureIndex + 1) % this.textures.length;

    // Reference the texture
    var texture = this.textures[this.textureIndex].resource;        

    // Go through all the mesh instances of the model and change the diffuse texture on the
    // material to our new one
    var meshInstances = this.entity.model.meshInstances;
    for (var i = 0; i < meshInstances.length; ++i) { 
        var mesh = meshInstances[i];
        mesh.material.diffuseMap = texture;
        mesh.material.update();
    }
};

The cubemap code (don’t work)

var ChangeMetalness = pc.createScript('METALLIC');

// Reference a list of cubemaps that we can cycle through
ChangeMetalness.attributes.add("cubemap", {type: "asset", assetType: "cubemap", array: true, title: "cubemap"});

// initialize code called once per entity
ChangeMetalness.prototype.initialize = function() {
    var self = this;
    
    // Keep track of which cubemap in the array we are currently using
    this.cubemapIndex = 0;

    // Change cubemaps on button press
  var myMetalness = this.app.root.findByName('Metallic');
    myMetalness.element.on('mouseup', this.onMetalnessBtnPressed, this);
    };
 

ChangeMetalness.prototype.onMetalnessBtnPressed = function(dt) {
    // Index the next cubemap in the list, wrapping around if we reach the end
    this.cubemapIndex = (this.cubemapIndex + 1) % this.cubemaps.length;

    // Reference the cubemap
    var cubemap = this.cubemaps[this.cubemapIndex].resource;        

    // Go through all the mesh instances of the model and change the diffuse cubemap on the
    // material to our new one
    var meshInstances = this.entity.model.meshInstances;
    for (var i = 0; i < meshInstances.length; ++i) { 
        var mesh = meshInstances[i];
        mesh.material.cubeMap = cubemap;
        mesh.material.update();
    }
};

change cubemap

1 Like

Hmm, your code seems correct, I don’t see any issue. Are the cubemap assets loaded when you apply it to the material? (though I imagine if not, they should still load in place).

Are you able to share a sample project url to take a look at?

Hello @Leonidas, yes shure

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

(press the “Metallic” button to see the error)

So first there is an error thrown for this.cubemaps being undefined:

Uncaught TypeError: can't access property "length", this.cubemaps is undefined

And indeed in your METALLIC.js script you don’t define that property. Change your attribute to this:

ChangeMetalness.attributes.add("cubemaps", {type: "asset", assetType: "cubemap", array: true, title: "cubemap"});

Then your button seems to be working fine:

Ok, many thanks @Leonidas, it works perfectly. Many Thanks friend.

1 Like