3
votes

I'm using libgdx to develop a basic 3d game for android and I'm having difficulty properly orienting the camera given three rotation angles provided from the compass (azimuth - rotation about Z, roll - rotation about Y, pitch - rotation about X). I've had some slight success with the following code in that I can properly aim the virtual camera down the Z-axis and X-axis as I expected. (Angles are in degrees [-180,180])

camera.direction.x = 0;
camera.direction.y = 0;
camera.direction.z = 1;
camera.up.x = -1;
camera.up.y = 0;
camera.up.z = 0;

camera.rotate(azimuth,0,0,1);
camera.rotate(roll,0,1,0);
camera.rotate(pitch,1,0,0);

I've also had some success with this, but it does not orient the camera's up-vector. (Angles have been converted to radians in this version)

float x,y,z;
roll = (float) (roll + Math.PI/2.0);
x = (float) (Math.cos(azimuth) * Math.cos(roll));
y = (float) (Math.sin(azimuth) * Math.cos(roll));
z = (float) (Math.sin(roll));
Vector3 lookat = new Vector3(x,y,z);
camera.lookAt(lookat.x, lookat.y, lookat.z);

Can someone shed some light on how to properly orient the virtual camera from these three angles?

Also, I'm trying to have the phone be in landscape mode such that the top of the phone is to the left and the bottom is to the right. Hence the camera's default direction (all rotations are at 0, top of the phone is aimed north) be the camera aiming toward the ground (positive Z) with the up aiming east (negative X).

1
could you possibly post the source code of this or explain the answer better?William Reed

1 Answers

4
votes

By coding other things for a while, I eventually reached a point where I was trying to separate the rendering, simulation, and input. Because of that I have come up with the following solution that works for me. I haven't tested it rigorously, but it appears to do what I want (ignoring camera roll).

On the android part of the program, I needed to set the orientation to landscape mode:

<activity android:name=".MySuperAwesomeApplication"
              android:label="@string/app_name"
              android:screenOrientation="landscape">
              >

I created a player class to store yaw, pitch, roll, and position

public class Player {
    public final Vector3 position = new Vector3(0,1.5f,0);    
    /** Angle left or right of the vertical */
    public float yaw = 0.0f;
    /** Angle above or below the horizon */
    public float pitch = 0.0f;
    /** Angle about the direction as defined by yaw and pitch */
    public float roll = 0.0f;
}

And then when I update the player based on input I do the following:

player.yaw = -Gdx.input.getAzimuth();
player.pitch = -Gdx.input.getRoll()-90;
player.roll = -Gdx.input.getPitch();

Note that pitch maps to input.roll and roll maps to input.pitch. Not sure why, but it works for me. Finally update the camera:

camera.direction.x = 0;
camera.direction.y = 0;
camera.direction.z = 1;
camera.up.x = 0;
camera.up.y = 1;
camera.up.z = 0;
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 0;
camera.update();

// The world up vector is <0,1,0>
camera.rotate(player.yaw,0,1,0);
Vector3 pivot = camera.direction.cpy().crs(camera.up);
camera.rotate(player.pitch, pivot.x,pivot.y,pivot.z);
camera.rotate(player.roll, camera.direction.x, camera.direction.y, camera.direction.z);
camera.translate(player.position.x, player.position.y, player.position.z);
camera.update();

EDIT: added camera roll to the code. For me and my Droid 2, roll appears to only have values in [-90,90] such that if you rotate past -90 or 90 the values start changing back towards 0.