I study OpenGL and make something like 3d shooter. If you move the mouse slowly, then everything works fine. If it is fast, then the rotation of the camera does not keep pace with the mouse. Previously, this was all written in three classes. I decided to simplify in order to optimize. Maybe something else needs to be optimized?
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;
}
You are not taking the mouse move distance into account. When the mouse moves faster, the distance between x and prev_mouse_x will be larger, but you always add 0.3. Scale the angle by the difference beteween x and prev_mouse_x and you should be fine.
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));
...
Note, that even the OS layer only sends mouse events at a certain rate and you will never be able to get a separate event for each moved pixel.
Also note, that since you are not using angles but distances for the camera movement along the y axis, the y-rotation will not be constant anyway and feel strange.