Filament: How can i change materials of a GLB model to my material Instances?

Created on 24 Jun 2020  路  8Comments  路  Source: google/filament

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

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:

  • The primitiveIndex in setMaterialInstance is typically a small number like 0 or 1, not 500000. I suspect that's where your bug is.
  • I don't think you need the Builder(1)...build(engine, entitiy) towards the end of your loop body.
  • Calling 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.
  • Minor naming suggestion: instead of 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.

All 8 comments

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:

  • The primitiveIndex in setMaterialInstance is typically a small number like 0 or 1, not 500000. I suspect that's where your bug is.
  • I don't think you need the Builder(1)...build(engine, entitiy) towards the end of your loop body.
  • Calling 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.
  • Minor naming suggestion: instead of 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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Y0hy0h picture Y0hy0h  路  5Comments

MHDante picture MHDante  路  4Comments

ferry-creator picture ferry-creator  路  4Comments

dakom picture dakom  路  5Comments

yongtang picture yongtang  路  5Comments