为什么 glutPassiveMotionFunc 没有时间处理所有移动鼠标的调用
why the glutPassiveMotionFunc does not have time to process all the calls to move the mouse
我研究 OpenGL 并制作类似 3d 射击游戏的东西。如果您缓慢移动鼠标,则一切正常。如果速度很快,则相机的旋转跟不上鼠标。
以前,这都是写成三个类。我决定简化以优化。也许还有其他需要优化的地方?
main.cpp
#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;
}
game_engine.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
game_engine.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()
{
}
camera.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
camera.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));
...
请注意,即使 OS 层也仅以特定速率发送鼠标事件,您永远无法为每个移动的像素获取单独的事件。
另请注意,由于相机沿 y 轴的移动不是使用角度而是距离,因此 y 轴旋转无论如何都不会恒定,感觉很奇怪。
我研究 OpenGL 并制作类似 3d 射击游戏的东西。如果您缓慢移动鼠标,则一切正常。如果速度很快,则相机的旋转跟不上鼠标。 以前,这都是写成三个类。我决定简化以优化。也许还有其他需要优化的地方?
main.cpp
#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;
}
game_engine.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
game_engine.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()
{
}
camera.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
camera.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));
...
请注意,即使 OS 层也仅以特定速率发送鼠标事件,您永远无法为每个移动的像素获取单独的事件。
另请注意,由于相机沿 y 轴的移动不是使用角度而是距离,因此 y 轴旋转无论如何都不会恒定,感觉很奇怪。