繁体   English   中英

如何在C ++中的精确帧处设置QQuickItem位置?

[英]How to set the QQuickItem position at a precise frame from C++?

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

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

为此,我直接连接到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更好,并且不是使用我自己的函数来确保QSGNode能够接收更新,而不是调用setPosition()呢?

因此,答案是渲染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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM