protected UVW computeUVW() {
        Vector3 w = subtract(eye, look).normalize();

        Vector3 up = rotate(this.up, w, roll);
        // take care of the singularity by hardwiring in specific camera orientations
        if (eye.getX() == look.getX() && eye.getZ() == look.getZ() && eye.getY() > look.getY()) { // camera looking vertically down
            return new UVW(
                    new Vector3(0, 0, 1),
                    new Vector3(1, 0, 0),
                    new Vector3(0, 1, 0));
        }

        if (eye.getX() == look.getX() && eye.getZ() == look.getZ() && eye.getY() < look.getY()) { // camera looking vertically up
            return new UVW(
                    new Vector3(1, 0, 0),
                    new Vector3(0, 0, 1),
                    new Vector3(0, -1, 0));
        }

        //Otherwise, calculate UVW
        Vector3 u = cross(up, w).normalize();
        Vector3 v = cross(w, u);

        return new UVW(u, v, w);
    }