【问题标题】:FPS camera rotating by itself. QT 4.8 + OpenGL + C++FPS 相机自行旋转。 QT 4.8 + OpenGL + C++
【发布时间】: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


【解决方案1】:

好的,我发现了旋转相机的问题。原因是我在Camera::computeMatrices 中硬编码了纵横比,并使用了与它不匹配的小部件分辨率:

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

我在(float)_screenWidth / (float)_screenHeight 上更改了4.0f / 3.0f,但也没有用。

所以我只是将我的小部件的分辨率更改为800 x 600 并且它有所帮助。

新的问题是它只适用于 4/3 维度(例如 800x6001024x768)。

【讨论】:

  • 将此标记为您的问题的答案并将新问题发布为新主题。
【解决方案2】:

最好的纠正方法

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

_direction.normalize();

...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 2023-03-12
    • 2017-06-07
    • 1970-01-01
    • 2014-03-22
    • 2022-01-01
    • 1970-01-01
    相关资源
    最近更新 更多