首页 > 解决方案 > 为什么 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;
}

标签: c++openglglut

解决方案


您没有考虑鼠标移动距离。当鼠标移动得更快时,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 旋转无论如何都不会是恒定的并且感觉很奇怪。


推荐阅读