I 've currently tried to refactor some of my old device rotation code, where I read in the device rotation and turn those into the gyro rotation of the camera entity.

The main calculation looks like this (unfortunatly I don’t know where I took the code from)

var x = this.do ? pc.math.DEG_TO_RAD * this.do.beta : 0;
var y = this.do ? pc.math.DEG_TO_RAD * (this.do.alpha + this.alphaOffset) : 0;
var z = this.do ? pc.math.DEG_TO_RAD * -this.do.gamma : 0;
var w = this.so ? pc.math.DEG_TO_RAD * this.so : 0;
var c1 = Math.cos( x / 2 );
var c2 = Math.cos( y / 2 );
var c3 = Math.cos( z / 2 );
var s1 = Math.sin( x / 2 );
var s2 = Math.sin( y / 2 );
var s3 = Math.sin( z / 2 );
var q0 = new pc.Quat(
s1 * c2 * c3 + c1 * s2 * s3,
c1 * s2 * c3 - s1 * c2 * s3,
c1 * c2 * s3 - s1 * s2 * c3,
c1 * c2 * c3 + s1 * s2 * s3
);
var q1 = new pc.Quat(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); // - PI/2 around the x-axis
q0.mul(q1);
var q2 = new pc.Quat();
q2.setFromAxisAngle(pc.Vec3.FORWARD, this.so);
q0.mul(q2);
this.entity.setRotation(q0);

I’ve tried to replace this working solution with the Quat.setFromEulerAngles Method, but ran into weird behaviour. Is this calculatio above a different way of calculation (which maybe avoids gimbal lock or else) or should It be possible to replace this calculation with some Quat-Method.

Thanks @yaustar for your info. I’ve looked into the gyronorm library a while ago, maybe I will give it a try.

I would have thought using the alpha/beta/gamma as XYZ would have been fine.

As a followup question on this (as 3d rotations always mangle up my mind)
I assume the alpha, beta, gamma rotations of the device are local rotations?
But aren’t the xyz of the quat.setFromEulerAngles() to be understood as global rotations?
Could that be an issue, or do I misunderstand the inner workings of the quaternion?

It’s irrelevant as you can a quat representing a global or a local rotation. The quat is going to be a representation of the euler angles you give it. If you give it local euler angles, you will have a quat representing a local rotation.

AFAIK, the only issue you will have is rotating the phone landscape so you will need to compensate for that somehow.

It’s irrelevant as you can a quat representing a global or a local rotation. The quat is going to be a representation of the euler angles you give it. If you give it local euler angles, you will have a quat representing a local rotation.

Just to wrap it up (thank you very much for explaining that):
The quaternion itself is only a different form representing a rotation (like 3 euler angels or transform matrix). But the way it is applied actually determines the kind of rotation (local vs. global):
entity.setLocalRotation(q) vs. entity.setRotation(q);

And (hopefully) my last question (again thanks): The advantage of quaternions (in this case) is that the the quaternion prevents the gimbal lock, which could be happening if used setLocalEulerAngles() directly with alpha, beta, gamma.

Generally yes. It also makes things like (s)lerping between rotations easier as you don’t have to deal with wrapping around the 360/0 boundary.

Outside of PlayCanvas, it can also be more performant on some hardware like consoles as you have a 4 value vector representing a rotation instead of a 3x3 transform matrix. Less storage in memory needed too.