我的移动应用程序使用OpenGL
范例下的QML
。
我的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()
对于{{1}来说显然为时已晚获取该帧的更新。计划对该项目进行更新,但直到下一帧才生效。因此1帧延迟。
你可能认为它并没有那么糟糕,然而,它确实产生了一种奇怪的效果,并且无助于阅读标签上的内容,因为眼睛也跟着背景(记住相机)与设备运动传感器同步。
我尝试使用QSGNode
信号,但延迟更大。这是正常的,因为此信号是从GUI线程发出的,因此我们对QSGRenderThread将同步到哪个帧的控制更少。
所以我的问题是,如何在精确的框架中实现C ++中QML项目的定位?这甚至可以使用QML吗?如果我的标签是纯C ++ QQuickItems并且如果不是调用setPosition()而是使用我自己的函数来确保QSGNode将接收更新,那会更好吗?
答案 0 :(得分: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
}