【发布时间】: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