I have a MeshInstance object that creates a mesh via script.
But it depends of a bitmap that is created in a TextureRect, that is a child of a Viewport. And that bitmap is created with a script (and that bitmap depends on a shader, that is inside the TextureRect).
The MeshInstance should only be calculated after the bitmap is fully calculated.
So, how can I make sure the mesh is calculated after the bitmap?
I placed the MeshInstance and the Viewport/TextureRect inside a Node. So, is there a way to evoke code inside a script attached to the Node, so that it calls some code inside the MeshInstance scrip only after calling code inside the Viewport?
I believe it should be made with signals and, probably, Yeld something, until the Viewport signals that the bitmap is ready, but I really don't know how to do that, because it seems that a very specific hierarchy must be set.
Any help on this?
Execution order
Probably signals and yield, but also understanding the node structures and orders in the scenetree as well.
https://docs.godotengine.org/en/stable/tutorials/scripting/scene_tree.html
Thank you, Megalomaniak. I read the text in the link. And I don't see where is the "Root Viewport" that is mentioned. When I start a new 3D Scene, for instance, I only get a Spatial node. Not a Viewport.
Anyway, this is what I have and what I want to be able to do:
Is it difficult?
- Edited
rui_mac And I don't see where is the "Root Viewport" that is mentioned
When a project is running, click the Remote tab in the scene dock. The "root" node at the top is the root viewport. If you click on it, its properties will be shown in the Inspector.
For timing stuff like this, it is best to put a script on the root node of your scene to organize it. The actual code (like processing a texture) and be done on a local script, but the root script can organize it (call the functions on each node in the correct order, and get the return results from each step to pass to the next node's function). Signals could work, however, the order will be dependent on the order the nodes are initialized. If you put a script on the root, you are guaranteed that all other nodes in the whole scene are ready, and then you can start the process.
cybereality the root node of your scene
I assume you mean the top level node that you've created, rather than "/root". The terminology can be confusing in this case.
Yes, the node all the way on top. This is called the root node, root itself should never be used (this is actually a Viewport that renders the scene on the screen).
cybereality This is called the root node, root itself should never be used (this is actually a Viewport that renders the scene on the screen).
Yes, the application output buffer, essentially.
So, if I wanted to add signal processing to the script that generates the mesh, and assuming that the MeshInstance object is named "planet_mesh", I should add the code:
var planet = get_node("../planet_mesh") # this would reference the object itself
planet.connect("create_mesh",self,"calculate_mesh")
Right?
And, if yes, in what method/function should I add this code?
And where should I place the...
signal create_mesh
???
On a script, assigned to the root node?
If you want reference the object itself, you use self
. But self
is implied, so you don't need to write it when calling functions or accessing properties. So you can just do this:
connect("create_mesh", self, "calculate_mesh")
The code:
signal create_mesh
Should be near the top of the same script as above, which would be on the planet mesh object.
Thank you so much.
So, in what method/function should I place the
connect("create_mesh", self, "calculate_mesh")
???
And, if I send the the signal "create_mesh" from a script assigned to the root node, must I also add the code...
signal create_mesh
to the top of the script in the root node?
The connect
call needs to be in the same script file as where the calculate_mesh()
function is. The signal create_mesh
only needs to be in that same file, not any others. But when you emit the signal, it has to be called on the node that has the original script.
get_node("Planets/EarthPlanet").emit_signal("create_mesh")
cybereality Yes, the node all the way on top. This is called the root node, root itself should never be used (this is actually a Viewport that renders the scene on the screen).
So one is the root node and the other is the root node
- Edited
The top most node of your scene is called the root node in the Godot documentation. I think this should be assumed, unless otherwise stated, because there is no way to click on the real root node or attach a script via the editor (though you could do it with code possibly and break your game).
On top of acting like nodes, scenes have the following attributes:
They always have one root node, like the "Character" in our example.
https://docs.godotengine.org/en/stable/getting_started/step_by_step/nodes_and_scenes.html
Ok, so let's see if I got this correctly (and I will try to be as clear as I can.
Imagine I have this hierarchy:
And I have a script attached to the Universe node, another attached to the planet_texture node and another to the planet_mesh node.
The script attached to the planet_texture node, calculates the bitmap that will be required by the script attached to the planet_mesh node, to create the mesh. This means that the script that generates the bitmap needs to run first and only after it is finished, the script that creates the mesh can be executed.
So, inside the script attached to the Universe node (my Scene Root), I code this:
func _ready():
get_node("planet_stuff/planet_texture").emit_signal("create_heightmap")
yield(get_node("planet_stuff/planet_texture"),"heightmap_done")
get_node("planet_stuff/planet_mesh").emit_signal("create_planet")
Inside the script attached to the planet_texture node, I code:
signal create_heightmap
signal heightmap_done
func _init():
connect("create_heightmap",self,"calculate_all")
func: calculate_all:
# do bitmap stuff
emit_signal("heightmap_done")
And, in the scrip attached to the planet_mesh node, I code:
signal create_planet
func _init():
connect("create_planet",self,"calculate_mesh")
Is this the correct way of doing it?
Because I still get warnings telling me that the signal 'create_planet" is declared and never emitted, that the function 'connect()' returns a value, but this value is never used, and errors telling me that I'm attempting to call function 'get_texture' in base 'null instance' on a null instance.
Sorry, I mixed things up. This:
signal create_planet
Should be in the file that emits that signal. Though it will work either way, that is the correct method.
I don't get the connect warning on my test app Godot 3.4.4, put you can do this to make it go away:
var _val = connect("create_planet",self,"calculate_mesh")
The get_texture() error is just standard node search or initialization problem. Most likely the node reference is wrong, like if you did get_node("a_typo") and that will be null. Or if the name is correct, but it is not a child on that node, etc.
The error about the null instance is in a specific line of code, inside the script that creates te mesh. I tried using relative referencing, with:
var vpimg = get_node("../planet_texture").get_texture().get_data()
and even absolute referencing, with:
var vpimg = get_node("planet_stuff/planet_texture").get_texture().get_data()
And I still get the same error, whenever I save the file.
Also, I get this error:
Signal 'create_planet' is already connected to given method 'calculate_mesh' in that object
What could it be, since I only have one line code that connects the signal to the method?
You might want to read this tutorial regarding node paths, as it's essential to using Godot.
https://kidscancode.org/godot_recipes/basics/getting_nodes/
Did you connect the signal with the editor? You may have to undo that with the Node tab on the right side.
I did read that tutorial. And, according to my hierarchy, the script attached to the planet_mesh should point to the planet_texture node by going up one level, and pointing the planet_texture, as the planet_texture node is a sibling of the planet_mesh node.
I did not connect the signal with the editor. Maybe that is the problem. I will check if out.
- Edited
What node is the script attached to? Also, are you properly deleting the node when you're done?