【发布时间】:2014-03-10 00:33:14
【问题描述】:
我正在尝试将我用 c++ 编写的高度图可视化程序从 SFML 移植到 Qt,以便它可以显示在小部件上并由 GUI 元素控制。
问题是当我启动一个应用程序时,一个相机开始非常快速地围绕它的中心滚动(实际上,它看起来像一个围绕相机飞行的地形网格,就像一个围绕太阳的地球:),没有任何动作我这边(例如移动鼠标、按下按钮)。
当我按下 w、a、s、d 时,相机应该向前、向后、向左、向右移动,并在我移动鼠标时环顾四周(只是典型的 FPS 相机行为)。
我认为问题出在程序的主循环中,因为它在 qt 中不是标准的while(true){ //do something// } 方法,而且有点令人困惑。
这是我的代码:
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)
);
}
帮我解决这个问题。
【问题讨论】:
-
您向我们倾倒了大量代码 - 请提供能证明问题的最少代码量。
-
我更正了帖子,感谢您的评论。我认为问题出在 OGLWidget 类中。我认为我在程序的主循环管理中做错了什么。
-
@RusselLedge:您是否尝试过不触摸鼠标或改变其物理位置?
-
@legends2k:是的,我只是启动了一个程序,没有触摸任何控件。顺便说一句,如果我在“Camera::computeMatrices”中将 0 作为第三个参数传递,图像会静止。所以这里的定时器和循环有问题,但我不知道是什么。
-
@RusselLedge:你真的应该尝试使用调试器;毕竟 QtCreator 有一个很好的用于调试的 GUI 界面,你可以在这里好好利用它。
_keyPressed似乎在您的类的构造函数中未初始化。
标签: c++ qt opengl camera game-loop