Godot version:
Version 3.1.1 official
OS/device including version:
windows 10
Issue description:
Steps to reproduce:
I create a cube, uvw map it, create texture, import it to godot.
I create a new inherited scene from the exported dae file, The texture is applied correctly and shows up in the material. The problem is with accessing it from code.
I put a script in MeshInstance like this
extends MeshInstance
export(Texture) var box_texture
func _ready():
print(get_surface_material_count())
print(get_surface_material(0))
var new_material = SpatialMaterial.new()
new_material.albedo_texture = box_texture
set_surface_material(0, new_material)
print(get_surface_material_count())
print(get_surface_material(0))
The result is like this:
* Debug Process Started *
OpenGL ES 3.0 Renderer: GeForce GTX 970M/PCIe/SSE2
1
[Object:null]
1
[SpatialMaterial:1146]
As you can see, even if the get_surface_material_count() sees the material, while getting the material using get_surface_material returns null object. On the other hand if I create a material on code and run the same print statements again, it shows correct SpatialMaterial.
Minimal reproduction project:
https://github.com/roiteee/godot_issue_surface_material
I think this reflects an issue with how the editor assigns materials.
If you do surface_get_material(0) on the Mesh, it should work. E.g.
$MeshInstance.mesh.surface_get_material(0)
script on MeshInstance
var mat = mesh.surface_get_material(0) #协褌芯褌 谐谢褞泻 械褋褌褜 薪邪 谐懈褌褏邪斜械!
print (mat)
Null
Still not working in 3.2 stable
Do you have your material assigned to the MeshInstance or to the Mesh?
Mesh.surface_get_material() returns the material assigned to a particular surface, while MeshInstance.get_surface_material() returns the surface material override.
To clarify what is going on here. It is not a bug. Below is a sample layout of a Mesh with 2 surfaces.
MeshInstance
|
-- Mesh
--|
---- Surface0
--|
---- Surface1
Materials can be assigned at different places. You can assign the material to the surfaces individually, you can assign a material override in the MeshInstance, or you can assign a per-surface material override in the MeshInstance
With Materials the above layout becomes
MeshInstance
| Material override (overrides all materials on all surfaces)
| Material0 (overrides Surface0 Material)
| Material1 (overrides Surface1 Material)
-- Mesh
--|
---- Surface0
----| Material
--|
---- Surface1
----| Material
The OP's issue is that they have assigned a material to "Surface0 Material" But then they are using MeshInstance.get_surface_material(0) which returns "Material0" which is rightly null
@lexpartizan I am guessing you have done the opposite. It sounds like you have assigned a material to "Material0" but are using Mesh.surface_get_material(0) which is returning "Surface0 Material" which is null
Can't this be unified somehow (potentially with a new function) so that it gets the override or mesh material, whichever exists?
@Zireael07 Thats a good idea. Something like MeshInstance.get_active_material()
Big Thanks!
The fact is that these methods are called very similar, but they are written a little differently.
MeshInstance.get_surface_material(0)
mesh.surface_get_material(0)
In the first case, the "get" is at the beginning, in the second in the middle.
I didn't notice this difference. And when just call Meshinstance this method, I thought that it does not exist.
@Lexpartizan I agree the naming is confusing. For 4.0 I would like to rename $MeshInstance.get_surface_material() to $MeshInstance.get_surface_override_material()
that would still have get at the beginning of 1 and the middle of the other. Instead of calling it get_active_material(), why not call it get_material()? Surely it isn't a stretch to infer that one wants the active one.
Most helpful comment
@Lexpartizan I agree the naming is confusing. For 4.0 I would like to rename
$MeshInstance.get_surface_material()to$MeshInstance.get_surface_override_material()