Godot Version
4.3 (Steam)
Question
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!
1 Like
Your code looks great BTW, a pleasure to read.
Are you sure you are using StandardMaterial3D?
In the docs it also says:
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.
Might be worth checking.
1 Like
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.
Just to check, how about adding a 1.0 alpha value to the colour.
var color = Color(randf(), randf(), randf(), 1.0)
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.
This seems to change nothing, unfortunately.
It was a long shot
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?
Have you tried checking ālocal to sceneā? I think that forces non sharing of resources.
Iāve tried it with this as a test.
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)
Doesnāt seem to change the result, unfortunately.
Did you try clicking āLocal to sceneā?
I have no other ideas, sorry. This must be driving you up the wall! Your code looks spot on, I will have a look if there are any bug reports.
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?
I was about to post you this:
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!
1 Like