使用 OpenGL 和 GLUT 创建 FPS 风格的运动系统
Posted
技术标签:
【中文标题】使用 OpenGL 和 GLUT 创建 FPS 风格的运动系统【英文标题】:Creating an FPS style movement system with OpenGL and GLUT 【发布时间】:2014-10-01 03:41:30 【问题描述】:我正在尝试使用 GLUT 和 OpenGL 实现第一人称移动系统。到目前为止,我的扫射从左到右,向前/向后运动正常工作。但是,我的问题来自环顾四周。我希望能够像大多数/所有 FPS 游戏一样使用鼠标的移动环顾四周。我正在使用 gluLookAt 进行所有运动/环顾四周。目前,对于环视部分,我有这个(取自教程)
gluLookAt(position.x, position.y, position.z,
position.x + direction.x, position.y + direction.y, position.z + direction.z,
up_vector.x, up_vector.y, up_vector.z);
然后,当有被动鼠标移动时,我会检查它并执行以下操作:
horizontal_angle += 0.005* float(x - origin_x);
vertical_angle += 0.005* float(y - origin_y);
direction_vector.x = cos(vertical_angle) * sin(horizontal_angle);
direction_vector.y = sin(vertical_angle);
direction_vector.z = cos(vertical_angle) * cos(horizontal_angle);
position.x = sin(horizontal_angle - 3.14f/2.0f);
position.y = 0.0f;
position.z = cos(horizontal_angle - 3.14f/2.0f);
up_vector = crossProduct(right_vector, direction_vector);
但是,这给了我一些非常奇怪、摇摆不定的效果,与我想要的效果并不特别接近。
【问题讨论】:
【参考方案1】:首先,据我所知 gluLookAt 已被弃用,如果您不想深入研究该级别,您应该考虑查看 GLM,它是一个可以为您处理几乎所有数学内容的数学库。
其次,您可以考虑使用 quaternions 来旋转您的相机,它们比仅使用普通三角函数来旋转相机要平滑得多,而且它们也不会受到 gimbal lock 的影响。据我所知,GLM 确实有一个四元数的实现,但你也可以自己实现它,我已经做了很长时间了,而且我做对了,所以我不会很难。 :P
如果您现在确实想坚持使用三角函数,这是我更改为四元数之前的旧旋转函数:
void Camera::rotateCamera(int xDelta, int yDelta, int xMid, int yMid)
const GLfloat X_SCALED = (GLfloat)xDelta / (GLfloat)xMid;
const GLfloat Y_SCALED = (GLfloat)yDelta / (GLfloat)yMid;
const GLfloat ANGLE_DELTA = 2 * 360.0f / 360.0f * 3.14f;
const GLfloat LEFT_RIGHT_ROT = X_SCALED * ANGLE_DELTA;
const GLfloat UP_DOWN_ROT = Y_SCALED * ANGLE_DELTA;
direction = d - r;
vec3 right = cross(direction, u);
vec4 temp(direction.x, direction.y, direction.z, 0.0f);
mat4 identity;
identity = rotate(identity, UP_DOWN_ROT, right);
identity = rotate(identity, LEFT_RIGHT_ROT, u) ;
temp = identity * temp;
d = r;
d[0] += temp[0];
d[1] += temp[1];
d[2] += temp[2];
view = lookAt(r,d,u);
xDelta 是鼠标从屏幕中心移动的量,xMid 是屏幕中心。 r 是相机的眼睛,d 是它的朝向,u 是它的向上向量。
如果你有任何问题,尽管问我 :)
更新:
这是我用于实现quaternion based camera 的初始文章。
我最好的建议是尽量远离欧拉角,它们会失去精度,并可能导致奇怪的运动和旋转伪影。
【讨论】:
感谢您的回复,我想我会选择四元数,似乎是一个更好的选择! 万向节锁定是我们头部旋转方式的结果,即当您直视或直视时,您会看到一个奇点。您的“基于四元数的解决方案”不是通过四元数来避免万向节锁定,而是通过将间距从两极夹住,这样您就不能直视或直视。您也可以夹紧 Eular 角,从而避免该问题。如果你不夹紧,那么四元数不会救你,因为当View - Position
与Up
平行时,它们的叉积会降为零,你就会得到可怕的万向节锁。【参考方案2】:
除了职位部分,你的做法对我来说似乎是正确的:
position.x = sin(horizontal_angle - 3.14f/2.0f);
position.y = 0.0f;
position.z = cos(horizontal_angle - 3.14f/2.0f);
应该是这样的:
vector right_vector = crossProduct(direction_vector, vector(0, 1, 0)); // maybe crossProduct(vector(0, 1, 0), direction_vector)
float speed = 3; // you decide the value.
if ( GetKey(Key_Forward) == Key_Pressed )
position.x += (direction_vector.x * speed);
position.y += (direction_vector.y * speed);
position.z += (direction_vector.z * speed);
else if ( GetKey(Key_Back) == Key_Pressed )
position.x -= (direction_vector.x * speed);
position.y -= (direction_vector.y * speed);
position.z -= (direction_vector.z * speed);
if ( GetKey(Key_Right) == Key_Pressed )
position.x += (right_vector.x * speed);
position.y += (right_vector.y * speed);
position.z += (right_vector.z * speed);
else if ( GetKey(Key_Back) == Key_Pressed )
position.x -= (right_vector.x * speed);
position.y -= (right_vector.y * speed);
position.z -= (right_vector.z * speed);
GetKey() 和 Key_Pressed 取决于您使用的 API 希望它对你有用,:)。
【讨论】:
以上是关于使用 OpenGL 和 GLUT 创建 FPS 风格的运动系统的主要内容,如果未能解决你的问题,请参考以下文章
在终端应用程序中使用 opengl(没有 glut/glew)[关闭]
win8.1中vs2015配置opengl环境,那个glut.lib和glut32.lib放哪里啊