Question about set() method.

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

Why does this work

var color = get_node("/root/Root/Constants/PowerColor").color
get("material/0").set_shader_param("albedo", color)
get("material/1").set_shader_param("albedo", color)

but this does not

var color = get_node("/root/Root/Constants/PowerColor").color
set("material/0/shader_param/albedo", color)
set("material/1/shader_param/albedo", color)

I’m using Godot 3.2 stable. I’ve tried to debug this using the black and white console and using the blue output box, but so far, there was no error detected. When I ran the former code, it worked as intended. It changed the material color. But when I ran the latter code, not only did it not work, the entire material stopped working. Yet I did not see any error in the console whatsoever.

As to why I am asking this question despite having a working code (An answer to those guys who get annoyed when people ask questions when there isn’t a problem :P). It’s because I’m trying to make my game run on the lowest amount of processes as possible. If it doesn’t make sense, I’m trying to apply my knowledge on “pointers”. Let say for example you need to access a variable and the normal route is

point0 ->point1-> point2 -> variable

What you see, is the normal route that is similar to my working code. From point0 to the variable it has undergone 3 steps.

 point0 -> variable

Now what I was going for with my non-working code was to reduce the steps by having it point directly to the variable I wish to access. It’s confusing for some people but the goal here is to reduce the amount of processing power.

:bust_in_silhouette: Reply From: Zylann

"material/0" and "material/1" are property paths that the engine is actually exposing and checking when you use set. They exist to simplify saving them to scene files (since they aren’t actual properties, more like arrays of properties). However, it doesn’t go outside of the current object.
See https://github.com/godotengine/godot/blob/master/scene/3d/mesh_instance.cpp#L55

The current node and its material are whole different objects, so it makes sense that adding /shader_param to the path won’t take it, properties don’t work like that.
And even if it somehow worked, it would not reduce the number of steps at all.

Also, using get and set is slower than using methods and properties designed for it in the first place, because you specified that using strings which need to be parsed by the engine at runtime before it finds out which property you use.

If you want to reduce CPU usage, here is what you should do:

get_surface_material(0).set_shader_param("albedo", color)
get_surface_material(1).set_shader_param("albedo", color)

And if you are doing it often on the same node, you could cache the materials in member variables.

Note: the same applies to get_node.The $ syntax would be faster, however you query from absolute path, which is not optimal (or recommended). You could cache it in _ready if possible.

Just to confirm for myself: You can’t use get/set to access properties that are not part of the object you’re calling them on. The ability to make properties have a pathlike name is just for cosmetics (folding in editor). Is that correct?

omggomb | 2020-02-20 15:05

The “path-like” naming of those properties is getting used in several ways:

First it’s like a convention for array-like or map-like properties so they can be read and written as if they were individual properties. Otherwise you would have to call functions with arguments.

Second is categories. If such properties get exposed to the inspector, they will be placed in a collapsible section, however I believe this is an old way to make categories. See SpatialMaterial: https://github.com/godotengine/godot/blob/851cb429631168369d2a51812de763b658795fbf/scene/resources/material.cpp#L2232

Zylann | 2020-02-20 19:01

Thanks, Zylann I learned a lot :slight_smile:

Xian | 2020-02-21 01:23