0

I have a number of gyroscopes(in real life) attached to my body on my arms, legs, head and spine. Each gyroscope has a unique id, which I map to a body part on the 3d model.

The gyroscope data for each sensor is a quaternion.

I basically just want to animate my 3d model based on this data.

So if I rotate my head to the right, the 3d model should rotate its head similarly. If I stand on one leg, the 3d model should do the same.

When using 2d physics engines like Box2d, this is as simple as applying a transform. What is the equivalent way to do this in Unity ?

EDIT: In Godot its really simple.

https://docs.godotengine.org/en/3.0/tutorials/3d/working_with_3d_skeletons.html

extends Spatial
var skel
var id

func _ready():
    skel = get_node("skel")
    id = skel.find_bone("upperarm")
    print("bone id:", id)
    var parent = skel.get_bone_parent(id)
    print("bone parent id:", id)
    var t = skel.get_bone_pose(id)
    print("bone transform: ", t)
    set_process(true)

func _process(delta):
    var t = skel.get_bone_pose(id)
    t = t.rotated(Vector3(0.0, 1.0, 0.0), 0.1 * delta)
    skel.set_bone_pose(id, t)
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
Rahul Iyer
  • 19,924
  • 21
  • 96
  • 190
  • It's hard to tell exactly what you would need to do from the broad description in the question, but a good place to start could be setting `transform.eulerAngles = new Vector3(triplet.x, triplet.y, triplet.z);` on the `GameObject` representing the object the gyroscope is on. – Ruzihm Sep 06 '19 at 22:57
  • @Ruzhim - Since all bones are connected, does that mean I need to create a game object for each bone in a skeleton ? This seems like the kind of thing there would already be a solution for. Take a look at this link: https://hackaday.com/2016/01/23/amazing-imu-based-motion-capture-suit-turns-you-into-a-cartoon/ The code he uses in the python script to access the blender api is really simple. I'm trying to figure out the equivalent in Unity. – Rahul Iyer Sep 08 '19 at 07:26
  • @Ruzihm If you see the Godot example I've posted, it may be clearer what I am trying to achieve. – Rahul Iyer Sep 08 '19 at 07:41
  • looking at the arduino code, it collects **quaternions**, *not* the euler angles or axis/angle state of each gyroscope. I'm editing the question to reflect that. – Ruzihm Sep 08 '19 at 17:03

1 Answers1

1

In Unity, you can apply a quaternion rotation to a transform (overwriting its previous rotation) like this:

float quatX,quatY,quatZ,quatW;

Quaternion quat = new Quaternion(quatX,quatY,quatZ,quatW);
transform.rotation = quat;

If the problem then is that your arduino outputs right-handed quaternions, and that you need to convert them to the left-handed quaternions that unity uses, then this answer by stackexchange user DMGregory by may help you make the conversion in Unity:

A quaternion can be thought of as an angle-axis representation:

quaternion.xyz = sin(angle/2) * axis.xyz
quaternion.w = cos(angle/2)

So, converting them between two coordinate systems can be broken down into two steps:

  1. Map the axis into the new coordinate system.
  2. If changing between left & right hand coordinates (eg. if there's an odd number of axis negations or axis exchanges between the two), negate the angle.

    Since cos(-angle) = cos(angle) and sin(-angle) = -sin(angle) this is the same as flipping the axis of rotation, negating the x, y, and z parts.

Taking your specific example:

         sensor   unity
forward    x        z
up         z        y
right     -y        x

We can combine these steps into:

Quaternion ConvertToUnity(Quaternion input) {
    return new Quaternion(
         input.y,   // -(  right = -left  )
        -input.z,   // -(     up =  up     )
        -input.x,   // -(forward =  forward)
         input.w
    );
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48