I want to change the materials of a glb model after loading it.Is this possible?
for(i in 0 until asset?.materialInstances?.size!!){
asset!!.materialInstances[i] = materialInstance
}
I am trying to set the material instance like this but it doesnt reflect on the model
How to update the materials in the model
The list of material instances in the glTF asset is immutable, but you can swap out the active material instances by iterating over asset.entities and using RenderableManager.getInstance() to extract each entity's associated renderable. (however note that not all entities have associated renderables)
Some of the useful RenderableManager methods in this scenario are getInstance(), setMaterialInstanceAt(), and getMaterialInstanceAt().
@prideout What is primitive index in setMaterialInstance and getMaterialInstance ?What should i set it too?
I think it would be really help if filament can have a usage documentation as well describing how to use it and small description on what all the parameters. Is there any future plans on this?
I am doing this still the model doesn't reflect any changes
for (i in 0 until asset?.entities?.size!!) {
asset?.entities?.get(i)?.let {
var entity = renderableManager.getInstance(it)
MaterialBuilder.init()
val matPackage = MaterialBuilder().platform(MaterialBuilder.Platform.MOBILE)
// Set the name of the Material for debugging purposes.
.name("Clear coat")
// Defaults to LIT. We could change the shading model here if we desired.
.shading(MaterialBuilder.Shading.LIT)
// Add a parameter to the material that can be set via the setParameter method once
// we have a material instance.
.uniformParameter(MaterialBuilder.UniformType.FLOAT3, "baseColor")
// Fragment block- see the material readme (docs/Materials.md.html) for the full
// specification.
.material(
"void material(inout MaterialInputs material) {\n" +
" prepareMaterial(material);\n" +
" material.baseColor.rgb = materialParams.baseColor;\n" +
" material.roughness = 0.15;\n" +
" material.metallic = 0.8;\n" +
" material.clearCoat = 1.0;\n" +
"}\n"
)
// Turn off shader code optimization so this sample is compatible with the "lite"
// variant of the filamat library.
.optimization(MaterialBuilder.Optimization.NONE)
.build()
if (matPackage.isValid) {
val buffer = matPackage.buffer
material = Material.Builder().payload(buffer, buffer.remaining()).build(engine)
}
// We're done building materials, so we call shutdown here to free resources. If we wanted
// to build more materials, we could call MaterialBuilder.init() again (with a slight
// performance hit).
MaterialBuilder.shutdown()
materialInstance = material.createInstance()
// Specify that our color is in sRGB so the conversion to linear
// is done automatically for us. If you already have a linear color
// you can pass it directly, or use Colors.RgbType.LINEAR
materialInstance.setParameter(
"baseColor",
Colors.RgbType.SRGB,
212.0f,
175.0f,
55.0f
)
Builder(1)
.material(0, materialInstance)
// .geometry(0, PrimitiveType.TRIANGLES, vb, ib)
.build(engine, entity)
renderableManager.setMaterialInstanceAt(entity,500000,materialInstance)
}
}
Agreed that we should document this better; this tutorial might help a little, as well as the Javadoc for RenderableManager.
In Filament, Renderables are bundles of primitives, each of which has its own geometry and material. This is similar to glTF, where a "mesh" is composed of primitives, each of which has its own geometry and material.
Here are my notes about your code snippet:
primitiveIndex in setMaterialInstance is typically a small number like 0 or 1, not 500000. I suspect that's where your bug is.Builder(1)...build(engine, entitiy) towards the end of your loop body.createInstance on the material is fairly lightweight, but building the package is not, so you might want to move all the MaterialBuilder stuff to outside the loop.var entity = renderableManager.getInstance(it) I would say val renderable = renderableManager.getInstance(it). You already have the "entity" in the it variable, and the renderable component is really what this variable represents.You definitely don't want to compile a new material for every item in the list. You are also doing an init/shutdown cycle every time which is going to be very expensive.
Thank you to both, I am really looking forward to javadoc whenever it comes out.
I will try your suggestions and let you know how it works :)
@prideout It absolutely worked you guys are awesome! Keep up the good work.
@romainguy Also I only run the init/shutdown cycle once now and it runs faster than before
P.S.
I set the primitiveIndex to 0.
Most helpful comment
Agreed that we should document this better; this tutorial might help a little, as well as the Javadoc for RenderableManager.
In Filament, Renderables are bundles of primitives, each of which has its own geometry and material. This is similar to glTF, where a "mesh" is composed of primitives, each of which has its own geometry and material.
Here are my notes about your code snippet:
primitiveIndexinsetMaterialInstanceis typically a small number like 0 or 1, not 500000. I suspect that's where your bug is.Builder(1)...build(engine, entitiy)towards the end of your loop body.createInstanceon the material is fairly lightweight, but building the package is not, so you might want to move all the MaterialBuilder stuff to outside the loop.var entity = renderableManager.getInstance(it)I would sayval renderable = renderableManager.getInstance(it). You already have the "entity" in theitvariable, and the renderable component is really what this variable represents.