Need help with consistant rotation

Godot Version

Godot Engine v4.4.1.stable.arch_linux

Question

Hi, I am having an issue with rotations not behaving as I would like. For context I am creating a game based around manipulating a cube. I would like to be able to rotate the cube in the X, Y, and Z direction. However I would like these directions to operate in respect to a reference corner, (the corner held directly in view of the camera, but not actually using the camera as a reference point for this since I plan to add free cam and snap later on).

Basically, as I have it now. When I rotate along the Y axis, what direction the cube rotates about the X and Z axes changes, I do not want that. When I do an X rotation, I want the cube to always rotate horizontally away and to the left, when I do a Z rotation, I want the cube to rotate horizontally away and to the right. Currently the Y rotation already behaves as I would like, always rotating the cube vertically to the left, this never changes regardless of what X and Z rotations have come before.

I have tried multiple different methods and always end up with the exact same behavior. While Y works as I would expect, X is always a horizontal rotation, but could be to the left, right, forward or backward depending on what Y rotations have come before. And Z is the most strange as it can be a horizontal or vertical rotation to the left, right, forward or backward depending on what Y and X rotations have come before.

I have tried:

global_transform.basis = global_transform.basis.slerp(Basis.from_euler(new_rotation), 0.1)
transform.basis = transform.basis.slerp(Basis.from_euler(new_rotation), 0.1)
global_basis = global_basis.slerp(Basis.from_euler(new_rotation), 0.1)

all behave the exact same as the most naive implementation:

rotation = lerp(rotation, new_rotation, 0.1)

I have even tried reparenting what I want to rotate and rotating that instead, but it just does the same. The only thing I’ve tried that hasn’t is using global_rotation but I clearly don’t understand how to use that as it behaves similarly, only with the added chaos of completely glitching out after a few turns. I strongly feel the answer is somewhere in rotating a child object with respect to the parent axes but I have yet to find a way to do that.

If anyone understands what I’m trying to accomplish and knows how, please help!

UPDATE! I have solved my problem using quaternions. Not sure why I hadn’t been pointed in that direction from every thread I’ve looked at asking about similar problems. My final solution looks something like this:

if is_rotating:
		var current_quat: Quaternion = cubies.quaternion
		var interpolated_quat := current_quat.slerp(cube_rotation, 0.1)
		if interpolated_quat.angle_to(cubies.quaternion) < 0.0001:
			is_rotating = false
			interpolated_quat = cube_rotation
		cubies.quaternion = interpolated_quat

for preforming the actual rotation inside of _process() and

func preformCubeRotation(axis: Axis, dir: Dir) -> void:
	var rotation_amount: float = deg_to_rad(90)*dir
	var rotation_vector: Vector3 = Vector3.ZERO
	
	match axis:
		Axis.X:
			rotation_vector = Vector3(1, 0, 0)
		Axis.Y:
			rotation_vector = Vector3(0, 1, 0)
		Axis.Z:
			rotation_vector = Vector3(0, 0, 1)
		
	var quat = Quaternion(rotation_vector, rotation_amount)
	cube_rotation = (quat * cubies.quaternion).normalized()

for calculating the specific rotation.

is_rotating is updated in handled in a function called processMove(), currently I just block rotations from happening if the previous hasn’t finished, but will be creating a queue system for my input so inputs aren’t dropped.

I’d like to credit this video: https://www.youtube.com/watch?v=Ri2xIhcii8I
and the accompanying gitlab repo for being the thing to help me crack this solution.

I will likely never be using Euler angles to handle rotations ever again.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.