Well i got this far:

The problem is that the tooltip that displays item name, when ever node is in motion, it translates slower than the parent.

Not sure why it does that or how to avoid that.

I want to keep the tooltip on top of the AABB of the item mesh (i got that part figured out) but also keep it in that position when the parent node is moving.

Right now when i throw the item or pick it up for some reason the tooltip gets moved real far away from apparent mesh AABB.

Inside the tooltip:

extends Node3D
class_name ToolTip3D

@onready var v_offset:Vector3 =Vector3.UP * vertical_offset 
var v_mesh_end:Vector3
@export var owner_path: NodePath
@onready var owner_node = get_node(owner_path)

func _ready() -> void:
	label.text = text_value
	top_level = true
	
	if not owner_node: owner_node = get_parent()
	
	offset  = to_local(owner_node.global_transform.origin)
	get_item_data_update_label()
	set_node_size_and_position()
	pass # Replace with function body.

func _process(delta: float) -> void:
	set_node_size_and_position()

func get_mesh_end(_owner_node:Item):
	var item_mesh:MeshInstance3D = _owner_node.item_mesh
	if not item_mesh == null:
		var end:Vector3
		var aabb = _owner_node.item_visual_node.global_transform * item_mesh.get_aabb().abs() 
		
		var size = aabb.size 
		var tooltip_rect = sprite_3d.get_aabb().abs().size
		var tooltip_size = Vector3.UP * (tooltip_rect )
		
		end = Vector3.UP * (tooltip_size + (aabb.end )) 
		
		return end

func set_node_size_and_position():
	
	if owner_node is Item:
		if not owner_node.item_mesh == null:
			v_mesh_end = get_mesh_end(owner_node)
			
	sub_viewport.size = panel_container.get_rect().size
	
	self.global_transform.origin = owner_node.global_transform.origin + v_offset + v_mesh_end #- offset


With item:


EDIT:
Maybe its related to top_level = true. But if i dont set it to true then whenever the parent rotates the tooltip rotates with it , and sometimes it gets stuck under the floor, depending on rotation.

Maybe im doing this simple thing completely wrong?

    kuligs2 Keep the tooltip completely separate from the object, i.e. don't parent it.

      Jesusemora Did not know such thing existed, so i just did the next best thing - improvised 😃. Will look into it.

      xyz But thats counter-intuitive. One would think that you keep that data/node with the ItemNode itself. Will have to try it out.

      • xyz replied to this.

        kuligs2 But thats counter-intuitive

        Not really. It's how it's typically done. Parenting implies transformation inheritance. A label doesn't need to inherit object's transformation matrices, it just needs to follow the object. This following is often not strict. Many situations can happen where you have to nudge or adapt the label position for various reasons so the relative position from the object can vary. Also parenting will inherit rotation and scaling which you typically don't want. From logical/design standpoint the relation between an object and its label is not parent-child relation.

          xyz unless we use label3D and billboard, then we don't have to worry about rotation, or any code at all.

          • xyz replied to this.

            Jesusemora unless we use label3D and billboard, then we don't have to worry about rotation, or any code at all.

            We actually still have the rotation inheritance problem. For example if you want the label to always appear "above" the object and you position a child Label3D in that way, if you rotate the parent object for e.g. 180 degrees the label will go "below". So you still need to nullify the rotation. The parent space transformation will affect the position of the parented label which is typically what you don't want. Sure, you can set the label transforms to be top level but then all the placement code would need to be exactly the same as if it wasn't parented at all. So there's really no way to do it without some placement code.

              xyz i tried your method by adding tooltip to the world (child of world) and then set transforms to the item so that it appears at the top of the object, but still i face the same problem where the label is falling behind the item placement when its going real fast.

              Its pretty much the same result i had when using the tooltip inside the Item Node. This time like you say, i didnt have to set top_level = true because the rotation of the item does not affect the tooltip.

              Also i used the Label3D in this example. Works fine i guess. Few less nodes to worry about.

              Mu hunch for the delayed transforms is this line in the _process() function:

              	self.global_transform.origin = owner_node.global_transform.origin + v_offset + v_mesh_end

              where v_offset is an exported value and customizable, default 0.0 and v_mesh_end is vertical offset of the mesh end, owner_node.global_transform.origin is the basepoint of the Item Node at 0,0,0

              Maybe setting the property .origin is not the best practice? Maybe i should use a function, maybe translate() or something?

              • xyz replied to this.

                kuligs2 Try calling force_update_transform() on the label node after setting its position. Also, make sure that code that sets label's position is executed after the code that sets object's position.

                  xyz Label position is set in _process() of the node itself.
                  The Item Node does not know anything about the ToolTip node.
                  I guess i need to somehow set the ToolTipNode position from within the Item Node?

                  • xyz replied to this.

                    kuligs2 It doesn't matter where exactly they are, just that they are executed in said order. Otherwise the label will copy object's position from the previous frame because object's current frame script hasn't yet been executed. Scripts always execute in order in which nodes appear in the tree (for siblings) and children are executed before parents. So note that you can change the order of execution by merely shuffling the nodes around. Print something from each script's _ready() to see in what order they execute if you're not sure.

                    Alternatively you can do updating of both things from the same script.

                      xyz Printing out _ready()

                      ItemNode
                      ItemNode
                      ItemNode
                      ItemNode
                      ItemNode
                      ItemNode
                      ItemNode
                      Tooltip3dv2
                      Tooltip3dv2
                      Tooltip3dv2
                      Tooltip3dv2
                      Tooltip3dv2
                      Tooltip3dv2
                      Tooltip3dv2
                      --- Debugging process stopped ---

                      Hmm... i just noticed something. The problem is not where i set the value but the vertical offset calculation. As i ascend the slope the tooltip ascends with me

                      So i guess there goes my math. 😃..

                      Need few moments to catch my bug in the code... brb

                      EDIT: Found the bug
                      added -owner_node.global_transform.origin

                      Works good now.. need to clean up but principle is now understandable

                      func get_mesh_end(_owner_node:Item):
                      	var item_mesh:MeshInstance3D = _owner_node.item_mesh
                      	if not item_mesh == null:
                      		var end:Vector3
                      		var aabb = _owner_node.item_visual_node.global_transform * item_mesh.get_aabb().abs() 
                      	
                      		var size = aabb.size 
                      		var tooltip_rect = label_3d.get_aabb().abs().size
                      		var tooltip_size = Vector3.UP * (tooltip_rect )
                      	
                      		end = Vector3.UP * ((tooltip_size + (aabb.end )) - _owner_node.global_transform.origin)
                      		
                      		return end
                      	else:
                      		return null
                      func set_node_size_and_position_v2(_owner_node):
                      	
                      	if not _owner_node == null and _owner_node is Item:
                      		if not _owner_node.item_mesh == null:
                      			v_mesh_end = get_mesh_end(_owner_node)
                      			
                      		self.global_transform.origin = _owner_node.global_transform.origin + v_offset + v_mesh_end #- offset