#c #opengl
#c #opengl
Вопрос:
Я хочу сделать что-то вроде 3D-шутера. Расчеты кажутся правильными, но это работает через раз с разбросом с поворотом на 180 градусов при каждом вызове glutPostRedisplay(). Я понял это благодаря этой красной строке. Я делаю это с помощью такой IDE: Code Blocks / Qt Creator под Linux (Ubuntu x64).
main.cpp
#include "Functions.h"
int main(int argc, char** argv)
{
glutInit(amp;argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(wnd_width, wnd_height);
glutInitWindowPosition(300, 100);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
glutCreateWindow("OpenGL my");
glutDisplayFunc(display);
glutIdleFunc(Idle);
glutSpecialFunc(KeyPressed);
GLdouble aspect = wnd_width/wnd_height;
gluPerspective(90, aspect, 0.1, 10);
glTranslatef(0, -0.3, 0);
glutMainLoop();
return 0;
}
Functions.h
#include <GL/glut.h>
#include <math.h>
#include <iostream>
int wnd_width=1300;
int wnd_height=900;
float pos_x=0, pos_z=0.1;
float angle = 0;
float speed = 0.1;
void DrawFloor(){
glVertex3d(1, 0, 2.5);
glVertex3d(1, 0, 0);
glVertex3d(-1, 0, 0);
glVertex3d(-1, 0, 2.5);
}
void DrawWall(float x, float width, float height){
glVertex3f(x, height, 0);
glVertex3f(x, height, width);
glVertex3f(x, 0, width);
glVertex3f(x, 0, 0);
}
void DrawLine(){
glVertex3f(0, 0.1, -1);
glVertex3f(0, 0.1, 1);
}
void KeyPressed(int key, int x, int y){
switch (key) {
case GLUT_KEY_UP: {
//pos_x = speed * cos(3.14*angle/180);
//pos_z = speed * sin(3.14*angle/180);
pos_z =0.1;
break;
}
case GLUT_KEY_DOWN: {
pos_x = speed*cos(angle);
pos_z = speed*sin(angle);
break;
}
case GLUT_KEY_LEFT: {
angle = 1;
pos_x = speed * cos(3.14 * angle/180);
pos_z = speed * sin(3.14 * angle/180);
break;
}
case GLUT_KEY_RIGHT: {
angle -= 3;
pos_x = speed * cos(3.14 * angle/180);
pos_z = speed * sin(3.14 * angle/180);
break;
}
}
std::cout<<"x: "<<pos_x<<'t';
std::cout<<"z: "<<pos_z<<'n';
glutPostRedisplay();
}
void display(){
glClearColor(0.6, 0.8, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z 0.2, 0, 1, 0);
glBegin(GL_QUADS);
glColor3f(0, 0, 0.7);
DrawFloor();
glColor3f(0, 0.8, 0.1);
DrawWall(-0.5, 2, 0.7);
DrawWall(0.5, 2, 0.7);
glEnd();
glLineWidth(2);
glColor3f(0.7, 0.2, 0.2);
glBegin(GL_LINES);
DrawLine();
glEnd();
glutSwapBuffers();
}
void Idle(){
//pos_z =0.01;
//glutPostRedisplay();
}
Комментарии:
1. разве не
pos_x = ???
следует ссылаться на старую позицию? нравитсяpos.x = pos.x speed.x
?
Ответ №1:
Вы используете фиксированный стек функций, поэтому вам придется изучить, что glMatrixMode
и как матрицы преобразования управляются этими старыми способами.
В любом случае, рассмотрите это как возможную реализацию glMatrixMode
void glMatrixMode(GLenum m)
{
switch(m){
case GL_MODELVIEW: ctx->M = amp;ctx->matrix_modelview; break;
case GL_PROJECTION: ctx->M = amp;ctx->matrix_projection; break;
case GL_TEXTURE: ctx->M = amp;ctx->matrix_texture; break;
case GL_COLOR: ctx->M = amp;ctx->matrix_color; break;
}
}
Другими словами, существует (контекстная) глобальная матрица, выбранная с glMatrixMode
помощью , которая впоследствии используется для всех последующих манипуляций с матрицей.
Следовательно, glMatrixMode
это не какая-то форма инициализации, а то, что вы используете для переключения (часто несколько раз) во время рендеринга кадра! Ваше использование его в main
функции в некотором роде бессмысленно. Вы должны использовать его в своей функции рисования.
Кроме того, каждая манипуляция с матрицей умножается поверх того, что есть в данный момент ctx->M
. gluLookAt
обычно используется с идентификационной матрицей. Если вы не сбросите свою личность, это gluLookAt
будет работать по сравнению с предыдущим просмотром. Итак, что вы хотите, это:
void display(){
glClearColor(0.6, 0.8, 1., 1.); /* <<<----* */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTIOM);
glLoadIdentity();
setup_projection_here();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z 0.2, 0, 1, 0);
glBegin(GL_QUADS);
/* ... */
glutSwapBuffers();
}
(*) Кроме того, вы обычно хотите очистить alpha = 1
в главном фреймбуфере, если только вы не планируете рисовать изображения, полупрозрачные в окне. В alpha = 0
окне все может выглядеть правильно, но если сделан снимок экрана или используется какая-либо запись экрана или совместное использование, это может привести к нежелательной прозрачности.