这对我来说解释起来会很混乱,所以请耐心等待。
我已经在我的相机类中实现了大多数类型的移动和旋转,一切都可以通过键盘进行,现在我想实现鼠标。我像这样捕获鼠标移动:
#define SENSITIVITY 25.0f
void main(void) {
(...)
glutPassiveMotionFunc(processPassiveMotion);
glutWarpPointer(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2);
glutSetCursor(GLUT_CURSOR_NONE);
(...)
}
void processPassiveMotion(int x, int y) {
int centerX = WINDOW_WIDTH / 2;
int centerY = WINDOW_HEIGHT / 2;
int deltaX = -1 * (x - centerX);
int deltaY = -1 * (y - centerY);
if(deltaX != 0 || deltaY != 0) {
mainCamera.Rotate(deltaX / SENSITIVITY, deltaY / SENSITIVITY);
glutWarpPointer(centerX, centerY);
}
}
在我读完所有内容之后,我相信这对于我的情况来说已经足够了。但我必须声明,首先我尝试致电Pitch()
and Yaw()
相机功能,但这是行不通的,我必须创建一个额外的功能来“同时”旋转两个轴。
旋转函数是这样的:
#define DEG2RAD(a) (a * (M_PI / 180.0f))
#define SINDEG(a) sin(DEG2RAD(a))
#define COSDEG(a) cos(DEG2RAD(a))
void Camera::Rotate(GLfloat angleX, GLfloat angleY) {
Reference = NormalizeVector(
Reference * COSDEG(angleY) + UpVector * SINDEG(angleY)
);
Reference = NormalizeVector(
Reference * COSDEG(angleX) - RightVector * SINDEG(angleX)
);
UpVector = CrossProduct(&Reference, &RightVector) * (-1);
RightVector = CrossProduct(&Reference, &UpVector);
}
The Reference
是观察方向,即相机正在观察的点。由于它是标准化向量,因此它的范围从 -1.0 到 1.0。该向量或点稍后与另一个向量一起使用(Position
,这是相机位置)来计算要使用的真实观察点gluLookAt
, 像这样:
void Camera::LookAt(void) {
Vector3D viewPoint = Position + Reference;
gluLookAt(
Position.x, Position.y, Position.z,
viewPoint.x, viewPoint.y, viewPoint.z,
UpVector.x, UpVector.y, UpVector.z
);
}
上面的所有向量运算都像+
, -
and *
当然是超载的。
现在我要尝试描述我的问题......
上面的旋转函数工作得很好,因为它可以使用鼠标正确执行俯仰和偏航。然而,这些旋转看起来并不像第一人称射击游戏中的旋转。在这些游戏中,当一个人看着天空,然后向左/向右看时,人们期望继续看着天空。想象我们在一个球体内部,这样的运动应该在球体的顶部“画”一个圆。
但事实并非如此,因为偏航不是这么做的。偏航运动将围绕任意轴旋转,我认为在这种情况下它是向上向量。所以,问题出在偏航运动上,因为俯仰似乎工作得很好。
换句话说,我上面的代码无法保持地平线水平,这是必须发生的事情,因为在游戏中,当一个人看着天空,然后向左/右看时,地平线总是水平的。我的代码不会发生同样的情况,我向上看,然后向左/向右,地平线将全部扭曲。
我说得够清楚了吗?我不确定如何更好地解释这一点。 :( 希望这足以让任何人理解。
我不知道如何解决这个问题...向上/向下看后如何正确地向左/向右看,保持地平线水平?
EDIT:
我的旋转函数代码取自同样存在的偏航和俯仰函数,因此我可以独立调用这些旋转。出于参考目的,我也会将它们与 Roll 函数一起添加到下面(我可能永远不会使用它,但如果我需要它,它就在那里):
void Camera::Pitch(GLfloat angle) {
Reference = NormalizeVector(
Reference * COSDEG(angle) + UpVector * SINDEG(angle)
);
UpVector = CrossProduct(&Reference, &RightVector) * (-1);
}
void Camera::Yaw(GLfloat angle) {
Reference = NormalizeVector(
Reference * COSDEG(angle) - RightVector * SINDEG(angle)
);
RightVector = CrossProduct(&Reference, &UpVector);
}
void Camera::Roll(GLfloat angle) {
RightVector = NormalizeVector(
RightVector * COSDEG(angle) - UpVector * SINDEG(angle)
);
UpVector = CrossProduct(&Reference, &RightVector) * (-1);
}