[SOLVED] Change of Material on an object

HI Guys,

I am trying to have a list of materials and change the msterial on the obejct through buttons created in CSS.

My Code is as such for the UI scipt which i am attaching to the Model in the editor.

pc.script.attribute('environment', 'asset', [ ], { type: 'texture' });
pc.script.attribute('materials', 'asset', [], { type: 'material'});

pc.script.create('ui', function (context) {
    var Ui = function (entity) {
        this.entity = entity;
    };

    Ui.prototype = {
        initialize: function () {
            this.ChangeMaterial = context.assets.getAssetById(this.materials[0]).resource;
            console.log(this.ChangeMaterial);
            var css = [
"body {",
"   -webkit-touch-callout: none;",
"   -webkit-user-select: none;",
"   -khtml-user-select: none;",
"   -moz-user-select: none;",
"   -ms-user-select: none;",
"   user-select: none;",
"   outline-style:none;",
"}",
"a {",
"    color: #fff;",
"}",
".ui-buttons {",
"    position: absolute;",
"    top: 0;",
"    right: 0;",
"    margin: 12px;",
"    display: flex;",
"    flex-wrap: wrap;",
"    flex-direction: row-reverse;",
"    width: 240px;",
"}",
".ui-button {",
"    width: 96px;",
"    height: 96px;",
"    display: block;",
"    margin: 12px;",
"    box-shadow: 0px 0px 8px rgba(0,0,0,.3);",
"    transform: scale(1, 1);",
"    border-radius: 64px;",
"    cursor: pointer;",
"    transition: box-shadow 200ms, transform 200ms;",
"    outline: 0 !important;",
"    -webkit-tap-highlight-color: rgba(255, 255, 255, 0); !important",
"    -webkit-tap-highlight-color: transparent; !important",
"}",
".ui-button:hover {",
"    box-shadow: 0px 0px 12px rgba(0,0,0,.6);",
"    transform: scale(1.05, 1.05);",
"}",
".ui-button.active {",
"    box-shadow: 0px 0px 16px rgba(0,0,0,1);",
"    transform: scale(1.1, 1.1);",
"}",
"*:focus {",
"    outline: 0 !important;",
"    -webkit-tap-highlight-color: rgba(255, 255, 255, 0); !important",
"    -webkit-tap-highlight-color: transparent; !important",
"}",
".author {",
"    position: absolute;",
"    left: 8px;",
"    bottom: 8px;",
"}",
".author > img, .website > img {",
"    display: block;",
"}",
".website {",
"    position: absolute;",
"    right: 8px;",
"    bottom: 8px;",
"}",
".music {",
"    position: absolute;",
"    top: 16px;",
"    left: 16px;",
"    width: 32px;",
"    height: 32px;",
"    cursor: pointer;",
"    transition: opacity 200ms;",
"}",
".music.off {",
"    opacity: 0.3;",
"}",
"@media screen and (max-width: 640px), screen and (max-height: 480px) {",
"    .ui-buttons {",
"        margin: 6px;",
"        width: 120px;",
"    }",
"    .ui-button {",
"        width: 48px;",
"        height: 48px;",
"        margin: 6px;",
"        border-radius: 24px;",
"    }",
"    .ui-element.author {",
"        left: 0;",
"        bottom: 0;",
"    }",
"    .ui-element.author > img {",
"        width: 128px;",
"    }",
"    .ui-element.website {",
"        right: 0;",
"        bottom: 0;",
"    }",
"    .ui-element.website > img {",
"        width: 128px;",
"    }",
"}"
            ].join('\n');

            var style = document.createElement('style');
            style.innerHTML = css;
            document.querySelector('head').appendChild(style);
            
            var self = this;

            this.windowFocused = true;
        
            window.onfocus = function() {
                self.windowFocused = true;
            };
            window.onblur = function() {
                self.windowFocused = false;
            };
            
            window.addEventListener('click', function() {
                self.windowFocused = true;
            }, false);
            window.addEventListener('touchstart', function() {
                self.windowFocused = true;
                
            }, false);
            
           
            
            
            if (this.environment) {
                

                var buttons = document.createElement('div');
                buttons.classList.add('ui-buttons');
                document.body.appendChild(buttons);
                       
                var asset_01 = this.materials[1];
                
                console.log(asset_01);
                

                for(var i = 0; i < this.environment.length; i++) {
                    var asset = context.assets.get(this.environment[i]);
                    var button = asset.resource._levels[0];
                    
                    button.classList.add('ui-button', 'ui-element');
                   
                    
                    button.addEventListener('click', function(evt) {
                       
                       console.log("Pressed");
                       
                       //modelEntity.update();
                    });
                    
                    button.addEventListener('touchstart', function(evt) {
                        
                    });
                    
                    buttons.appendChild(button);
                }
            }
            
            
            
            var stopMousePropagation = function(evt) {
                evt.preventDefault();
                evt.stopPropagation();
            };
            
            var elements = document.querySelectorAll('.ui-element');
            for(var j = 0; j < elements.length; j++) {
                elements[j].addEventListener('mousedown', stopMousePropagation, false);
                elements[j].addEventListener('mouseup', stopMousePropagation, false);
            }
        },

        update: function (dt) {
           //
            // this.entity.model.model.meshInstances[0].material = this.materials[1].resource;
            //this.ChangeMaterial.update();
            
             
        }
    };

    return Ui;
});

My FBX which i am using has 3 seperate meshes in them. do i need to do something specific to target a specific mesh?

kindly help me out as i am not able to get the material to change on the object.

regards,
Sharat

Hi.

It would help if you would separate UI code from logic code where you change materials.
Try changing materials on models without UI first, to figure out how it works.
Then you will be able to do it with UI.
Keeping it separate will help to reduce code and make it more manageable, otherwise you will over-complicate code.

This project might help you to tidy up your HTML/CSS: https://playcanvas.com/project/354600/overview/htmlcss--live-updates
I’ve added there code to update material on model too just for example, in htmlHandler.js on lines 93-100.

If you face any particular problem, feel free to ask. It is hard to answer on “questions” that not actually asking any specific problem, but generally unclear.

Thanks for the swift reply max… this is just what I needed to get in the right direction … I’ll get back with updates as soon I’m done viewing through your sample and implimenting it into my project as well…

1 Like

Hey max,

After going through your snippets i can see that i need to change tthe texture in my material instead of swapping the complete material.

I am able to change the color if i have tint enabled in the diffuse but i am not able to change the texture.

i am trying to use materal.setParameter(); to change the diffise color map but i am unble to fins the right parameter for the same.

regards,
Sharat

There are two ways to change texture, one is to do:

material.diffuseMap = texture;
material.update();

Another is to use setParameter, on material or meshInstance.
Parameter name is texture_diffuseMap.

Perfect max. It worked!

Good info about the Parameter Name!

Is there any documentation about the different parameter names? i would love to go through it.

Any how regards to your solution. Thanks a bunch!

Parameters are not documented anywhere, as they are internals and subject to change.
They are set here, and looking in chunks, you can find loads of variables. Btw, each of this chunk, can be overridden in runtime on material, to customise default PBR shader.

Hi, don’t know if this can help, i have 4 materials in my object and when i change them that’s the script

this.target.findByName('Model').model.model.meshInstances[0].material = context.assets.find('Standard_1','material').resources[0];
this.target.findByName('Model').model.model.meshInstances[1].material = context.assets.find('Standard_1','material').resources[0];
this.target.findByName('Model').model.model.meshInstances[2].material = context.assets.find('Material #4','material').resources[0];
this.target.findByName('Model').model.model.meshInstances[3].material = context.assets.find('Standard_1','material').resources[0];

you need this 4 lines everytime you want to change the materials of course (as you can see Standard_1 is the same material used 3 times)

I would write it a bit more simple:

// meshes
var meshes = this.target.findByName('Model').model.model.meshInstances;

// materials
var matStandard = app.assets.get(32).resource;
var mat4 = app.assets.get(64).resource;

// set materials
meshes[0].material = matStandard;
meshes[1].material = matStandard;
meshes[2].material = mat4;
meshes[3].material = matStandard;

Difference notice, you use app.assets.get instead of find. It is more stable and recommended way to reference assets.
You can use assets script attributes for defining materials in editor on scripts.

1 Like

Thanks for the code improvement :smile: , i’m just a novice with javascript

I am so sorry because I found this is my problem.

I do something wrong in the script which make the material’s script don’t work.

I am so sorry.

Dear max

I want to change the material on an object.

I study your code:

// set materials
meshes[0].material = matStandard;

However,when I use this method in my script

I find it doesn’t work.

This is my script:

this.box=this.app.root.findByName('Box');

var assets=this.app.assets.get(5103927).resource;
this.box.model.model.meshInstances[0].material=assets;

Could you tell me the trouble with my script?

5103927 is here

Thank you for your time

Check out this tutorial for how to do this:

http://developer.playcanvas.com/en/tutorials/beginner/keyboard-input/

@will
How do you change a material from chrome console?

Example scene - https://launch.playcanvas.com/545808?debug=true

// Box model
var box = pc.app.root.findByName(“Box1”)

// Materials
var red = pc.app.assets.get(8887337);
var green = pc.app.assets.get(8887339);

That example scene is private so I can’t see it. However, imagine a case where you have a model with two mesh instances, where each mesh instance has a different material. And imagine you wanted to swap the materials on that model. You could do the following in the JavaScript console:

entity = pc.app.root.findByName('Some Entity');
tmp = entity.model.meshInstances[0].material.
entity.model.meshInstances[0].material = entity.model.meshInstances[1].material;
entity.model.meshInstances[1].material = tmp;

Do be mindful that the Editor is not like a running PlayCanvas app - it doesn’t render constantly - only when it has to. So if you make this kind of change, you have to do something like mouse over the 3D view to force a re-render.

@will … I have made the project public now and got it working thanks to your help. Much appreciated.

//chrome console
var firstobject = pc.app.root.findByName(“Box1”);
var secondobject = pc.app.root.findByName(“Box2”);
firstobject.model.meshInstances[0].material = secondobject.model.meshInstances[0].material