I have an object that creates n amount of objects. Each of these should be assigned a unique color.
for i in numberOfCables:
var cableInstance = cable.instantiate()
var color = Color(randf(),randf(),randf())
cableInstance.set_color(color)
[...]
cables.append(cableInstance)
add_child(cableInstance)
in this case, set_color(color) is run.
extends Node3D
[...]
func set_color(color):
var mesh_instances = find_children("*", "MeshInstance3D", true, false)
print(mesh_instances)
for mi in mesh_instances:
var mesh = mi.get_mesh()
# Ensure there's a material on the surface before modifying
if mesh and mesh.surface_get_material(0):
# Duplicate the material to create a unique instance
var material = mesh.surface_get_material(0).duplicate()
# Set the albedo color
if material is StandardMaterial3D:
material.albedo_color = color
# Apply the unique material to the mesh surface
mesh.surface_set_material(0, material)
This script duplicates the color-changing material, and assigns it to the new instance, yet all of the created Cables have the same color in the end!
Alpha channel in albedo color and texture is also used for the object transparency. If you use a color or texture with alpha channel, make sure to either enable transparency or alpha scissoring for it to work.
Looks to be one!
I am loading the models in as .blend files, but as far as Iām aware, this shouldnāt be causing this issue.
Additionally, the color is changed from the default (the red tone you see in the material preview) so it definitely is using StandardMaterial3D and applying the color. The color is just applied to all of the objects, despite me explicitly duplicating the materials to make them unique to each of them.
I did some more testing. Even assigning an external Material directly seems to cause this issue.
I am guessing the issue is that each cable is instantiated, instead of being a unique object.
But even if they are instantiated, you have taken the material, copied it, made it unique and replaced it. I honestly canāt see anything wrong with your code.
How about having it without a material on instantiation. Then adding a unique material?
This part is responsible for choosing the to-be-applied materials.
var redRubberMaterial = preload("res://materials/redRubber.tres")
var whiteRubberMaterial = preload("res://materials/whiteRubber.tres")
func chooseMaterial(index):
var material = redRubberMaterial;
if (index%2==1):
material = whiteRubberMaterial;
return material;
Thos section acts like before, but instead of changing the color of a material, it instead replaces the material entirely with either redRubberMaterial or whiteRubberMaterial.
for i in numberOfCables:
var cableInstance = cable.instantiate()
cableInstance.set_material(chooseMaterial(i))
cableInstance.cableId = i+1
cableInstance.position = cableSpawn.position
cableInstance.position.x += -0.3 + float((0.6/numberOfCables)*(i+0.5))
cables.append(cableInstance)
add_child(cableInstance)
This is the code responsible for changing the material.
func set_material(material):
var mesh_instances = find_children("*", "MeshInstance3D", true, false)
for mi in mesh_instances:
var mesh = mi.get_mesh()
if mesh and mesh.surface_get_material(0):
mesh.surface_set_material(0, material)
However, no matter what, only the whiteRubberMaterial is ever shown.
Right, but how do I do this in code? These nodes are created at runtime through var cableInstance = cable.instantiate() and then added to the hierarchy by add_child(cableInstance)
Right, but where? What should be local to scene?
All of the relevant nodes do not offer this as an option.
This is the hierarchy of the created Object. In this case, the materials on mdl_cable_origin, mdl_cable_destination, mdl_plug_origin and mdl_plug_destination should be changed to the desired one.
I think the issue is because I am using Blender files directly. This may be a hint?
To import Blender files into Godot, you can follow these steps:
In Godot 4.0 onwards, the editor can directly import .blend files by calling Blenderās glTF export functionality transparently.
In Godot project settings, under Import Defaults, select āSceneā from the Importer Dropdown.
Scroll down to āImport Script Pathā and load the standard import path for the addon: res://addons/blender_godot_pipeline/GLTFImporter.gd. This ensures that all your GLTF or .blend files get the importer attached
This finally allowed me to set the plug model as local to the scene.
This should really be a default feature of Godot, lel.
Anyhow, that solved it. Thank you!