1

I've made my own Camera object, with a forward vector as well as a up vector. I happen to be programming in Android using OpenGL ES 2.0 but I think this question is relevant to all frameworks, it seems to be some math issue I'm not understanding.

Here's a gif of my Pitch/Yaw working correctly:

Pitch/Yawing

Here's a gif of Pitch/Yaw in a circle, causing the square to rotate, because the camera is tilting (the up vector becomes negative as I continue).

Pitch/Yaw in a circle causes Tilting

Here's pseudocode for my pan/yaw functions:

function pitch(amount) {
    if (amount == 0) return;
    forward = normalize(forward + up * amount);

    // Now fix the incorrect up vector
    right = cross(forward, up);
    up = normalize(cross(right, forward));
}

function yaw(amount) {
    if (amount == 0) return;

    right = cross(forward, up);
    forward = normalize(forward + right * amount);
}

I get the same issue if I use Vector rotations instead of Vector Addition (amount is an angle and I use a Rotation Matrix in the X or Y axis)

Pitch: forward = normalize(rotated(forward, angle, Vector3(1, 0, 0)));
Yaw: forward = normalize(rotated(forward, angle, Vector3(0, 1, 0)));

Why is this happening? Is there a way to stop it?

EDIT: I followed the instructions at Why is the camera tilting around the z axis when I only specified x and y? to pitch using the local X axis and yaw using the world Y axis, same result.

Here's the new pseudocode:

function pitch(angle) {
    if (angle == 0) return;

    right = cross(forward, up);
    forward = normalized(rotated(forward, angle, right));

    // Fix the now incorrect up vector
    up = normalized(cross(right, forward));
}

function yaw(angle) {
    if (angle == 0) return;

    forward = normalized(rotated(forward, angle, Vector3(0, 1, 0)));
}

You can see all the code at https://github.com/repwolfe/paper-escaper-android/tree/master/app/src/main/java/com/studioussoftware/paperescaper

robev
  • 145
  • 5

1 Answers1

2

You're using the previous value of the up vector to update the right vector and the up vector itself. That means any small deviation from the vertical will tend to accumulate in the up vector and snowball over repeated updates.

Instead, you can define right in reference to the global up vector (0, 1, 0) so this error can't accumulate:

right = normalized(cross(forward, Vector3(0, 1, 0)));
up = cross(forward, right);

Note that this is not suitable when forward points nearly parallel to the vertical axis. You can either clamp the camera's pitch to stay away from this trouble spot, or apply the up correction gradually over multiple frames to avoid a sudden pop or lurch.

DMGregory
  • 134,153
  • 22
  • 242
  • 357