Problem With Rotation Using Physics Based Object Grabbing
Asked Answered
S

1

0

I've been pulling my hair out finding why some code I have for a physics based approach to moving and rotating held objects based on the location and orientation of the player's hand in VR.

I believe the problem stems from something to do with the way Godot XR Tools handles hand rotation.

In the video below, the only important code is lines 37 and 38:
print("vector check")
print(HandMesh.global_rotation_degrees)

All I'm doing is getting the rotation of the handmesh (I also tried getting the rotation directly from the controller node itself) and printing it out.

In the video, you can see me rotating me hand to first test the z axis, then the y axis, and finally the x axis. The z and y axes work perfectly fine, ranging from -180 to 180 degrees. But then, when I print the x axis, we only see it printing from -90 to 90 degrees. When I rotate my controller past the point where the fingers are pointing straight up, the x rotation vector starts decreasing.

I believe this may be because, once the hand crosses this point of my fingers pointing straight up, Godot XR Tools represents that as the hand facing forwards but pointed slightly upwards, then rotated around the y and z axes 180 degrees, so the x axis will never actually surpass -90 to 90 degrees.

This normally wouldn't be a problem, except that I'm trying to add rotational force so that the grabbed object rotates with the hand, using the following code:
if(held_object_body):
held_object_body.linear_velocity = (global_position - held_object_point.global_position) * translational_strength * delta
held_object_body.angular_velocity = vector_angle_difference(global_rotation_degrees, held_object_body.global_rotation_degrees) * rotational_strength * delta

func vector_angle_difference(vector1: Vector3, vector2: Vector3) -> Vector3: # input 2 Vector3s of angles
var diff_x = rad_to_deg(angle_difference(deg_to_rad(vector2.x), deg_to_rad(vector1.x)))
var diff_y = rad_to_deg(angle_difference(deg_to_rad(vector2.y), deg_to_rad(vector1.y)))
var diff_z = rad_to_deg(angle_difference(deg_to_rad(vector2.z), deg_to_rad(vector1.z)))
return Vector3(diff_x, diff_y, diff_z)

So, because of this, once my hand faces in the opposite direction so that my fingertips cross that 90 degree threshold, the object I'm holding starts spinning in random directions VIOLENTLY. I believe that's due the the fact that we suddenly apply 180 degree velocities to 2 axes, but even if I slowed this down, it wouldn't fix the fact that the object shouldn't have to spin around in the first place, just because the hand crosses the x threshold I mentioned earlier.

Does anyone have any ideas to fix this? I really don't want to give up the physics based movement since I like the way it feels over simply locking objects to the player's hands, and I also have some cool ideas I want to implement with this later, something similar to Boneworks style interactions. I am open to ideas though.

video:

Shipowner answered 19/12, 2023 at 2:37 Comment(0)
S
0

Problem Solved:

func vector_angle_difference_from_quaternions(quat1: Quaternion, quat2: Quaternion) -> Vector3: 
	var diff =  quat1 * quat2.inverse()
	diff = diff.normalized().get_euler()
	return Vector3(diff.x, diff.y, diff.z)
  • in my case, the hand is quat 1 and the target object is quat 2.

We use quaternions here because there can only be 1 quaternion to represent a certain rotation. Euler angles were causing problems for the reasons I outlined in the original post:

Shipowner I believe this may be because, once the hand crosses this point of my fingers pointing straight up, Godot XR Tools represents that as the hand facing forwards but pointed slightly upwards, then rotated around the y and z axes 180 degrees, so the x axis will never actually surpass -90 to 90 degrees.

This is easily avoided with quaternions, and seems to work perfectly in my case. I'm simply using the provided function to return the difference as a Vector3 and applying them to the object with:
object.angular_velocity = vector_angle_difference_from_quaternions(quaternion, object.quaternion) * rotational_strength * delta
where "quaternion" by itself is my hand's quaternion, and rotational_strength is a number which needs to be set pretty high for a noticeable effect (for reference, I have my rotational_strength set to 500).

If anything I've posted is confusing, wrong, or simply doesn't work, please let me know.

Shipowner answered 20/1 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.