Reparent with Children Attached

Godot Version

4.1.1

Question

I have a blender-to-Godot pipeline that basically works in two steps:

  1. Parse out the GLTF file as it imports - this maps custom object and vertex data properties into node metas
  2. A “Scene Init” script gets attached, and runs when the GLTF import gets first dragged into the scene. This iterates through the newly populated metas and performs certain setup actions in the node tree

This lets me do all kinds of things like setting scripts, shaders, textures, setting collision types, etc., however, I am running into a decent amount of complexity when trying to convert a basic MeshInstance3D that comes in from the GLTF file into a RigidBody3D.

Conversely, adding a StaticBody3D was easy because all you have to do is add a couple of children to the MeshInstance3D:

MeshInstance3D
→ StaticBody3D
→ -> CollisionShape3D

Easy.

With RigidBody3D, I have to restructure the whole thing, where the structure is now:

RigidBody3D
→ MeshInstance3D
→ CollisionShape3D

Right now I’m doing this, and it’s causing me issues whenever other objects are parented to the MeshInstance3D:

func setGenericCollision(node, rigid_body=false):
	var body = StaticBody3D.new()
	body.name = "StaticBody3D"
	
	if rigid_body:
		body = RigidBody3D.new()
		body.name = node.name + "_RigidBody3D"
		body.transform = node.transform
		
		# this doesn't work super well because really it needs
		# to recursively check all child nodes... complicated
		var new_node = node.duplicate()
		new_node.transform = Transform3D.IDENTITY
		body.add_child(new_node)
		
		node.get_parent().add_child(body)
		new_node.set_owner(get_tree().edited_scene_root)
		
		node.hide()
		
	else:
		node.add_child(body)
	
	body.set_owner(get_tree().edited_scene_root)		
		
	var collision = CollisionShape3D.new()
	collision.name = "CollisionShape3D"
	
	return [body, collision]

func setShape(col, shape):
	col[1].shape = shape
	
	col[0].add_child(col[1])
	col[1].set_owner(get_tree().edited_scene_root)

And then in the calling code:

						var col = setGenericCollision(node, rigid_body)
						
						var box = BoxShape3D.new()
						
						var size_x = float(node.get_meta("size_x"))
						var size_y = float(node.get_meta("size_y"))
						var size_z = float(node.get_meta("size_z"))
						
						box.size = Vector3(size_x, size_y, size_z)
						
						setShape(col, box)

(In this example I have a Blender add-on which I coded that finds the extents of the mesh and then tags custom data with the collision dimensions, which get brought in through my import pipeline)

My question is this:

Can I reparent my MeshInstance3D to a RigidBody3D, and keep all of the child nodes?

My use case would be applying forces to the RigidBody3D to move it, and have all the attached child nodes move with it.

Nevermind - I think I got it. In order to reparent and retain all children, the reparent() method must be called in a second pass. You can’t reparent while iterating through all nodes in the scene (which makes sense).

The other thing is that you have to recursively go through all the children and set the scene root:

func secondPass():
	
	for node in reparent_nodes:
		#[node, reparent_to]
		node[0].reparent(node[1])
		node[0].set_owner(get_tree().edited_scene_root)
		
		set_children_scene_root(node[0])
	

func set_children_scene_root(node):
	for child in node.get_children():
		set_children_scene_root(child)
		child.set_owner(get_tree().edited_scene_root)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.