我正在尝试按照this教程编写类似相机的FPS。但是,当我左右移动鼠标而不是左右移动时,相机会旋转。

我正在使用的sphericalToCartesian函数来自this帖子。

我的相机课:

private static final float FOVY = 60f, ZNEAR = .1f, ZFAR = 2000f;

private Mat4 projectionMatrix;

// start out at origin (0,0,0)
private Vec3 position = new Vec3();

// horizontal angle in radians: toward -Z
private float horizontalAngle = (float) FastMath.PI;
// NOTE: tutorial says 0 is horizon
// vertical angle in radians: π/2, look at the horizon
private float verticalAngle = (float) (FastMath.PI / 2.0f);

private float mouseSpeed = 0.01f;

private Vec3 sphericalToCartesian(float yaw, float pitch) {
    return new Vec3(
            (float) (FastMath.cos(pitch) * FastMath.sin(yaw)),
            (float) FastMath.sin(pitch),
            (float) (FastMath.cos(pitch) * FastMath.cos(yaw))
        );
}

public FPSCamera(Observer o) {
    addObserver(o);
}

/**
 * Called in GLEventListener.display() and sent to shader with
 * glUniformMatrix4fv
 *
 * @return MPV matrix
 */
public Mat4 getMVPMatrix() {
    Vec3 frontVector = sphericalToCartesian(horizontalAngle, verticalAngle);
    Vec3 rightVector = sphericalToCartesian((float) (horizontalAngle + FastMath.PI / 2.0f), 0f);
    Vec3 upVector = rightVector.cross(frontVector);

    Mat4 viewMatrix = Matrices.lookAt(position, position.add(frontVector), upVector);

    return projectionMatrix.multiply(viewMatrix);
}

/**
 * Called in GLEventListener.reshape()
 *
 * @param aspect The aspect ratio
 */
public void setPerspective(float aspect) {
    projectionMatrix = Matrices.perspective(FOVY, aspect, ZNEAR, ZFAR);
}

/**
 * Key and mouse listeners will notify the camera when something happens by
 * calling this method.
 */
@Override
public void update(Observable o, Object arg) {
    if (o instanceof FPSKeyController) {
        final FPSKeyController.Direction[] dirs = (FPSKeyController.Direction[]) arg;

        Vec3 right = sphericalToCartesian((float) (horizontalAngle + FastMath.PI / 2.0f), 0f);
        Vec3 front = sphericalToCartesian(horizontalAngle, verticalAngle);

        // Move forward and backward
        if (dirs[0] == FPSKeyController.Direction.FORWARD) {
            position = position.add(front);
        } else if (dirs[0] == FPSKeyController.Direction.BACKWARD) {
            position = position.subtract(front);
        }
        // Strafe left and right
        if (dirs[1] == FPSKeyController.Direction.RIGHT) {
            position = position.subtract(right);
        } else if (dirs[1] == FPSKeyController.Direction.LEFT) {
            position = position.add(right);
        }
    } else if (o instanceof FPSMouseController) {
        final FPSMouseController.Direction[] dirs = (FPSMouseController.Direction[]) arg;

        if (dirs[0] == FPSMouseController.Direction.LEFT) {
            // Look left
            horizontalAngle -= mouseSpeed;
            // Let angle range from -2π to 2π
            if (horizontalAngle < -FastMath.PI * 2) {
                horizontalAngle = 0;
            }
        } else if (dirs[0] == FPSMouseController.Direction.RIGHT) {
            // Look right
            horizontalAngle += mouseSpeed;
            // Let angle range from -2π to 2π
            if (horizontalAngle > FastMath.PI * 2) {
                horizontalAngle = 0;
            }
        }

        if (dirs[1] == FPSMouseController.Direction.UP) {
            // Look up
            // Stop the camera from looking more than straight up
            if (verticalAngle + mouseSpeed <= FastMath.PI) {
                verticalAngle += mouseSpeed;
            }
        } else if (dirs[1] == FPSMouseController.Direction.DOWN) {
            // Look down
            // Stop the camera from looking more than straight down
            if (verticalAngle - mouseSpeed >= 0) {
                verticalAngle -= mouseSpeed;
            }

        }
    }
    // input is guaranteed to change the camera, so we can always update the view
    setChanged();
    // repaint() and eventually GLEventListener.display() are called at the observer
    notifyObservers();
}


我认为我的问题是verticalAngle,在本教程中,0是指地平线。我必须将其更改为π/2 radians才能看到地平线。当我向下看时,我可以左右看。

最佳答案

您说得对,gouessej,Valve使用Z作为向上,而openGL使用Y。

我通过这样旋转整个世界来解决这个问题:

private Mat4 modelMatrix = Matrices.rotate(HALF_PI, new Vec3(1,0,0));


然后将视图和投影矩阵乘以getMVPMatrix()中的这个新模型矩阵:

return projectionMatrix.multiply(viewMatrix).multiply(modelMatrix);


使MVP矩阵成为实际的ModelViewProjection矩阵。在仅定义ViewProjection矩阵之前。

感谢您的时间,

枯萎病

08-26 11:52