0 votes

Hi,

So I have a tree mesh attached to my multimesh, and I have a exported variable to pick how many trees I run.

When my game runs, a landscape mesh is generated and positions to place trees are picked by raycasting random positions over the mesh. After I have the positions, I loop over the instances in my mesh and translate the trees to the appropriate position.

Now, I want to add a random rotation to my trees so that they son't all look the same.

This is my multimesh code:

extends MultiMeshInstance

export(int) var treeScale = 5

func _ready():
    self.scale = Vector3(treeScale, treeScale, treeScale)



func updatePositions(posArray):
    print("Update tree positions")
    for i in self.multimesh.instance_count:

        var position = posArray[i]
        position.y -= 2
        position /= treeScale

        var rotation = rand_range(0, PI * 2)        
        var transformation = Transform(Basis(), position)
        self.multimesh.set_instance_transform(i, transformation)

I have been messing around with transformation.rotated but sometimes it rotates the trees off of my mesh.

How should I implement rotation?

Thanks.

in Engine by (49 points)

1 Answer

+1 vote
Best answer

Hi,
the easiest way to rotate around the up-axis is rotate_y( radiants )

rotate_y( rand_range(0, PI * 2) )

https://docs.godotengine.org/en/stable/classes/class_spatial.html#class-spatial-method-rotate-y

by (2,470 points)
selected by

How would I use rotate_y in this case? I cannot apply it to the transform, and I can't apply it to the position vector I am moving the trees to. If I could get the actual instances of the trees perhaps I could apply it to them, but I'm not sure how to do that.

I could do rotate_y on the multimesh node, but that would rotate the entire plane of trees.

As far as I know I have to use the .rotated() function on my transform.

I can do

transformation.rotated(Vector3(0, 1, 0), rand_range(0, PI * 2))

but this makes some of my trees rotate off of my terrain mesh.

In the meantime I have abandoned the multimesh in my actual project and I am just instancing new tree scenes and placing them at the coordinates, this allows me to use the rotate_y function, but I thought using a multimesh would be better for performance.

You would use it on multiMeshInstance wich is a decendand of spatial that implements the method rotate_y

Is there any way I can rotate individual instances of trees in my multimesh?

If I just rotate the whole multimesh then some of the trees will end up rotating off of my terrain - I want to apply a randomized individual rotation to each tree.

Ok, got it now.
You have to set transform_format of your MultiMeshInstance to 3D (you can only do so if the instance count is zero, so put it back to zero make it 3D then set the count back to your value).
Here is a litle script that rotates and places the instances randomly on startup:

func _ready():
    for i in range(multimesh.instance_count):
        var transform = Transform()
        transform = transform.translated(Vector3(rand_range(-5,5), 0, rand_range(-5,5)))
        transform = transform.rotated(Vector3.UP,rand_range(0,PI * 2))
        multimesh.set_instance_transform(i, transform)

make sure your trees have there pivot right in the middle bottom of the mesh

There is although a tool to populate a surface with instances .. read about it here:
https://docs.godotengine.org/en/stable/tutorials/3d/using_multi_mesh_instance.html#doc-using-multi-mesh-instance

So when I use rotate like that I still end up with trees being rotated off of the map for some reason.

extends MultiMeshInstance

export(int) var treeScale = 6

func _ready():
    self.scale = Vector3(treeScale, treeScale, treeScale)

func updatePositions(posArray):
    print("Update tree positions")
    for i in self.multimesh.instance_count:
        var pos = posArray[i]
        pos.y -= 6
        pos /= treeScale


        var transformation = Transform()
        transformation = transformation.translated(pos)
        transformation = transformation.rotated(Vector3.UP, rand_range(0, PI*2))
        multimesh.set_instance_transform(i, transformation)

With rotation in I get trees like this that go off the map: https://imgur.com/ozyr8sU

With rotation commented out I get trees that stay on the map: https://imgur.com/vZAdd44

Any ideas on how to fix this?

Is the pivot of the tree is in the exact center of the tree?

I believe it is. I get the same behavior when I replace the tree mesh with a new cube mesh that is definitely positioned properly as well.

I get my desired behavior (i think), when I use this:

extends MultiMeshInstance

export(int) var treeScale = 6

func _ready():
    self.scale = Vector3(treeScale, treeScale, treeScale)

func updatePositions(posArray):
    print("Update tree positions")
    for i in self.multimesh.instance_count:
        var pos = posArray[i]
        pos /= treeScale

        var b = transform.basis.rotated(Vector3.UP, rand_range(0, PI*2))
        var t = Transform(b, pos)
        multimesh.set_instance_transform(i, t)

Not sure why this works but the other doesn't.

okay, i messed it up ... but now

first rotate then reposition

func _ready():
    for i in range(multimesh.instance_count):
        var transform = Transform()

        transform = transform.rotated(Vector3.UP,rand_range(0,PI * 2))
        transform.origin = Vector3(rand_range(-4.8,4.8),0,rand_range(-4.8,4.8))
        multimesh.set_instance_transform(i, transform)
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 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 webmaster@godotengine.org with your username.