Setting Material Of Copied Mesh Fails

I have copied a mesh, but when I set its material to a material that has an opaque texture, then it becomes completely invisible.

When playing the project, press 1 to copy the mesh (the character with a blue opaque texture) and 2 to set its material.
Open ‘CopyMesh.js’ to see the simple implementation.
Here is the project overview: https://playcanvas.com/project/724615/overview/mesh-material-problem

Notes: if I just set the diffuse color, then the material gets set. It only becomes invisible when I set one with an opaque texture. If I set the character’s material to the opaque material in editor, then everything works too.

Hi @machineman1357,

Your code works fine, there is no issue or special case for blended meshes. The reason it doesn’t work is because your new, cloned, mesh doesn’t include UV coordinates. So the opacity map you are using in the material isn’t properly applied.

To get the source mesh UV coordinates you need to specify the channel you are targetting:

targetMesh.getUvs(0, newUvs);

Also normally on mesh instances we don’t set a pc.Entity as the translation node but create a new pc.GraphNode to be used for local translations. It makes it easier to keep the hierarchy in order.

Here is how I structured your script and it’s working now:

var CopyMesh = pc.createScript('copyMesh');

// initialize code called once per entity
CopyMesh.prototype.initialize = function() {
    var asset = this.app.assets.find('Source Material');
    this.sourceMaterial = asset.resource;
};

// update code called every frame
CopyMesh.prototype.update = function(dt) {
    if(this.app.keyboard.wasPressed(pc.KEY_1)) {
        this.copyMesh();
    }
    if(this.app.keyboard.wasPressed(pc.KEY_2)) {
        this.setCopiedMeshMaterial();
    }
};

CopyMesh.prototype.copyMesh = function() {
    this.sourceMesh = this.app.root.findByName('Source Mesh');
    this.entityWithCopiedMesh = this.createEntityWithTargetMesh(this.sourceMesh.model.meshInstances[0].mesh);
    this.entityWithCopiedMesh.setPosition(0, 0, 2);
    this.entityWithCopiedMesh.setLocalScale(0.01, 0.01, 0.01);
};

CopyMesh.prototype.setCopiedMeshMaterial = function() {
    this.entityWithCopiedMesh.model.meshInstances[0].material = this.sourceMaterial;
};

CopyMesh.prototype.createEntityWithTargetMesh = function(targetMesh) {
    var newEntity = new pc.Entity();
    
    var newPositions = [];
    var newUvs = [];
    var newIndices = [];
    targetMesh.getPositions(newPositions);
    targetMesh.getUvs(0, newUvs);
    targetMesh.getIndices(newIndices);
    var newNormals = pc.calculateNormals(newPositions, newIndices);
    
    var options = {
        normals: newNormals,
        uvs: newUvs,
        indices: newIndices
    };
    
    var newMesh = pc.createMesh(this.app.graphicsDevice, newPositions, options);
    
    var material = new pc.StandardMaterial();
    material.diffuse = new pc.Color(Math.random(), Math.random(), Math.random());    
    
    var node = new pc.GraphNode();
    var meshInstance = new pc.MeshInstance(node, newMesh, material);

    var newModel = new pc.Model();
    newModel.graph = node;
    newModel.meshInstances.push(meshInstance);    
    
    newEntity.addComponent('model', {
        layers: [this.app.scene.layers.getLayerByName('World').id],
        model: newModel
    });
    newEntity.model.model = newModel;    
    
    this.app.root.addChild(newEntity);
    
    return newEntity;
};
1 Like

Wow just a perfect answer, thanks!

1 Like