mardi 21 avril 2015

Using device orientation with 3D transforms

There is this project that wants to implement a cube that has sides for east/west/up/ground/north/south which are supposed to always point in the respective geolocations. The necessary data is gathered from the deviceorientation API:

Me and lots of other users were wondering why this app is not doing what it's supposed to do. (It's supposed to run on Firefox OS or on any Android device with Firefox.) Apart from the fact that the code seems to do a lot of unnecessary things and the coding style is a shame, I don't quite understand what he is doing there.

Then I discovered hints on how to do something similar on MDN:

Both approaches seem to be obviously wrong: They assume that you can simply invert the device orientation by just applying rotateX, rotateY and rotateZ in the right order.

But there's a clear definition of the angles (alpha, beta, gamma) that the deviceorientation event provides: And it says that the respective rotation axes are the axes of the rotated (device) frame. So you rotate by an angle alpha around the z-axis, then you rotate by an angle beta around the (now rotated!) x-axis, then you rotate by an angle gamma around the (now twice rotated!) y-axis.

Since for CSS transforms the reference frame is always the device frame, to invert these steps you would need to manually keep rotating the axis of rotation.

var b = e.beta,
    g = -e.gamma,
    a = e.alpha,
    axis_y = Array(0,1,0),
    axis_x = rotate(Array(1,0,0), axis_y, g),
    axis_z = rotate(rotate(Array(0,0,1), axis_y, g), axis_x, b);

Thus, the CSS transforms look like this:

document.getElementById("cube").style.transform =
    "rotate3d(" + axis_z[0] + ", " + axis_z[1] + ", " + axis_z[2] + ", " + a + "deg) " +
    "rotate3d(" + axis_x[0] + ", " + axis_x[1] + ", " + axis_x[2] + ", " + b + "deg) " +
    "rotate3d(" + axis_y[0] + ", " + axis_y[1] + ", " + axis_y[2] + ", " + g + "deg)";

Note that for the CSS transform function rotate3d "the rotation is clockwise as one looks from the end of the axis vector toward the origin" while for the provided alpha-beta-gamma "positive rotation around an axis is clockwise when viewed along the positive direction of the axis". Taking into account that the y axis for CSS transforms is pointing to the bottom of the screen we only have to invert the gamma angle in our context.

Here is my implementation of this:

My question is: Is this the right/best way of implementing this or is there a way to do it without rotating the axes of rotation multiple times?

Aucun commentaire:

Enregistrer un commentaire