Hi,
for level editing (in Godot) I use a bunch of FBX models. Each of them contains one or more submeshes. I opened each of the models as new inherited scene, added collision and saved the new scene. Mostly I assigned a (default) material I created before (just to see how it looks). This is my standard workflow.
Inherited scene of FBX model with submeshes (just opened to show, not edited)
For the FBX models there are up to 16 textures available, each representing a different appearance of the model. For every texture I created a seperate material manually.
Now I want to use these scenes to create some kind of placeable game object scenes, switch their type (visibility of subnodes) and appearance (material of subnode meshes).
Game object scene with multiple inherited scenes (meshes)
For example (sorry for talking about walls and seeing trailers in code/images): There are different wall model (or other) scenes with one or more mesh instances as children and each mesh instance can have one or more materials assigned to it.
My goal is it, to place some of the walls (or other objects) an change their appearance by replacing/overriding their material by/with another one to create different appearing walls (or other objects).
Scene containing game object scenes
I tried it by code (GDScript) as a tool within the editor (by different export variables) and first it seems to work, but there are some issues. When reopening a scene where these "game objects" are placed or adding it to other scenes, all of them are "resetted" to the default material I assigned while creating the inherited model scenes.
Scene with added scene containing game object scenes with unexpected appearance
To change a material within the tool script I get all mesh instance nodes. One way was to get all surface materials and set them to the new one. The second try was to set the "material_override"-Property. Both leads to the issue.
Sample Code (not the complete script):
tool
extends Spatial
# Different types of trailer models
enum TRAILER_TYPE {
TRAILER_1, TRAILER_2,TRAILER_1_DAMAGED,TRAILER_2_DAMAGED
}
# Different types of materials
enum MATERIAL_TYPE {
DEFAULT, INTERIOR, GLASS
}
# Dictionary with pathes to mesh nodes of different trailer models
const TRAILERS = {
"TRAILER_1": {
"NodeName": "SM_Bld_Trailer_01",
"DEFAULT": [
"SM_Bld_Trailer_02",
"SM_Bld_Trailer_02/SM_Bld_Trailer_Skirt_02"
],
"INTERIOR": [
"SM_Bld_Trailer_02/SM_Bld_Trailer_Interior_02",
"SM_Bld_Trailer_02/SM_Bld_Trailer_Interior_02/SM_Bld_Trailer_Interior_Door_02"
],
"GLASS": [
"SM_Bld_Trailer_02/SM_Bld_Trailer_Glass_02"
]
},
"TRAILER_2": {
"NodeName": "SM_Bld_Trailer_02",
"DEFAULT": [
"SM_Bld_Trailer_03",
"SM_Bld_Trailer_03/SM_Bld_Trailer_Skirt_03"
],
"INTERIOR": [
"SM_Bld_Trailer_03/SM_Bld_Trailer_Interior_03"
],
"GLASS": [
"SM_Bld_Trailer_03/SM_Bld_Trailer_Glass_03"
]
},
"TRAILER_1_DAMAGED": {
"NodeName": "SM_Bld_Trailer_Damaged_01",
"DEFAULT": [
"SM_Bld_Trailer_Damaged_02"
],
"INTERIOR": [
"SM_Bld_Trailer_Damaged_02/SM_Bld_Trailer_Damaged_Interior_02"
],
"GLASS": [
"SM_Bld_Trailer_Damaged_02/SM_Bld_Trailer_Damaged_Glass_02"
]
},
"TRAILER_2_DAMAGED": {
"NodeName": "SM_Bld_Trailer_Damaged_02",
"DEFAULT": [
"SM_Bld_Trailer_Damaged_03"
],
"INTERIOR": [
"SM_Bld_Trailer_Damaged_03/SM_Bld_Trailer_Damaged_Interior_03"
],
"GLASS": [
"SM_Bld_Trailer_Damaged_03/SM_Bld_Trailer_Damaged_Glass_03"
]
},
}
# Export variables
export (Game.Materials.PA_TYPE) var default_material = Game.Materials.PA_TYPE.PA_01_A setget _set_default_material
#export (Game.Materials.PA_TYPE) var interior_material = Game.Materials.PA_TYPE.PA_01_A setget _set_interior_material
#export (Game.Materials.GLASS_TYPE) var glass_material = Game.Materials.GLASS_TYPE.GLASS_01 setget _set_glass_material
export (TRAILER_TYPE) var trailer_type = TRAILER_TYPE.TRAILER_1 setget _set_trailer_type
# Private variables
var _current_trailer_node: Node #current node containing the mesh instances (could be multiple within the scene)
var _current_default_material: Material #current material mesh instance nodes (default means outside part meshes)
#var _current_interior_material: Material
#var _current_glass_material: Material
# Create materials instance for function calls
var _materials = Game.Materials.new() #contains all the loaded material resources
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass
func _set_default_material(mat_type: int) -> void:
if _current_trailer_node:
default_material = mat_type
var trailer_key = TRAILER_TYPE.keys()[trailer_type]
_current_default_material = _materials.get_material_PA(mat_type) #change the current material to the new one
for mesh_name in TRAILERS[trailer_key]["DEFAULT"]: #node pathes to the mesh instance nodes
var mesh = _current_trailer_node.get_node(mesh_name) #get the mesh instance node
if mesh:
mesh.material_override = _current_default_material
# for index in mesh.get_surface_material_count():
# mesh.set_surface_material(index,_current_default_material)
func _set_trailer_type(tt: int) -> void:
... # handling stuff to change _current_trailer_node (and visibility) whose meshes should be affected by changing material
Am I completely wrong with this approach? Maybe better change the albedo texture of the mesh instance material? Use the mesh material itself or use the override material and how about multiple materials at the mesh?
Will it eventually be a better solution, to create a seperate inherited scene for every appearance (material)? But this will increase the amount of scenes (f.e. one wall mesh with two materials and 16 textures... in combination there would be 32 scenes for just one wall element).
How to deal with this problem in general?
Thanks in advance for reading and maybe helping.
Cheers Z3R0PTR