Problems with creating a new material at run-time

First of all,show me project: https://playcanvas.com/editor/scene/583750

I created two entities on run time:

var entity1 = new pc.Entity();
    entity1.addComponent("model",{
         type:'plane'
    }); 
    entity1.addComponent("script");
    entity1.script.create("text");
    entity1.script.text.text = "entity1";
    
    
    var entity2 = new pc.Entity();
    entity2.addComponent("model",{
         type:'plane'
    }); 
    entity2.addComponent("script");
    entity2.script.create("text");
    entity2.script.text.text = "entity2";
    entity2.setPosition(1,0,0);
    
    
    this.app.root.addChild(entity1);
    this.app.root.addChild(entity2);

And i use scripts named text.js write text on two entities,first of it text is entity1,second of it is entity2,but the truth is all of it is entity2.

Then I find the reason is that two entities have shared the same material,when second entity and his material update,first update too.I’m so confused .

I guess I have to create two material for two entities . I have tried so many times to create new material but failed all.

Any one can help me about that? I need the method to create new material,the material could be added on a entity.because I want to write different text on different entity.

So sorry about my bad English. Thanks for watching this topic and best wishes for you.Last of all is text.js 's content:

var Text = pc.createScript('text');

Text.attributes.add('text', { type: 'string', default: 'Hello World'});

Text.prototype.initialize = function () {
    // Create a canvas to do the text rendering
    this.canvas = document.createElement('canvas');
    this.canvas.height = 128;
    this.canvas.width = 512;
    this.context = this.canvas.getContext('2d');

    this.texture = new pc.Texture(this.app.graphicsDevice, {
        format: pc.PIXELFORMAT_R8_G8_B8,
        autoMipmap: true
    });
    this.texture.setSource(this.canvas);
    this.texture.minFilter = pc.FILTER_LINEAR_MIPMAP_LINEAR;
    this.texture.magFilter = pc.FILTER_LINEAR;
    this.texture.addressU = pc.ADDRESS_CLAMP_TO_EDGE;
    this.texture.addressV = pc.ADDRESS_CLAMP_TO_EDGE;

    this.updateText();

    var material = this.entity.model.material;
    material.emissiveMap = this.texture;
    material.opacityMap = this.texture;
    material.blendType = pc.BLEND_NORMAL;
    material.update();
};

Text.prototype.updateText = function () {
    var ctx = this.context;
    var w = ctx.canvas.width;
    var h = ctx.canvas.height;

    // Clear the context to transparent
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, w, h);

    // Write white text
    ctx.fillStyle = 'white';
    ctx.font = 'bold 70px Verdana';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(this.text, w / 2, h / 2);

    // Copy the canvas into the texture
    this.texture.upload();
};

Without a project link, I’m guess it is because you are referring to the same material with both entities as seen in line:

var material = this.entity.model.material;

You would need to change the texture on the material ‘instance’ for lack of a better word as shown here: https://developer.playcanvas.com/en/tutorials/changing-textures-at-runtime/ or clone the material on initialize and change the mesh instance reference.

@yaustar Thank you for answer my qustion twice.

I have read changing -textures-at-runtime,but I still confused about what shouid I do.Please give me some codes to make my project work better.

:star_struck:

So here is a version with the solution to use two different materials: https://playcanvas.com/editor/scene/583970

You can use a similar method in code by cloning the model’s material in the script and assigning that to the mesh instances.

This link is no longer valid, can you provide sample code?
thank you!

Hi @chitiantong,

If you are trying to clone the same material and assign it to two different entities that have a single mesh instance, you can do it like this:

var originalMaterial = this.entity.model.material;
var materialA = originalMaterial.clone();
var materialB = originalMaterial.clone();

// here you can change any property on materialA or materialB
...

entityA.model.meshInstances[0].material = materialA;
entityB.model.meshInstances[0].material = materialB;

thanks. perfect!

Is there a way to save permanently theses materials? Can we generate a Json file from a material created at run-time?