我正在尝试按照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矩阵成为实际的
Model
,View
和Projection
矩阵。在仅定义View
和Projection
矩阵之前。感谢您的时间,
枯萎病