Changing/ switching materials triggered by HTML button

From that example, I know how to change the diffuse colour in the box from a HTML button (HTML/CSS UI | Learn PlayCanvas).

Please tell me how to change the material from one to the other triggering it also from a HTML button. Is that possible?

Sometimes there are a lot of settings changed and It would be much faster to me switch material than to change every single attribute.

I would like to apply to change material to every subobject from a hierarchy tree (So I have a locator as a parent and a few objects under it. I would like to change the material on every child mesh of the parent locator.

Hello mdesign,

You should be able to change the material of an object through an HTML button. To switch materials in runtime through scripts, take a look at this example. As for how to trigger that with an HTML button, there is also this example, which is incredibly close to what you’re trying to achieve.

Let me know if you run into any issues!

1 Like
HtmlHandler.prototype.bindSwitchMaterialToggle = function( buttonName, objectName, materialNameToSwitch ) {
    var self = this;
    var changeMaterialButton = this.element.querySelector(buttonName);

    if (changeMaterialButton) {
        changeMaterialButton.addEventListener('click', function() {
            var obj = pc.app.root.findByName(objectName);
            if (obj && obj.render) { 
                var material = obj.render.meshInstances[0].material;
                if (material) {
                    material.name= materialNameToSwitch;
                }
            }
        }, false);
    }
};

What I’m doing bad here? Should I change it`s name?

Hey @mdesign,

It’s hard for me to give you some assistance without seeing the core issue.

  • Are you getting any console errors?
  • What is the intended behaviour?
  • Can you share a project link?
1 Like

Thanks for helping me and sorry that I`ve not shared enough info.

  • console.log proves that I`ve already changed ‘oldMaterial’ to ‘newMaterial’ (as I wanted to do) but nothing happens in the viewer (I still see oldMaterial - red one);
  • I would like to toggle on/off between two materials ‘oldMaterial’ and ‘newMaterial’;
  • Sure: PlayCanvas | HTML5 Game Engine .

Hi @mdesign,

The reason that the button doesn’t appear to be working is that your script currently only updates the name of the material in question. In order to update the actual material, you will want to change the actual object attached to the meshInstance in question. I slightly modified your script to now change the actual material object on the box like this:

var Ui = pc.createScript('ui');

Ui.attributes.add('css', {type: 'asset', assetType:'css', title: 'CSS Asset'});
Ui.attributes.add('html', {type: 'asset', assetType:'html', title: 'HTML Asset'});

Ui.prototype.initialize = function () {
    // create STYLE element
    var style = document.createElement('style');

    // append to head
    document.head.appendChild(style);
    style.innerHTML = this.css.resource || '';
    
    // Add the HTML
    this.div = document.createElement('div');
    this.div.classList.add('container');
    this.div.innerHTML = this.html.resource || '';
    
    // append to body
    // can be appended somewhere else
    // it is recommended to have some container element
    // to prevent iOS problems of overfloating elements off the screen
    document.body.appendChild(this.div);
    
    this.counter = 0;
    
    this.bindEvents();
};

Ui.prototype.bindEvents = function() {
    var self = this;
    // example
    //
    // get button element by class
    var button = this.div.querySelector('.button');
    var counter = this.div.querySelector('.counter');
    // if found
    if (button) {
        // add event listener on `click`
        button.addEventListener('click', function() {
            ++self.counter;
            if (counter)
                counter.textContent = self.counter;
            
            console.log('button clicked');

            // try to find object and change its material diffuse color
            // just for fun purposes
            var obj = pc.app.root.findByName('box');
            if (obj && obj.render) {
                var material = obj.render.meshInstances[0].material;
                if (material) {
                    // console.log(material.name)
                    //material.name.set('newMaterial');
                //     material.name = 'newMaterial';
                //     material.update();
                    obj.render.meshInstances[0].material = self.app.assets.find('newMaterial', 'material').resource;
                }
            }
        }, false);
    }

    if (counter)
        counter.textContent = self.counter;
};

The change that I made is rather quick and dirty (look at line 57), and you would likely want to find a better way of getting your materials other than searching by name for them in the future, but for now, this should work for you.

You may want to take sometime to review this section of the user manual to get better aquainted with the way materials work in Playcanvas:

https://developer.playcanvas.com/en/user-manual/assets/materials/

You can also look at the API Reference documentation here:

https://developer.playcanvas.com/api/pc.Material.html

I hope this is helpful.

3 Likes

Thanks. I wanted that type of rough answer to have a starting point. Super. Thanks a lot.