something like
this.attributeentity.changematerial = this attributenumber
Where the attribute number is any material id
something like
this.attributeentity.changematerial = this attributenumber
Where the attribute number is any material id
Hi @ALUCARD,
I don’t think there’s a built in way to do the behavior that you’re describing. Taking a look at this example project:
we can dive into the way the material is being switched at runtime by looking at this script:
https://playcanvas.com/editor/code/437442?tabs=5625601&focused=5625601
Specifically
...
SwitchingMaterials.attributes.add("materials", {type: "asset", assetType: "material", array: true, title: "Materials"});
...
SwitchingMaterials.prototype.changeToNextMaterial = function(dt) {
var i = 0;
// Get the next material asset in the array
this.materialIndex = (this.materialIndex + 1) % this.materials.length;
var material = this.materials[this.materialIndex];
// Assign the material to all the mesh instances in the model
var allMeshInstances = [];
var renders = this.entity.findComponents('render');
for (i = 0; i < renders.length; ++i) {
var meshInstances = renders[i].meshInstances;
for (var j = 0; j < meshInstances.length; j++) {
allMeshInstances.push(meshInstances[j]);
}
}
for (i = 0; i < allMeshInstances.length; ++i) {
var mesh = allMeshInstances[i];
mesh.material = material.resource;
}
};
You can see that we have to iterate over the meshInstances of the renderComponent and update the material of the meshInstance specifically. This is because a single render component can have several different materials applied to it if there are multiple meshes as part of the file.
However, you can also see that this project sets up a an asset script attribute that is an array. This is a bit closer to what you’re asking for, but I can see why a basic array might not be as helpful because, other than the array index, you don’t get an description of what material you’re selecting.
What you could do, instead, is use a json script attribute, which would allow you to have descriptive names for your materials and then you could select their resources and apply them to the meshInstances of the render component as you need them. That might look something like this:
SwitchingMaterials.attributes.add("namedMaterials", {
type: 'json',
title: 'Named Materials',
schema: [
{
name: 'clean',
title: 'My Clean Material',
type: 'asset',
assetType: 'material'
},
{
name: 'dirty',
title: 'My Dirty Material',
type: 'asset',
assetType: 'material'
},
{
name: 'damaged',
title: 'My Damaged Material',
type: 'asset',
assetType: 'material'
},
]
});
Then you could do something like this to switch the material of the render components you need to update:
SwitchingMaterials.prototype.changeToSpecificMaterial(entity, matId) {
// var i = 0;
// Get the next material asset in the array
// this.materialIndex = (this.materialIndex + 1) % this.materials.length;
// var material = this.materials[this.materialIndex];
var material = this.namedMaterials[matId];
// Assign the material to all the mesh instances in the model
var allMeshInstances = [];
// var renders = this.entity.findComponents('render');
var renders = entity.findComponents('render');
for (i = 0; i < renders.length; ++i) {
var meshInstances = renders[i].meshInstances;
for (var j = 0; j < meshInstances.length; j++) {
allMeshInstances.push(meshInstances[j]);
}
}
for (i = 0; i < allMeshInstances.length; ++i) {
var mesh = allMeshInstances[i];
mesh.material = material.resource;
}
}
You can see how I modified the previous changeToNextMaterial
function to work with a provided entity and id, but there are quite a few different way you could achieve the same thing for your project, likely in a cleaner fashion, depending on your needs.
I hope this is helpful.
This does seem far more complicated than it should be. But alright.
Actually I think it would be easier to have the same material but set a different texture and tint. How would I go about doing that.
Actually I got it working myself.
How did you get it to work?
Its kinda frankenstein code but just apply this to a button, set the number to 1, and it will change every entity with the tag player to whatever material it has assigned to it
// More information about materials: http://developer.playcanvas.com/en/tutorials/beginner/basic-materials/
var SwitchingMaterials = pc.createScript('switchingMaterials');
// Create an array of materials to cycle the model through
SwitchingMaterials.attributes.add("materials", {type: "asset", assetType: "material", array: true, title: "Materials"});
// initialize code called once per entity
SwitchingMaterials.prototype.initialize = function() {
this.entity.element.on('click', this.onClick, this);
this.materialIndex = 0;
};
SwitchingMaterials.prototype.onClick = function() {
this.theplayer = this.app.root.findByTag("player");
this.theplayer.forEach(function(playee){
var i = 0;
// Get the next material asset in the array
this.materialIndex = (this.materialIndex + 0) % this.materials.length;
var material = this.materials[this.materialIndex];
// Assign the material to all the mesh instances in the model
var allMeshInstances = [];
var renders = playee.findComponents('render');
for (i = 0; i < renders.length; ++i) {
var meshInstances = renders[i].meshInstances;
for (var j = 0; j < meshInstances.length; j++) {
allMeshInstances.push(meshInstances[j]);
}
}
for (i = 0; i < allMeshInstances.length; ++i) {
var mesh = allMeshInstances[i];
mesh.material = material.resource;
}
}.bind(this));
};
It is possible to remove the array true from the attribute but idk how that affects the rest of the code because it wasnt really meant for what I am doing.
Thanks!