旋转opengl相机的问题
Problems rotating opengl camera
我无法理解这个问题背后的数学原理,我正在尝试创建一个 FPS 相机,我可以通过鼠标输入自由查看。
我正在尝试以 180 度的自由度旋转和定位我的观察点。我知道更简单的解决方案是 glRotate 世界以适应我的视角,但我不想要这种方法。我对这里涉及的三角学相当陌生,无法弄清楚如何按照我想要的方式解决这个问题...
这是我到目前为止的尝试...
获取鼠标相对于window中心的坐标的代码,然后在我的相机对象中处理它
#define DEG2RAD(a) (a * (M_PI / 180.0f))//convert to radians
static void glutPassiveMotionHandler(int x, int y) {
glf centerX = WinWidth / 2; glf centerY = WinHeight / 2;//get windows origin point
f speed = 0.2f;
f oldX = mouseX; f oldY = mouseY;
mouseX = DEG2RAD(-((x - centerX)));//get distance from 0 and convert to radians
mouseY = DEG2RAD(-((y - centerY)));//get distance from 0 and convert to radians
f diffX = mouseX - oldX; f diffY = mouseY - oldY;//get difference from last frame to this frame
if (mouseX != 0 || mouseY != 0) {
mainCamera->Rotate(diffX, diffY);
}
旋转相机的代码
void Camera::Rotate(f angleX, f angleY) {
Camera::refrence = Vector3D::NormalizeVector(Camera::refrence * cos(angleX)) + (Camera::upVector * sin(angleY));//rot up
Camera::refrence = Vector3D::NormalizeVector((Camera::refrence * cos(angleY)) - (Camera::rightVector * sin(angleX)));//rot side to side
};
Camera::refrence是我们的lookat point,处理lookat point的处理如下
void Camera::LookAt(void) {
gluLookAt(
Camera::position.x, Camera::position.y, Camera::position.z,
Camera::refrence.x, Camera::refrence.y, Camera::refrence.z,
Camera::upVector.x, Camera::upVector.y, Camera::upVector.z
);
};
U_Cam_X_angle
是左右旋转..U_Cam_Y_angle
是上下旋转.
view_radius
是 U_look_point_x
、U_look_point_y
和 U_look_point_z
的视距(缩放)。
这始终是一个负数!这是因为你总是朝积极的方向看。在屏幕的更深处是更积极的。
这都是以弧度为单位的。
最后三个.. eyeX
、eyeY
和 eyeZ
是相机在 3D 中的位置 space。
此代码在 VB.net 中。在线查找 VB 到 C++ 的转换器或手动进行。
Public Sub set_eyes()
Dim sin_x, sin_y, cos_x, cos_y As Single
sin_x = Sin(U_Cam_X_angle + angle_offset)
cos_x = Cos(U_Cam_X_angle + angle_offset)
cos_y = Cos(U_Cam_Y_angle)
sin_y = Sin(U_Cam_Y_angle)
cam_y = Sin(U_Cam_Y_angle) * view_radius
cam_x = (sin_x - (1 - cos_y) * sin_x) * view_radius
cam_z = (cos_x - (1 - cos_y) * cos_x) * view_radius
Glu.gluLookAt(cam_x + U_look_point_x, cam_y + U_look_point_y, cam_z + U_look_point_z, _
U_look_point_x, U_look_point_y, U_look_point_z, 0.0F, 1.0F, 0.0F)
eyeX = cam_x + U_look_point_x
eyeY = cam_y + U_look_point_y
eyeZ = cam_z + U_look_point_z
End Sub
相机由位置点 (position
) 目标点 (refrence
) 和向上矢量 upVector
定义。如果你想改变相机的方向,那么你必须将方向矢量从位置(position
)旋转到目标(refrence
)而不是目标点Rotation matrix.
注意,由于这 2 个角度是应该改变已经旋转的视图的角度,因此您必须使用旋转矩阵来旋转指向任意方向的向量。
写一个函数,设置绕任意轴的 3x3 旋转矩阵:
void RotateMat(float m[], float angle_radians, float x, float y, float z)
{
float c = cos(angle_radians);
float s = sin(angle_radians);
m[0] = x*x*(1.0f-c)+c; m[1] = x*y*(1.0f-c)-z*s; m[2] = x*z*(1.0f-c)+y*s;
m[3] = y*x*(1.0f-c)+z*s; m[4] = y*y*(1.0f-c)+c; m[5] = y*z*(1.0f-c)-x*s;
m[6] = z*x*(1.0f-c)-y*s; m[7] = z*y*(1.0f-c)+x*s; m[8] = z*z*(1.0f-c)+c };
}
编写一个函数,通过矩阵旋转 3 维向量:
Vector3D Rotate(float m[], const Vector3D &v)
{
Vector3D rv;
rv.x = m[0] * v.x + m[3] * v.y + m[6] * v.z;
rv.y = m[1] * v.x + m[4] * v.y + m[7] * v.z;
rv.z = m[2] * v.x + m[5] * v.y + m[8] * v.z;
return rv;
}
从目标位置计算向量:
Vector3D los = Vector3D(refrence.x - position.x, refrence.y - position.y, refrence.z - position.z);
将所有向量围绕世界的 z 轴旋转 angleX
:
float rotX[9];
RotateMat(rotX, angleX, Vector3D(0, 0, 1));
los = Rotate(rotX, los);
upVector = Rotate(rotX, upVector);
将所有向量围绕视图的当前 y 轴旋转 angleY
:
float rotY[9];
RotateMat(rotY, angleY, Vector3D(los.x, los.y, 0.0));
los = Rotate(rotY, los);
upVector = Rotate(rotY, upVector);
计算新的目标点:
refrence = Vector3D(position.x + los.x, position.y + los.y, position.z + los.z);
我无法理解这个问题背后的数学原理,我正在尝试创建一个 FPS 相机,我可以通过鼠标输入自由查看。
我正在尝试以 180 度的自由度旋转和定位我的观察点。我知道更简单的解决方案是 glRotate 世界以适应我的视角,但我不想要这种方法。我对这里涉及的三角学相当陌生,无法弄清楚如何按照我想要的方式解决这个问题...
这是我到目前为止的尝试...
获取鼠标相对于window中心的坐标的代码,然后在我的相机对象中处理它
#define DEG2RAD(a) (a * (M_PI / 180.0f))//convert to radians
static void glutPassiveMotionHandler(int x, int y) {
glf centerX = WinWidth / 2; glf centerY = WinHeight / 2;//get windows origin point
f speed = 0.2f;
f oldX = mouseX; f oldY = mouseY;
mouseX = DEG2RAD(-((x - centerX)));//get distance from 0 and convert to radians
mouseY = DEG2RAD(-((y - centerY)));//get distance from 0 and convert to radians
f diffX = mouseX - oldX; f diffY = mouseY - oldY;//get difference from last frame to this frame
if (mouseX != 0 || mouseY != 0) {
mainCamera->Rotate(diffX, diffY);
}
旋转相机的代码
void Camera::Rotate(f angleX, f angleY) {
Camera::refrence = Vector3D::NormalizeVector(Camera::refrence * cos(angleX)) + (Camera::upVector * sin(angleY));//rot up
Camera::refrence = Vector3D::NormalizeVector((Camera::refrence * cos(angleY)) - (Camera::rightVector * sin(angleX)));//rot side to side
};
Camera::refrence是我们的lookat point,处理lookat point的处理如下
void Camera::LookAt(void) {
gluLookAt(
Camera::position.x, Camera::position.y, Camera::position.z,
Camera::refrence.x, Camera::refrence.y, Camera::refrence.z,
Camera::upVector.x, Camera::upVector.y, Camera::upVector.z
);
};
U_Cam_X_angle
是左右旋转..U_Cam_Y_angle
是上下旋转.
view_radius
是 U_look_point_x
、U_look_point_y
和 U_look_point_z
的视距(缩放)。
这始终是一个负数!这是因为你总是朝积极的方向看。在屏幕的更深处是更积极的。
这都是以弧度为单位的。
最后三个.. eyeX
、eyeY
和 eyeZ
是相机在 3D 中的位置 space。
此代码在 VB.net 中。在线查找 VB 到 C++ 的转换器或手动进行。
Public Sub set_eyes()
Dim sin_x, sin_y, cos_x, cos_y As Single
sin_x = Sin(U_Cam_X_angle + angle_offset)
cos_x = Cos(U_Cam_X_angle + angle_offset)
cos_y = Cos(U_Cam_Y_angle)
sin_y = Sin(U_Cam_Y_angle)
cam_y = Sin(U_Cam_Y_angle) * view_radius
cam_x = (sin_x - (1 - cos_y) * sin_x) * view_radius
cam_z = (cos_x - (1 - cos_y) * cos_x) * view_radius
Glu.gluLookAt(cam_x + U_look_point_x, cam_y + U_look_point_y, cam_z + U_look_point_z, _
U_look_point_x, U_look_point_y, U_look_point_z, 0.0F, 1.0F, 0.0F)
eyeX = cam_x + U_look_point_x
eyeY = cam_y + U_look_point_y
eyeZ = cam_z + U_look_point_z
End Sub
相机由位置点 (position
) 目标点 (refrence
) 和向上矢量 upVector
定义。如果你想改变相机的方向,那么你必须将方向矢量从位置(position
)旋转到目标(refrence
)而不是目标点Rotation matrix.
注意,由于这 2 个角度是应该改变已经旋转的视图的角度,因此您必须使用旋转矩阵来旋转指向任意方向的向量。
写一个函数,设置绕任意轴的 3x3 旋转矩阵:
void RotateMat(float m[], float angle_radians, float x, float y, float z)
{
float c = cos(angle_radians);
float s = sin(angle_radians);
m[0] = x*x*(1.0f-c)+c; m[1] = x*y*(1.0f-c)-z*s; m[2] = x*z*(1.0f-c)+y*s;
m[3] = y*x*(1.0f-c)+z*s; m[4] = y*y*(1.0f-c)+c; m[5] = y*z*(1.0f-c)-x*s;
m[6] = z*x*(1.0f-c)-y*s; m[7] = z*y*(1.0f-c)+x*s; m[8] = z*z*(1.0f-c)+c };
}
编写一个函数,通过矩阵旋转 3 维向量:
Vector3D Rotate(float m[], const Vector3D &v)
{
Vector3D rv;
rv.x = m[0] * v.x + m[3] * v.y + m[6] * v.z;
rv.y = m[1] * v.x + m[4] * v.y + m[7] * v.z;
rv.z = m[2] * v.x + m[5] * v.y + m[8] * v.z;
return rv;
}
从目标位置计算向量:
Vector3D los = Vector3D(refrence.x - position.x, refrence.y - position.y, refrence.z - position.z);
将所有向量围绕世界的 z 轴旋转 angleX
:
float rotX[9];
RotateMat(rotX, angleX, Vector3D(0, 0, 1));
los = Rotate(rotX, los);
upVector = Rotate(rotX, upVector);
将所有向量围绕视图的当前 y 轴旋转 angleY
:
float rotY[9];
RotateMat(rotY, angleY, Vector3D(los.x, los.y, 0.0));
los = Rotate(rotY, los);
upVector = Rotate(rotY, upVector);
计算新的目标点:
refrence = Vector3D(position.x + los.x, position.y + los.y, position.z + los.z);