Getting vertical device forward/up vectors from flat device euler angles

128 Views Asked by At

I am using Resonance Audio (spatial audio sdk) and trying to orient the listener based on device orientation.

Resonance has the methods setListenerOrientation(forward.x, forward.y, forward.z, up.x, up.y, up.z) taking two vectors, and also setListenerFromMatrix(matrix4). I would also like -z to be forward when the user is holding the device vertically, whereas the DOM api gives -z as forward when the device is flat.

Previously, I also had a 3d environment from three.js and I simply used this code:

this.cameraMatrix4 = cameraEl.object3D.matrixWorld;
this.resonanceAudioScene.setListenerFromMatrix(this.cameraMatrix4);

However now I am doing a version without 3d visualization, so I don't have something convenient like this. I have tried various things using quaternions and Matrix4s inspired by three.js DeviceOrientationControls, but didn't have much luck.

I also tried the following:

function updateListener(e: DeviceOrientationEvent) {
  const alpha = e.alpha ? (e.alpha / 180) * Math.PI + alphaOffset : 0; // Z
  const beta = e.beta ? (e.beta / 180) * Math.PI : 0; // X'
  const gamma = e.gamma ? (e.gamma / 180) * Math.PI : 0; // Y''
  euler.set(beta, gamma, alpha, "ZXY");
  forward.set(0, 0, -1).applyEuler(euler);
  up.set(0, 1, 0).applyEuler(euler);
  resonanceAudioScene.setListenerOrientation(forward.x, forward.y, forward.z, up.x, up.y, up.z);
}

However, it doesn't even seem like it's behaving correctly in the flat orientation. I have tried a few variations on the euler order, but I'm fumbling in the dark a bit because I don't understand the 3d maths, so I appreciate any help :)

1

There are 1 best solutions below

0
On

Thanks to looking @Marquizzo 's gimbal utility and also realizing that the initial Z direction is not consistent (which was preventing me from debugging effectively), I came up with this (including a bit to set the initial direction as the origin):

  //YZX order so we can apply the Y rotation for initial direction compensation
  //and then the offset for vertical device in the X axis last.
  const eulerOrigin = new Euler(Math.PI / 2, 0, 0, "YZX");

  //...

  const alpha = e.alpha ? e.alpha * degtorad + alphaOffset : 0; // Z
  const beta = e.beta ? e.beta * degtorad : 0; // X'
  const gamma = e.gamma ? e.gamma * degtorad : 0; // Y''
  quaternion.setFromEuler(eulerOrigin);
  q0.setFromAxisAngle(zAxis, alpha);
  quaternion.multiply(q0);
  q0.setFromAxisAngle(xAxis, beta);
  quaternion.multiply(q0);
  q0.setFromAxisAngle(yAxis, gamma);
  quaternion.multiply(q0);

  up.copy(upAxis).applyQuaternion(quaternion);
  forward.copy(forwardAxis).applyQuaternion(quaternion);

  if (!initialDirection) {
    initialDirection = new Vector3().projectOnPlane(upAxis).normalize();
    const angle = initialDirection.angleTo(forwardAxis);
    eulerOrigin.y = angle;
  }

  resonanceAudioScene.setListenerOrientation(forward.x, forward.y, forward.z, up.x, up.y, up.z);