Пользовательский рендеринг QtQuick OpenGL

Я использую QtQuick с пользовательским средством визуализации OpenGL (настраиваемым с точки зрения QtQuick, поскольку это просто OpenSceneGraph) . Для этого я создаю пользовательский QQuickItem, наследуемый от QQuickFramebufferObject, который, в свою очередь, создает пользовательский модуль визуализации, наследуемый от QQuickFramebufferObject::Renderer в QQuickFramebufferObject::Renderer strong>QQuickFramebufferObject::createRenderer(). Это хорошо задокументировано, и с этими шагами проблем не возникает.

Теперь происходит то, что для последующего доступа средство визуализации, созданное в QQuickFramebufferObject::createRenderer(), фактически кэшируется (фактически создается в конструкторе QQuickFramebufferObject и просто возвращается в QQuickFramebufferObject::createRenderer(). Это прекрасно работает, и я не вижу другого простого способа закодировать его, поскольку созданный модуль визуализации позже используется для реагирования на такие события, как geometryChanged. или mousePressEvent, например.

////////////////////////////////////////////////////////////////////////////////
void OsgItem::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
{
    if (m_renderer)
        m_renderer->m_window->getEventQueue()->windowResize(newGeometry.x(), newGeometry.y(), newGeometry.width(), newGeometry.height());


    QQuickFramebufferObject::geometryChanged(newGeometry, oldGeometry);
}

////////////////////////////////////////////////////////////////////////////////
void OsgItem::mousePressEvent(QMouseEvent *event)
{
    m_renderer->m_window->getEventQueue()->mouseButtonPress(event->x(), event->y(), button(*event));

    update();
}

, где OsgItem — это мой пользовательский QQuickFramebufferObject, а m_renderer — мой пользовательский QQuickFramebufferObject::Renderer.

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

В чем тут подвох? Есть ли что-то, что я пропустил? Можете ли вы увидеть другой чистый способ, которым я мог бы кодировать вещи?


person arennuit    schedule 08.08.2016    source источник


Ответы (2)


Velkan предоставил принцип интеграции Raw/Custom OpenGL с QQuickFramebufferObject. Поскольку мы только что закончили проект, который также объединяет OSG и QtQuick, я хотел бы поделиться нашим опытом.

Да, конечно, вы никогда не должны кэшировать рендерер. createRenderer является константой по какой-то причине, и именно так команда Qt разработала классы. Согласно нашим экспериментам, функция createRenderer может вызываться несколько раз.

Для синхронизации между QQuickFramebufferObject и его визуализатором мы добавляем QQueue в QQuickFramebufferObject, и когда происходят какие-либо интересующие нас события, мы помещаем их в очередь. А в рендерере при вызове synchronize мы копируем очередь из fbo в рендерер, и выполняем определенные операции в функции render.

person Jimmy Chen    schedule 21.08.2016
comment
Не связанный, но @Jimmy, вы, должно быть, столкнулись с ситуацией: были ли у вас какие-либо проблемы с вертикально перевернутыми 3D-сценами при кодировании этого приложения, о котором вы упоминаете? - person arennuit; 25.08.2017
comment
@arennuit Да, есть. Позвоните setMirrorVertically(true), который действует как шарм :) - person Jimmy Chen; 26.08.2017
comment
Это отлично работает для просмотра и взаимодействия с мышью. Теперь для выбора мне нужно было указать ширину межсектора - y, а не y. Вы тоже с этим сталкивались? Я вообще не могу понять, что происходит... - person arennuit; 26.08.2017

Ну, рендерер получает неконстантный QQuickFramebufferObject в файле synchronize(QQuickFramebufferObject *item).

Это происходит потому, что вы не должны касаться Renderer в потоке графического интерфейса с такими вещами, как mousePressEvent (как я вижу, у Renderer нет никаких функций, которые могут выполняться в потоке графического интерфейса). Renderer::synchronize() выполняется в потоке рендеринга, в то время как поток GUI заблокирован: так что это место для передачи данных.

В общем, поток графического интерфейса должен требовать синхронизации, когда есть что-то изменить из-за ввода. Это приводит к его остановке, а затем в потоке рендеринга вызывается synchronize() для графа сцены. Существует диаграмма синхронизации (не упоминает Renderer, но она должна подчиняться тому же принципу): http://doc.qt.io/qt-5/qtquick-visualcanvas-scenegraph.html

Renderer::render() происходит в потоке рендеринга, в то время как поток GUI работает свободно, насколько я помню. Таким образом, никакие данные не могут быть переданы туда.

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

person Velkan    schedule 08.08.2016