簡體   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