c++ - 为什么 glutPassiveMotionFunc 没有时间处理所有移动鼠标的调用
问题描述
我研究 OpenGL 并制作类似 3d 射击游戏的东西。如果您缓慢移动鼠标,则一切正常。如果它很快,那么相机的旋转就跟不上鼠标的速度。以前,这都是在三个类中编写的。我决定简化以优化。也许其他东西需要优化?
主文件
#include "game_engine.h"
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(wnd_width, wnd_height);
glutInitWindowPosition(300, 100);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glutCreateWindow("OpenGL my");
glutDisplayFunc(display);
//glutIdleFunc(Idle);
glutKeyboardFunc(KeyPressed);
glutPassiveMotionFunc(MouseMove);
glutSetCursor(GLUT_CURSOR_CROSSHAIR);
TextureInit("t.jpg");
glutMainLoop();
return 0;
}
游戏引擎.h
#ifndef GAME_ENGINE_H
#define GAME_ENGINE_H
#include <GL/glut.h>
#include <stb_image.h>
#include <dirent.h>
const int wnd_width=1300;
const int wnd_height=900;
const GLdouble aspect = wnd_width/wnd_height;
extern unsigned int texture_floor;
extern unsigned int texture_wall;
extern float text_coords[];
extern int prev_mouse_x;
extern int prev_mouse_y;
extern int tmp;
void DrawFloor(float x, float y, float z, float width,
float length, float lift=0); // x, y, z - center start point);
void DrawWall(float x1, float z1, float x2, float z2);
void KeyPressed(unsigned char key, int x, int y);
void TextureInit(char* file);
void display();
void MouseMove(int x, int y);
void Idle();
#endif
游戏引擎.cpp
#define STB_IMAGE_IMPLEMENTATION
#include "game_engine.h"
#include "camera.h"
#include <cstdio>
float text_coords[] = {0,0, 1,0, 1,1, 0,1};
int prev_mouse_x=0;
int prev_mouse_y=0;
int tmp=0;
unsigned int texture_floor=0;
void TextureInit(char* file)
{
int width, height, cnt;
unsigned char* data = stbi_load(file, &width, &height, &cnt, 0);
if(data==nullptr) { printf("NO\n"); }
else { printf("%d\t%d\n",width, height); }
glGenTextures(1, &texture_floor);
glBindTexture(GL_TEXTURE_2D, texture_floor);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
0, GL_RGB, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
}
void display()
{
glClearColor(0.6, 0.8, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90, aspect, 0.1, 5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(pos.x, pos.y, pos.z,
view.x, view.y, view.z,
0, 0.2, 0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_floor);
glBegin(GL_QUADS);
DrawFloor(0, 0, 0, 1.5, 2.5);
DrawFloor(0, 0, 2.5, 1.5, 5);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
DrawWall(-0.5, 0.1, -0.5, 2);
DrawWall(0.5, 0.1, 0.5, 1.7);
DrawWall(0.5, 1.7, 1.5, 1.7);
DrawWall(-0.5, 2, 0.9, 2.1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEnd();
glutSwapBuffers();
}
void DrawFloor(float x, float y, float z, float width, float length, float lift)
{
float r = width/2;
glVertex3d(x-r, y, z);
glVertex3d(x+r, y, z);
glVertex3d(x+r, y+lift, z+length);
glVertex3d(x-r, y+lift, z+length);
}
void DrawWall(float x1, float z1, float x2, float z2)
{
glTexCoord2f(0, 0);
glVertex3f(x1, 0, z1);
glTexCoord2f(1, 0);
glVertex3f(x2, 0, z2);
glTexCoord2f(1, 1);
glVertex3f(x2, 0.7, z2);
glTexCoord2f(0, 1);
glVertex3f(x1, 0.7, z1);
}
void KeyPressed(unsigned char key, int x, int y)
{
switch (key)
{
case 'w':
{ MoveForward(); break; }
case 's':
{ MoveBack(); break; }
case 'q':
exit(0);
}
if(key==32){
pos.y+=0.02;
view.y+=0.02;
}
glutPostRedisplay();
}
void MouseMove(int x, int y)
{
if(x>prev_mouse_x)
{
angle_rad +=0.03;
view.x = pos.x + (radius * cos(angle_rad));
view.z = pos.z + (radius * sin(angle_rad));
}
if(x<prev_mouse_x)
{
angle_rad -=0.03;
view.x = pos.x + (radius * cos(angle_rad));
view.z = pos.z + (radius * sin(angle_rad));
}
if(y>prev_mouse_y) { view.y-=0.0006; }
if(y<prev_mouse_y) { view.y+=0.0006; }
glutPostRedisplay();
prev_mouse_x = x;
prev_mouse_y = y;
}
void Idle()
{
}
相机.h
#ifndef CAMERA_H
#define CAMERA_H
#include <glm/glm.hpp>
using namespace glm;
const float pi = 3.14159265359;
extern float angle_deg; // in degrees
extern float angle_rad; // in radians
extern float radius;
extern vec3 pos;
extern vec3 view;
extern vec3 next_pnt;
vec3 operator*(vec3 v, int d);
void MoveForward();
void MoveBack();
void PrintPosition();
#endif
相机.cpp
#include "camera.h"
float angle_deg = 1;
float angle_rad = 1.57;
float radius = 0.02;
vec3 pos = vec3(0, 0.3, 0.0);
vec3 view = vec3(0.0, 0.3, 0.02);
vec3 next_pnt = vec3(0.0, 0.0, 0.0);
vec3 operator*(vec3 v, int d)
{
float x = v.x * d;
float y = v.y * d;
float z = v.z * d;
return vec3(x, y, z);
}
void MoveForward()
{
vec3 d = view - pos;
d = d * 2;
next_pnt = pos + d;
pos = view;
view = next_pnt;
}
void MoveBack()
{
vec3 d = view - pos;
next_pnt = pos - d;
view = pos;
pos = next_pnt;
}
解决方案
您没有考虑鼠标移动距离。当鼠标移动得更快时,x 和 prev_mouse_x 之间的距离会更大,但你总是加 0.3。通过 x 和 prev_mouse_x 之间的差异缩放角度,你应该没问题。
int diffx = x - prev_mouse_x;
angle_rad += 0.03 * diffx;
view.x = pos.x + (radius * cos(angle_rad));
view.z = pos.z + (radius * sin(angle_rad));
...
请注意,即使是操作系统层也只会以一定的速率发送鼠标事件,并且您永远无法为每个移动的像素获取单独的事件。
另请注意,由于您没有使用角度而是相机沿 y 轴移动的距离,因此 y 旋转无论如何都不会是恒定的并且感觉很奇怪。
推荐阅读
- java - 将非覆盖派生类方法的方法引用传递给其基类是否合法且已定义?
- php - mail() 命令的命令行太长
- mql4 - ERR_TRADE_NOT_ALLOWED 仅用于调试模式
- python-3.x - 将 f 字符串插值应用于字符串
- java - 如何将xml布局转换为图像?
- javascript - 我无法让选择下拉菜单在我的页面上工作
- javascript - 本地状态的不变性和更新嵌套键
- angular - Angular jQuery Datatable 动态 ngModel 绑定值和服务器过滤或处理 - mData 错误管理
- html - 如何删除 div 之间的空白?
- python - 给定一张叠加图(A^B)和一张原图(A),如何计算另一张原图(B)