LibGDX camera rotation does not work on Android

96 Views Asked by At

I have the orientation values from Android device RotationVector sensor expressed in degress as Yaw, Pitch and Roll angles. I want to continuously update the LibGDX Perspective camera rotation based on these orientation values. My goal is to build a 3D compass.

In the render() method I am trying:

@Override
public void render() {
    ScreenUtils.clear(Color.BLACK, true);

    // do some rendering
    modelBatch.begin(cam);
    modelBatch.render(instance, lights);
    modelBatch.end();
    
    // calculate/get the orientation angles
    float Yaw = ...;
    float Pitch = ...;
    float Roll = ...;

    // update camera orientation
    cam.view.setFromEulerAngles(Yaw, Pitch, Roll);
    cam.update();
}

I see the continuously changing Yaw/Pitch/Roll values in the logcat on the Android device orientation change, but unfortunately my model (the 3D compass) does not rotate. What is wrong with the above code? Why the camera rotation does not work?

2

There are 2 best solutions below

0
Ladislav On BEST ANSWER

Thanks to @bornander I ended up with the below perfectly working code:

@Override
public void render() {
    // clear screen
    ScreenUtils.clear(Color.BLACK, true);
    
    // do some rendering
    modelBatch.begin(cam);
    modelBatch.render(instance, lights);
    modelBatch.end();

    // calculate Azimuth (Yaw), Pitch and Roll angles (in degress)
    float Azimuth = ...
    float Pitch = ...
    float Roll = ...

    // Transform the Forward vector (Vector3.Z) using a quaternion got from Azimuth/Pitch angles to a LookAt vector
    Quaternion rotCam = new Quaternion().setEulerAngles(Azimuth, Pitch, 0);
    Vector3 newDir = new Vector3(Vector3.Z).mul(rotCam).nor();
    cam.lookAt(newDir);

    // Transform the camera UP vector (Vector3.Y) using a quaternion got from previous LookAt vector and Roll angle
    Quaternion rotUp = new Quaternion(newDir, Roll);
    Vector3 newUp = new Vector3(Vector3.Y).mul(rotUp).nor();
    cam.up.set(newUp);

    // apply the above changes on camera
    cam.update();
}
9
bornander On

This is because you cannot update the view of a PerspectiveCamera directly as it will be overwritten by the call to update.

You control a PerspectiveCamera by modifying the position and the direction (or look-at target).

You need to calculate a new direction based on your roll, yaw and pitch and then set that on the camera.

For reference, this is the implementation of update in PerspectiveCamera:

public void update(boolean updateFrustum) {
    float aspect = this.viewportWidth / this.viewportHeight;
    this.projection.setToProjection(Math.abs(this.near), Math.abs(this.far), this.fieldOfView, aspect);
    this.view.setToLookAt(this.position, this.tmp.set(this.position).add(this.direction), this.up);
    this.combined.set(this.projection);
    Matrix4.mul(this.combined.val, this.view.val);
    if (updateFrustum) {
        this.invProjectionView.set(this.combined);
        Matrix4.inv(this.invProjectionView.val);
        this.frustum.update(this.invProjectionView);
    }

}

Notice that is overwrites view.

This answer only applies if you are indeed using a PerspectiveCamera.

One way of using yaw, pitch and roll with a PerspectiveCamera could be to transform a forward vector using the matrix you already calculate using setFromEulerAngles, for example:

    Vector3 forward = new Vector3(Vector3.Z);
    Matrix4 mat = new Matrix4();
    mat.idt().setFromEulerAngles(yaw, pitch, roll);
    forward.mul(mat);

    Vector3 lookAtTarget = new Vector3();
    lookAtTarget.set(camera.position).add(forward);

    camera.lookAt(lookAtTarget);
    camera.update();