【问题标题】:How to set the QQuickItem position at a precise frame from C++?如何在 C++ 的精确帧处设置 QQuickItem 位置?
【发布时间】:2015-06-06 23:05:47
【问题描述】:

我的移动应用程序在QML 范式下使用OpenGL

我的 GL 场景的相机方向与移动设备的运动传感器(磁力计和加速度计)同步。我还在那个 3D 场景的顶部显示了一个 2D 标签,它在屏幕上的位置需要对应于我的 GL 场景中的给定 3D 位置。这些标签是我从应用程序的 C++ 端控制的常规 QML 项。

为此,我直接连接到QQuickWindow::beforeSynchronising() 信号,其中相机方向与运动传感器同步。然后我在屏幕上投影一个 3D 点来查找标签的位置,最后调用QQuickItem::setPosition()

使用与QQuickWindow::beforeRendering() 信号的直接连接,照常渲染 GL 场景。

MyAppController::MyAppController() : QObject() {
    connect(window, SIGNAL(beforeSynchronising()), this, SLOT(sync()), Qt::DirectConnection);
    connect(window, SIGNAL(beforeRendering()), this, SLOT(render()), Qt::DirectConnection);

    m_camera = ...; // create camera
    m_scene = ...;  // create GL scene
    m_quickItem = ...; // load label QML item

    // start updating the window at a constant frame rate
    QTimer* timer = new QTimer(this);
    connect (timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(1000.0 / 60.0);   // 60 FPS
}

MyAppController::sync() {
    m_camera->syncWithMotionSensor();

    // use camera matrix to calculate the projection of a 3D point on the screen
    QPointF pos = ...;  
    m_quickItem->setPosition(pos);  // set the label position
}

MyAppController::render() {
    m_scene->draw(); // OpenGL code
}

一切都很好,除了与我的 GL 场景相比,我的标签似乎晚了一帧,我想我明白为什么:从 QSGRendering 线程调用 QQuickItem::setPosition() 显然太晚了,QSGNode 无法更新对于那个框架。为该项目安排了更新,但直到下一帧才会生效。因此有 1 帧延迟。

您可能认为这还不错,但是,它确实会产生一种奇怪的效果,并且无助于阅读标签上的内容,因为眼睛也在跟随背景(请记住相机与设备运动传感器同步) .

我尝试使用QQuickWindow::afterAnimating() 信号,但延迟更大。这是正常的,因为这个信号是从 GUI 线程发出的,因此我们对 QSGRenderThread 将同步哪个帧的控制更少。

所以我的问题是,我怎样才能从 C++ 中将 QML 项目定位在精确的框架上?这甚至可以使用 QML 吗?如果我的标签是纯 C++ QQuickItems 并且我使用自己的函数而不是调用 setPosition() 来确保 QSGNode 将接收更新,那会更好吗?

【问题讨论】:

    标签: c++ qt opengl qml core-motion


    【解决方案1】:

    所以答案是在渲染 GL 场景之后简单地同步相机和标签的位置。这样我们就可以确定在下一帧标签的位置将被考虑在内。 最终解决方案如下所示:

    MyAppController::sync() {
        m_scene->prepare();  // uses the camera matrix from previous frame    
        m_camera->syncWithMotionSensor();  // update camera matrix
        // use camera matrix to calculate the projection of a 3D point on the screen
        QPointF pos = ...;  
        m_quickItem->setPosition(pos);  // set the label position, will be updated on the next frame
    }
    
    MyAppController::render() {
        m_scene->draw(); // execute OpenGL code
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多