FPS камера вращается сама по себе. QT 4.8 + OpenGL + переполнение стека

Я пытаюсь перенести мою программу визуализации карты высот, написанную на c ++, из SFML в Qt, чтобы она могла отображаться в виджете и контролироваться элементами GUI.

Проблема в том, что когда я запускаю приложение, камера начинает вращаться вокруг своего центра очень быстро (на самом деле это выглядит как сетка ландшафта, летящая вокруг камеры, как Земля вокруг Солнца :), без каких-либо действий с моей стороны ( например, перемещение мыши, нажатие кнопок).

Камера должна двигаться вперед, назад, влево, вправо, когда я нажимаю w, a, s, d, и оглядываться, когда я двигаю мышь (обычное поведение камеры FPS).

Я думаю, что проблема в основном цикле программы, потому что она не является стандартной while(true){ //do something// } Подход в Qt, и это немного сбивает с толку.

Вот мой код:

OGLWidget класс(здесь я рисую вещи. Проблема где-то здесь, я думаю) :

class OGLWidget :
public QGLWidget
{
Q_OBJECT

public:
OGLWidget(QWidget *parent = 0);
~OGLWidget(void);

public:
void paintGL();
void initializeGL();
void resizeGL();

public:
void updateCamera();

public slots:
void mainLoop();

protected:
void keyPressEvent(QKeyEvent *e);
void keyReleaseEvent(QKeyEvent *e);

private:
Terrain _terrain;
Camera  _camera;

private:
int           _keyPressed;
QTimer        _timer;
QElapsedTimer _elapsedTimer;
float         _simulationTime;
float         _fps;
};OGLWidget::OGLWidget(QWidget *parent)  : QGLWidget(parent)
{
_terrain.loadHeightMap("normalHeightMap256_2.png");

_camera.setScreenDimension(this->width(), this->height());

//setting vertical sync
QGLFormat frmt;
frmt.setSwapInterval(1);
setFormat(frmt);

setMouseTracking(true);

setFocus();

_simulationTime = 0;

_fps = 1.f / 60.f;

connect(&_timer, SIGNAL(timeout()), this, SLOT(mainLoop()));
_timer.start();

_elapsedTimer.start();
}OGLWidget::~OGLWidget(void)
{
}

void OGLWidget::mainLoop()
{
_simulationTime += _elapsedTimer.elapsed();
_elapsedTimer.restart();

while(_simulationTime > _fps)
{
_simulationTime -= _fps;
updateCamera();
}

updateGL();
}

void OGLWidget::updateCamera()
{
QPoint p = mapFromGlobal(QCursor::pos());

_camera.computeMatrices(p.x(), p.y(), _fps, _keyPressed);

glm::mat4 ViewMatrix = _camera.getViewMatrix();
glm::mat4 ProjectionMatrix = _camera.getProjectionMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);

_terrain.setMvp(ProjectionMatrix * ViewMatrix * ModelMatrix);

QPoint center = mapToGlobal(QPoint(this->width() / 2, this->height() / 2));
QCursor::setPos(center);
}

void OGLWidget::initializeGL()
{
glewExperimental = GL_TRUE;

if (glewInit() != GLEW_OK)
{
return;
}

glViewport(0, 0, this->width(), this->height());

_terrain.init();
}

void OGLWidget::paintGL()
{
_terrain.draw();
}

void OGLWidget::resizeGL()
{
glViewport(0, 0, this->width(), this->height());
}

void OGLWidget::keyPressEvent(QKeyEvent *e)
{
switch(e->key())
{
case Qt::Key::Key_Escape:
exit(0);
break;

case Qt::Key::Key_W:
_keyPressed = Key::KEY_PRESSED_UP;
break;

case Qt::Key::Key_S:
_keyPressed = Key::KEY_PRESSED_DOWN;
break;

case Qt::Key::Key_A:
_keyPressed = Key::KEY_PRESSED_LEFT;
break;

case Qt::Key::Key_D:
_keyPressed = Key::KEY_PRESSED_RIGHT;
break;
}
}

void OGLWidget::keyReleaseEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key::Key_W ||
e->key() == Qt::Key::Key_S ||
e->key() == Qt::Key::Key_A ||
e->key() == Qt::Key::Key_D)
_keyPressed = KEY_RELEASED;
}

Я абсолютно уверен, что классы Terrain и Camera работают правильно, потому что я не менял код со времени моего проекта SFML (за исключением использования QImage вместо sf :: Image, но он также работает правильно)

*Основной алгоритм камеры: *

void Camera::computeMatrices(int mouseXpos, int mouseYpos, float deltaTime, int keyPressed)
{
_horizontalAngle += _mouseSpeed * deltaTime * float(_screenWidth / 2 - mouseXpos);
_verticalAngle += _mouseSpeed * deltaTime * float(_screenHeight / 2 - mouseYpos);

_direction = glm::vec3
(
cos(_verticalAngle) * sin(_horizontalAngle),
sin(_verticalAngle),
cos(_verticalAngle) * cos(_horizontalAngle)
);

glm::vec3 right = glm::vec3
(
sin(_horizontalAngle - 3.14f/2.0f),
0,
cos(_horizontalAngle - 3.14f/2.0f)
);

glm::vec3 up = glm::cross( right, _direction );

switch(keyPressed)
{
case Key::KEY_PRESSED_UP:
_position += _direction * deltaTime * _speed;
break;

case Key::KEY_PRESSED_DOWN:
_position -= _direction * deltaTime * _speed;
break;

case Key::KEY_PRESSED_LEFT:
_position -= right * deltaTime * _speed;
break;

case Key::KEY_PRESSED_RIGHT:
_position += right * deltaTime * _speed;
break;

case Key::KEY_RELEASED:
break;
}

_projectionMatrix = glm::perspective(_initialFoV, 4.0f / 3.0f, 0.1f, 1000.0f);

_viewMatrix = glm::lookAt
(
_position,            // Camera is here
_position+_direction, // and looks here : at the same position, plus "direction"up                    // Head is up (set to 0,-1,0 to look upside-down)
);
}

Помогите мне решить эту проблему.

0

Решение

Хорошо, я разобрался с проблемой с вращающейся камерой. Причиной этого было то, что я жестко закодировал соотношение сторон в Camera::computeMatricesи использовал разрешение моего виджета, которое не соответствует ему:

_projectionMatrix = glm::perspective
(
_initialFoV,
4.0f / 3.0f, //here it is
0.1f,
1000.0f
);

Я изменился 4.0f / 3.0f на (float)_screenWidth / (float)_screenHeight но это тоже не помогло.

Итак, я просто изменил разрешение моего виджета на 800 x 600 и это помогло.

Новая проблема заключается в том, что работает только на 4/3 габаритах(например 800x600, 1024x768).

0

Другие решения

Лучший способ исправить

_direction = glm::vec3
(
cos(_verticalAngle) * sin(_horizontalAngle),
sin(_verticalAngle),
cos(_verticalAngle) * cos(_horizontalAngle)
);

_direction.normalize();

...
0

По вопросам рекламы [email protected]