Godot Version
4.3
Question
how would I go about aligning an object’s y axis witha given normal through code? I’m completely lost in terms of rotation math
4.3
how would I go about aligning an object’s y axis witha given normal through code? I’m completely lost in terms of rotation math
This is the code I’m working with rn:
func align_with_normal(object_to_rotate: Node3D, normal: Vector3):
var b = Basis()
var forward = basis.y
b = b.rotated(basis.x, forward.angle_to(normal))
object_to_rotate.transform = Transform3D(basis, object_to_rotate.transform.origin)
not certain why it’s not doing what I want as of right now
Here’s my hacky way that should achieve what you want.
func align_with_normal(object_to_rotate: Node3D, normal: Vector3):
object_to_rotate.global_transform = object_to_rotate.global_transform.looking_at(object_to_rotate.global_position + normal)
object_to_rotate.global_transform = object_to_rotate.global_transform.rotated(object_to_rotate.global_basis * Vector3.LEFT, PI / 2)
In the first line, we’re using looking_at() to rotate the Z axis towards the normal.
In the second line, we’re rotating the object 90 degrees forward to have it face Y axis towards the normal.
There has to be a better and cleaner way to do it, but that’s what first came to my mind and I don’t see any better way myself.
hey, thanks a ton. it seems to be teleporting the object a pretty significant distance though, any idea why that might be?
Ah, I didn’t test it outside of the origin position. Moving outside of origin indeed teleports it around.
Here’s ChatGPT’s solution, that seems to work better, if you don’t mind the LLM:
func align_with_normal(object_to_rotate: Node3D, normal: Vector3):
var y = normal.normalized()
var x = y.cross(Vector3.FORWARD).normalized()
if x.length() == 0:
x = y.cross(Vector3.RIGHT).normalized()
var z = x.cross(y).normalized()
object_to_rotate.global_transform = Transform3D(Basis(x, y, z), object_to_rotate.global_position)
it seems like it’s putting the y axis perpendicular to the normal rather than parallel, is there something I might be missing?
You can use the arc from → to quaternion constructor
object_to_rotate.quaternion = Quaternion(Vector3.UP, normal)
this seems way closer, but it’s placing the object at an angle to the normal. to clarify: the object’s y axis should be parallel to the normal. this seems to be part of the solution but not quite the whole
This should be parallel to the normal, can you screenshot what you are seeing and what you expect?
in the first screenshot here, the Red Cross in the center of the screen is the intersection of the dome and cylinder parts of a capsule collider(intended object to rotate), representing the player. a raycast is fired from the middle of the view, selecting a face(outlined in yellow)
in the second screenshot you can see the resulting rotation of the capsule collider . the outlined face is the initially selected face. as indicated by the camera orientation, the capsule collider is not parallel with the normal of this face
this final screenshot shows the “bottom” of the capsule collider in relation to the yellow outline.
essentially I’d like to take the normal of the selected face, align the player with it, and treat that as the gravity direction for the player, like magnet boots in space.
here is my current implementation of this idea:
func detect_magnetized():
if Input.is_action_just_pressed("Magnetize"):
if !magnetized:#check if you are currently magnetized or free floating
if eyes_cast.get_collider()
grav_normal = eyes_cast.get_collision_normal()#sample normal of colllision point of raycast
self.quaternion = Quaternion(Vector3.UP, grav_normal)#given code, thank you for your help btw
axis_lock_angular_x = true
axis_lock_angular_y = true
axis_lock_angular_z = true
magnetized = true
else:
magnetized = false
body.rotation = camera.global_rotation
head.rotation = Vector3.ZERO
camera.rotation = Vector3.ZERO
Sadly I’m not getting it, maybe your expecting the camera to have rotated too, but you are only setting the self.quaternion which I presume is the player (CharacterBody3D?) and the camera is a child or grand-child of it so the cameras rotation will be offset because it inherits from the parents. Maybe reset the camera and it’s parent’s rotation during this operation?
self.quaternion = Quaternion(Vector3.UP, grav_normal)
camera.rotation = Vector3.ZERO
head.rotation = Vector3.ZERO
I ended up just rotating the collider 90 degrees and using “lookat” with the parent rigidbody so it would orient the colider correctly.
fyi I pulled this from another discussion, lost the link
var old = transform.basis
look_at(global_position + grav_normal, Vector3.UP)
var new = transform.basis
transform.basis = lerp(old, new, .1)
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.