Material returning as Spatial in code but Shader in engine.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By DaddyMonster

The situation:

I’ve got a 3d model with many meshes which I originally imported with glTF (with materials) and set as a scene. I decided to change one of the many MeshInstances so, to avoid starting from scratch, I made a new model for the mesh in question, exported from blender as a obj and added that as a mesh (ArrayMesh) to the relevant MeshInstance. The new mesh has three surface materials. I made new materials in Material Maker, added them manually and converted them to ShaderMaterial.

The issue:

Even though the mesh’s surface materials are ShaderMaterial in the editor (and in Remote during runtime) and are rendered as the desired ShaderMaterial in the game, when addressed in code it returns as a SpatialMaterial.

That is to say: print(obj.mesh.surface_get_material(0)) returns [SpatialMaterial:2061]

Obviously, obj.mesh.surface_get_material(0).set_shader_param("foo", true) throws an error, no function set_shader_param on SpatialMaterial.

I’m certain I’m addressing the right object.

Remedies tried:

Reimporting the mesh / making a new MeshInstance node / making the shader material unique and saving it. It always remains a Spatial when addressed in code but appears as Shader in editor.

Is either the .mtl or .glTF file somehow acting in the background here but only in code?

Anyone know what’s going on?

:bust_in_silhouette: Reply From: maximinus

I had the same problem and this was the only google link that mentioned it.

So I think that the mesh is instanced from the file; if you change one of the materials, quit godot and then load back the scene you’ll see the materials go back to what they where.

The solution is to add a material to the MeshInstance, NOT the Mesh. If you import a mesh, then the properties window for me shows:

MeshInstance → Mesh → Surface1, Surface2 etc

You can leave those surfaces alone, instead, if we want to change surface2m we need to add:

Meshinstance → Material → 2

Again, all in the properties tab. Now if you write:

$name_of_node.get_surface_material(index_of_material)

Will indeed return a ShaderMaterial. Also, the shader material will override what material is in the Mesh.

Hope this helps somebody!

Nice. I’m a little embarrassed I didn’t figure this out for myself, I ended up reimporting the entire mesh. Still, great advice for someone googling the issue in the future.

DaddyMonster | 2021-09-22 19:18