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; } } } ```