• 3D
  • Pointing towards mouse cursor

I am currently converting a 2D game to 3D from gamemaker. One thing I struggled with is getting objects to point towards the mouse. From my understanding, you must use raycasting for 3D mouse pointing. It is fine when I use the look_at function like this: KinematicBodyNode.look_at(cursor_pos, Vector3.DOWN)

But the disadvantage to this code is that it rotates the CollisionShape because it is a child of the KinematicBodyNode. So what I decided to do was to use the function like this (because I only want to rotate the mesh that is a child of KinematicBody): MeshInstanceNode.look_at(cursor_pos, Vector3.DOWN)

This now no longer rotates the CollisionShape node but the MeshInstance now which is what I want. But the problem is now that I only want it to rotate by the y axis (because it is meant to be a flat sprite with x axis rotated at 90 degrees so that it is lying on the ground).

I found a quick hack to prevent this problem (by setting the rotation x back to -90 after using 'look_at'). This is works exactly how I want it to except how do I do this the non-hacky way.

This is how I (kind of) got it to work: MeshInstanceNode.look_at(cursor_pos, Vector3.DOWN) MeshInstanceNode.set_rotation(Vector3(-90, MeshInstanceNode.get_rotation().y + 90, 0))

But it still has problems like a slight unwanted rotation and the rotation is a bit off but the closest I have managed to getting it to work like when I was just getting its parent (KinematicBodyNode) to rotate.

But why does this code not work the same? It doesn't seem to put the correct value in the angle variable but surely this should be the equivilent to the angle which 'look_at' provides: var angle = cursor_pos.angle_to( MeshInstanceNode.global_transform.origin) var mesh_rot = MeshInstanceNode.get_rotation() mesh_rot.y = angle MeshInstanceNode.set_rotation(mesh_rot)

Another question:

Is there a better way I could place meshs into my level (were I do not even have to set the rotation y to -90). Like say if I imported from Blender? Or is that too much work? I just thought it might make more sense if it looked like a flat sprite on the floor with rotation values all at 0, 0, 0.

Also (the code above shows me having to offset the y rotation by 90 degrees (I guess I could make it so the sprite texture is 90 degrees to the right but is there not a better way to rotate this in the editor without having to hardcode the offset rotation).

Thanks

Sometimes I just rotate in blender into the y up position, so it's on it's side in Blender. I do this after I finish animating and whatever else, and set the scale to 1 first before exporting. Sometimes I set the export settings, but then it comes in rotated 90 on the y. Depends if it matters. The way I use lookat is look_at(Vector3(mousePos.x, meshPos.y, mousePos.z)) if I want it to rotate on the y.

@fire7side said: Sometimes I just rotate in blender into the y up position, so it's on it's side in Blender. I do this after I finish animating and whatever else, and set the scale to 1 first before exporting. Sometimes I set the export settings, but then it comes in rotated 90 on the y. Depends if it matters. The way I use lookat is look_at(Vector3(mousePos.x, meshPos.y, mousePos.z)) if I want it to rotate on the y.

It still has a wierd bug were the mesh slightly rotates from the wrong axis.

That would probably be because it not oriented right in it's own scene or when it was imported. You'll have to fix it there. It has to be rotating on it's own y axis. If it's parented, that might make it look funny, maybe check if you can rotate it globally. It just depends on your situation, but it will rotate on it's own y axis. That y may be parented so it looks funny in local space. That may be what's throwing it off, but if you make sure it's transform is the same as it's parent, and the parent is global, it should work.

@fire7side said: That would probably be because it not oriented right in it's own scene or when it was imported. You'll have to fix it there. It has to be rotating on it's own y axis. If it's parented, that might make it look funny, maybe check if you can rotate it globally. It just depends on your situation, but it will rotate on it's own y axis. That y may be parented so it looks funny in local space. That may be what's throwing it off, but if you make sure it's transform is the same as it's parent, and the parent is global, it should work.

I think the reason it is not working is only to do with the code.

I tried setting the global_transform like this. Sorry I am new to godot but from my understanding, you can manipulate the basis.x vector to change the direction the player is facing. I tried altering this (to use global_transform) and it just gives me a bunch of random scaling but not close to what I am looking for.

# Just gives random scaling issues (seems like basis is meant to deal with position, scale and rotation)
var angle = (MeshInstanceNode.transform.origin - cursor_pos).normalized()
var mesh_rot = MeshInstanceNode.transform.basis.x
mesh_rot.y = angle.y
MeshInstanceNode.transform.basis.x = mesh_rot

This code (BELOW) seems much closer to what I am trying to achieve but I still cannot work out how to get the angle to be correct. I have tried using the 'angle_to' function and found a method that I hope I am getting right but I seem to prefer (minus one point from another point and normalizing it, to get the direction).

# Closer to what I am trying to achieve than code above
var angle = (MeshInstanceNode.transform.origin - cursor_pos).normalized()
var mesh_rot = MeshInstanceNode.get_rotation()
mesh_rot.y = angle.y
MeshInstanceNode.set_rotation(mesh_rot)

Even looking at tutorials, I am still confused as to how the transform.basis works.

If you could manipulate that code above to work like the code below (explaining it) and link me to a good place to learn about things like what basis is and how it works. I will feel less baffled.

# Perfect for what I am trying to achieve but why won't that code above work the same
MeshInstanceNode.look_at(cursor_pos, Vector3.DOWN)

Thankyou!

Reformatted your post a bit, not sure if it's exactly how you intended it but I recon it makes it a bit easier to read. ;)

@fire7side said: You are just going to check the docs and figure it out. I don't know what you are doing exactly. https://docs.godotengine.org/en/stable/tutorials/3d/using_transforms.html

Idk if this is just my shortcomings of being able to understand the documentation or if it should explain a bit more. But I do not understand the difference between rotating relative to parent transform and rotating relative to local space. Like does it mean, it is rotating around the perant's origin point or does it add a rotation amount as if it was at the rotation of the parent? I tried experimenting in code and cannot see any difference in how they work.

I am a visual learner so if I could actually see the difference in action, I would find it much easier to read and understand the documentation.

rotate vs rotate_object_local

The simplest way is set up a very basic example project and just play around with it till you get it figured out.

local is indeed 'local' to the transformed object itself, whilst global is 'local' to the space itself. and parent is 'local' to the parent objects transform(location, rotation and scale). Global, position 0, 0(, 0 if 3d so extra axis) is world origin. Local, position 0, 0 ... is objects own origin. Parent space, position 0, 0 ... is parents origin.

Nice little explanation. I think what mostly throws people off is that the scale of the parent affects the children. That's why it's best not to mess with it and make sure it's always at 1. Change the size, not the scale.

I'm not sure how much it will help, but here's the code that gets called on a Basis when calling the look_at function: Basis looking_at function. I would try to explain it, but I only have a vague idea of how it works myself and I'm pretty sure I would mess up any explanation I try to give due to my lack of understanding. :lol:

If you want to use look_at for rotating around a single axis, one thing you can do is simply set the target to be on the same plane as whatever axis you want to rotate around. For example, if you want to only rotate around the Y axis:

var target_pos = cursor_pos
target_pos.y = MeshInstanceNode.global_transform.origin.y
MeshInstanceNode.look_at(target_pos, Vector3.DOWN)

I've used this a few times and it seems to work well :smile: