QT — Как установить позицию QQuickItem в точном кадре из C ++?

Мое мобильное приложение использует OpenGL под QML парадигма.

Ориентация камеры моей сцены GL синхронизируется с датчиком движения (магнитометр и акселерометр) мобильного устройства. Я также отображаю 2D-метку поверх той 3D-сцены, положение которой на экране должно соответствовать данной 3D-позиции в моей GL-сцене. Эти метки являются обычными элементами QML, которыми я управляю со стороны C ++ моего приложения.

Для этого я делаю прямую связь с QQuickWindow::beforeSynchronising() сигнал, где ориентация камеры синхронизируется с датчиком движения. Затем я проецирую 3D точку на экране, чтобы найти положение метки и, наконец, позвонить QQuickItem::setPosition(),

GL сцена визуализируется как обычно с использованием прямой связи с QQuickWindow::beforeRendering() сигнал.

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, и я думаю, что понимаю почему: QQuickItem::setPosition() из потока QSGRendering, видимо, слишком поздно для QSGNode чтобы получить обновление для этого кадра. Обновление запланировано для этого элемента, но оно не вступит в силу до следующего кадра. Отсюда задержка в 1 кадр.

Вы можете подумать, что это не так уж и плохо, однако, это создает странный эффект и не помогает с чтением того, что на этикетке, потому что глаза также следуют за фоном (помните, что камера синхронизируется с датчиком движения устройства).

Я пытался использовать QQuickWindow::afterAnimating() сигнал, но задержка еще больше. Это нормально, так как этот сигнал испускается из потока GUI, и, таким образом, мы еще меньше контролируем, на какой кадр будет синхронизироваться QSGRenderThread.

Итак, мой вопрос, как я могу добиться позиционирования элемента QML из C ++ в точном кадре? Возможно ли это с помощью QML? Было бы лучше, если бы мои метки были чистыми QQuickItems на C ++ и если бы вместо вызова setPosition () я использовал свою собственную функцию, которая гарантирует, что QSGNode получит обновление?

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
}
1

Другие решения


По вопросам рекламы [email protected]