![](/img/trans.png)
[英]How to create QQuickWindow as a child from a C++ extended 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.