I'm currently working with Oculus integration trying to export headset (and eventually controller) position and rotation data to a CSV for later use in Blender. My issue comes from the way Unity (or Blender) handles rotations. In Unity, 0 = 360
, whereas in Blender 0 != 360
.
My current solution is to grab the current rotation and subtract it from the rotation in the frame before. I then combine the difference with a running sum (Vector3 for x, y, and z sums). If any sum is greater than 360, I add a rotation to a separate Vector3 that tracks the number of complete rotations for each axis. I subtract rotations for sums less than -360. This way I can calculate the final rotation (x for example) using 360*numRots.x + xrot
to get the overall rotation.
Unfortunately my code doesn't properly store the running total correctly; it always matches the current rotation. For example, if I run the program, the current rotation might be (270, 23, -9)
and the running total SHOULD be (0, 0, 0)
(plus or minus some degrees) but the running total always matches the current rotation.
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System;
public class Mocap : MonoBehaviour
{
public GameObject cam;
static string path = "Assets/test.txt";
StreamWriter writer;
private Vector3 rotationSum; // running sums of x, y, z rotations
private Vector3 numRots; // total number of rotations per axis
private Vector3 prevRot; // previous rotation values
void Start()
{
writer = new StreamWriter(path, append: false);
rotationSum = new Vector3(0, 0, 0);
numRots = new Vector3(0, 0, 0);
}
void Update()
{
// get camera pos and rot
double xpos = cam.transform.position.x;
double ypos = cam.transform.position.y;
double zpos = cam.transform.position.z;
float xrot = cam.transform.rotation.eulerAngles.x;
float yrot = cam.transform.rotation.eulerAngles.y;
float zrot = cam.transform.rotation.eulerAngles.z;
Vector3 curr = new Vector3(xrot, yrot, zrot);
Vector3 tempDiff = curr - prevRot;
rotationSum += tempDiff;
// check x
if(rotationSum.x >= 360)
{
rotationSum.x -= 360;
numRots.x += 1;
} else if(rotationSum.x <= -360)
{
rotationSum.x += 360;
numRots.x -= 1;
}
// check y
if (rotationSum.y >= 360)
{
rotationSum.y -= 360;
numRots.y += 1;
}
else if (rotationSum.y <= -360)
{
rotationSum.y += 360;
numRots.y -= 1;
}
// check z
if (rotationSum.z >= 360)
{
rotationSum.z -= 360;
numRots.z += 1;
}
else if (rotationSum.z <= -360)
{
rotationSum.z += 360;
numRots.z -= 1;
}
// final rotation
xrot = 360 * numRots.x + xrot;
yrot = 360 * numRots.y + yrot;
zrot = 360 * numRots.z + zrot;
// update previous values
prevRot = curr;
string filetext = xpos + ", " + ypos + ", " + zpos + ", " + xrot + ", " + yrot + ", " + zrot;
this.writer.WriteLine(filetext);
}
}
EDIT
I have converted the code to use Quaternions I believe. I display in Euler angles for convenience. The next problem I'm facing is when the calculating the difference between the current and previous rotation and when the rotation jumps from 0-360 or 360-0. If curr=5
and prev=355
, the difference is -350 which correctly gets added to the running sum but this still acts as if I rotated through 355 down to 5 rather than looping at 360 to 0 then to 5. My current thinking to fix this is check if the difference is more than say 300. If so, that mean I either a) rotated my head 300 degrees in 1/24th second or b) I looped and should add a rotation to the axis. Advice is appreciated.
Also the reason I have to wait is because the headset rotation is set to (0,0,0) until it loads so I just wait until it doesn't equal (0,0,0).
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class mocapv2 : MonoBehaviour
{
// misc objects
public GameObject cam;
public Text uitext;
private bool onecheck;
// quaternion stuff
private Quaternion previous, sum;
void Start()
{
previous = sum = Quaternion.identity;
this.onecheck = true;
}
private IEnumerator waitasec()
{
yield return new WaitForSeconds(.1f);
}
void Update()
{
// wait for updated headset rotation
if(this.onecheck)
{
this.previous = cam.transform.rotation;
if(this.previous == Quaternion.identity)
{
StartCoroutine(waitasec());
} else
{
this.onecheck = false;
}
}
if(!this.onecheck)
{
Quaternion curr = cam.transform.rotation;
Quaternion difference = curr * Quaternion.Inverse(this.previous);
this.sum *= difference;
string text = "curr:" + curr.eulerAngles + "\ndiff:" + difference.eulerAngles + "\nprev:" + this.previous.eulerAngles + "\nsum:" + this.sum.eulerAngles;
uitext.text = text;
this.previous = curr;
}
}
}
```