The Godot Q&A is currently undergoing maintenance!

Your ability to ask and answer questions is temporarily disabled. You can browse existing threads in read-only mode.

We are working on bringing this community platform back to its full functionality, stay tuned for updates.

godotengine.org | Twitter

+1 vote

Hi All. I have a large 3d grid map in my level. I have a global function that captures translation of all cells of a specified type. I also have a grass clump node, which I spawn in all positions where I have a cell type: grass.
With bigger maps, this method takes forever to load all instances of grass clump (even though they are simple textured planes).

NEED:
I want to try multimesh instancing instead. I want a grass clump mesh spawned in all positions where there is a cell of the type: grass. All translations where I want those multimesh instances to spawn are stored in an array.

PROBLEM:
I do not know how tu use multimesh's set_instance_transform method to make that happen. Any tips appreciated!

in Engine by (513 points)
edited by

1 Answer

+1 vote

You want to do similar to the tutorial here https://docs.godotengine.org/en/stable/tutorials/3d/vertex_animation/animating_thousands_of_fish.html#making-a-school-of-fish

Note that when you set instance_count you effectively lock the multimesh, so do the setup first, set the number, and then set their positions.

E.g. script to be attached to a multimesh node

extends MultiMeshInstance

const HOW_MANY : int = 10

func _ready():
    multimesh = MultiMesh.new()
    multimesh.transform_format = MultiMesh.TRANSFORM_3D
    multimesh.mesh = $"../MY_MESH_INSTANCE".mesh.duplicate()
    multimesh.instance_count = HOW_MANY
    for i in range(HOW_MANY):
        # Set offset coordinates here. Replace Basis() if you need rotation too
        multimesh.set_instance_transform(i, Transform(Basis(), Vector3(0, 0, 0)))
by (396 points)

I know how to spawn instanced. That's not my question (I may have been imprecise).
The question is:
How do i manipulate set_instance_transform to have each instance spawn at a location that is stored in a separate array. So it's 2 separate arrays, one for multimesh instances (instance count), and one for 3d locations in the world. How do I pair them up?

Hello Macryc,

At this point you can just use the same index i over both arrays?

Supposing you have var positions : Array with size HOW_MANY and with each entry a Vector3, the final line would then be multimesh.set_instance_transform(i, Transform(Basis(), positions[i]))

Hey Tim, it worked!:)
Thanks. My next question is going to be: how do I remove an multimesh instance when the 'grass' cell is replaced with a different type. Definitely don't want to reload the whole thing each time...:)

While it might be considered a bit of a hack,

func remove_instance(var i : int):
    var t : Transform = multimesh.get_instance_transform(i)
    t.origin.y -= 1000
    multimesh.set_instance_transform(i, t)

is a valid way of doing this. I.e. just hide it deep, deep underground.

Awesome, I'll try that. Cheers.
BTW, do you happen to know how one should go about rotating each instance by 90 degrees on one of the axes? Trying to find this in the docs, no luck so far...

Manipulate the Basis in the Transform, this is where the rotation data is held (edit - typo)

var b := Basis()
b = b.rotated(Vector3.UP, deg2rad(90))
var t := Transform(b, positions[i])

thanks. I've played around with these and got it to work more or less the way I intended. Just to confirm though - there is not way to queue_free a multimesh instance, is there? As long as the number of instances has no bearing on performance, that's ok. It's just that I'm worried about having dozens or hundreds of instances buried underground and still impacting on performance. Or is this a silly thing to fear?

It's unavoidable, that's the trade off of using a MultiMesh. It's batching together one draw call to the GPU for all of your instances, as opposed to sending a single call per mesh.

As a consequence it can either send all of them, or none of them. The occluded ones will have some performance penalty, but it should be very small. MultiMesh is designed to scale to be drawing thousands of instances.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.