[SOLVED] How set collisionShape on MultiMeshInstance?

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

Hi i try to use MultiMeshInstance with collision node.
The attaches script works so far but the collision shape is only applyed to the MultiMeshInstance and not to the mesh instances.

Looks like MultiMeshInstance not handels collision shapes for all instances respecting translation, scale and rotating

The applied collision shape is static and has the original transformation from the original cube.
So how add a collision shape right to a MultiMeshInstance ?

Here my small test script

extends Node

func _ready():
	# create a simple box mesh
	var mesh = CubeMesh.new()
	mesh.size = Vector3(1,1,1)
	
	# create multi mesh
	var multiMesh = MultiMesh.new()
	multiMesh.transform_format = MultiMesh.TRANSFORM_3D
	multiMesh.color_format = MultiMesh.COLOR_FLOAT
	multiMesh.mesh = mesh
	multiMesh.instance_count = 4
	
	var mmi = MultiMeshInstance.new()
	mmi.multimesh = multiMesh;
	
	# create collision shape
	var collisionNode = StaticBody.new()
	var collisionShape = CollisionShape.new()
	collisionShape.shape = multiMesh.mesh.create_trimesh_shape()
	collisionNode.add_child(collisionShape)
	mmi.add_child(collisionNode)
	add_child(mmi)
	
	for mesh_index in range(multiMesh.instance_count):
		var position = Transform().translated(Vector3(mesh_index*2, 10+2, 0)).scaled(Vector3(1,1,1))
		multiMesh.set_instance_transform(mesh_index, position)

The official documentation has no info about MultiMeshInstance and using collision.
I use Godot 3.1.1

:bust_in_silhouette: Reply From: Zylann

I think a MultiMesh cannot currently be converted directly into a static body mesh. Even if it could, your code would not work for several reasons:

  • You are creating your static body from the single mesh, not the multimesh
  • You are defining where each instance is located only after creating your static body.

The transforms you are setting at the end are also purely for the renderer.

If you want collision on your instances, you need to create a static body for each of them, and give them the same transform.

Something like this (untested):

var shape = multiMesh.mesh.create_trimesh_shape()

for mesh_index in range(multiMesh.instance_count):
    var position = Transform().translated(Vector3(mesh_index*2, 10+2, 0)).scaled(Vector3(1,1,1))
    multiMesh.set_instance_transform(mesh_index, position)

    # create collision shape
    var collisionShape = CollisionShape.new()
    collisionShape.shape = shape
    var collisionNode = StaticBody.new()
    collisionNode.transform = position
    collisionNode.add_child(collisionShape)
    mmi.add_child(collisionNode)
    add_child(mmi)

Thanks for the fast anwser

That the anwser i unfortunately expected, ;(

My hope was the MultiMesh has some implemented functionallity to manage collision shapes by it self.
e.g. auto create collision shape for each instance and apply the transform by multiMesh.set_instance_transform( index, ..)

But what happens when i create tousends of multimesh ( original 1 mesh in memory) but additional extra tousends of collision shape nodes?
This takes the optimisations of MultiMesh ad absurdum or ?

Best Regards

Would be a good improvement for MultiMesh :wink:

NullPointer | 2019-10-01 14:03

I don’t know, I never had the need to give collision to thousands of individual objects at once so far. You could try and see.
The reason MultiMesh exists is because GPU instancing is a common rendering technique. But physics-wise, there doesn’t seem to be an equivalent, a static body is a static body.
Perhaps you could at least have a single static body, with a CollisionShape for each instead of many static bodies:

# Re-use the same shape
var shape = multiMesh.mesh.create_trimesh_shape()
# Create one static body
var collisionNode = StaticBody.new()
mmi.add_child(collisionNode)

for mesh_index in range(multiMesh.instance_count):
    var position = Transform().translated(Vector3(mesh_index*2, 10+2, 0)).scaled(Vector3(1,1,1))
    multiMesh.set_instance_transform(mesh_index, position)

    # Create many collision shapes
    var collisionShape = CollisionShape.new()
    collisionShape.shape = shape
    collisionShape.transform = position
    collisionNode.add_child(collisionShape)

Zylann | 2019-10-01 17:32

Thanks,

yes to use a single static body makes sence :wink:
I will do that in this way.

NullPointer | 2019-10-01 17:41

I was trying to figure out if it really would be better to use one static body with many collision shapes rather than many static bodies with one collision shape each, and I found some evidence for the latter.

According to the collision shape doc:

If a StaticBody has many collision shapes, the broad phase will fail. The narrow phase, which is slower, must then perform a collision check against each shape.

oxters168 | 2022-12-22 21:10