ObjectPicker не работает для динамически созданного объекта, если еще нет другого объекта с ObjectPicker - PullRequest
4 голосов
/ 03 марта 2020

У меня есть Scene3D, где я динамически добавляю сущность, которая имеет ObjectPicker, через слот этого класса помощника 'Scene3DViewHelper::addCuboid():

scene3dviewhelper.h:

#ifndef SCENE3DVIEWHELPER_H
#define SCENE3DVIEWHELPER_H

#include <Qt3DCore/QEntity>

class Scene3DViewHelper : public QObject
{
    Q_OBJECT
public:
    Q_PROPERTY(Qt3DCore::QEntity * rootEntity READ rootEntity WRITE setRootEntity NOTIFY rootEntityChanged)

    explicit Scene3DViewHelper(QObject *parent = nullptr);

    Qt3DCore::QEntity * rootEntity() const;

public slots:
    void setRootEntity(Qt3DCore::QEntity *rootEntity);
    void addCuboid();

signals:
    void rootEntityChanged(Qt3DCore::QEntity *rootEntity);

private:
    Qt3DCore::QEntity *rootEntity_;
};

#endif // SCENE3DVIEWHELPER_H

scene3dviewhelper. cpp:

#include "scene3dviewhelper.h"
#include <Qt3DCore>
#include <Qt3DRender>
#include <Qt3DExtras>

Scene3DViewHelper::Scene3DViewHelper(QObject *parent) : QObject(parent) {}

Qt3DCore::QEntity * Scene3DViewHelper::rootEntity() const { return rootEntity_; }

void Scene3DViewHelper::setRootEntity(Qt3DCore::QEntity *rootEntity)
{
    auto old = rootEntity_;
    rootEntity_ = rootEntity;
    if(rootEntity_ != old) emit rootEntityChanged(rootEntity);
}

void Scene3DViewHelper::addCuboid()
{
    if(!rootEntity_) return;
    auto cuboidEntity = new Qt3DCore::QEntity(rootEntity_);
    auto mat = new Qt3DExtras::QPhongMaterial(cuboidEntity);
    mat->setDiffuse(QColor(217, 217, 255));
    auto t = new Qt3DCore::QTransform(cuboidEntity);
    auto mesh = new Qt3DExtras::QCuboidMesh(cuboidEntity);
    auto picker = new Qt3DRender::QObjectPicker(cuboidEntity);
    connect(picker, &Qt3DRender::QObjectPicker::clicked, [=] {
        qDebug() << "clicked entity" << cuboidEntity;
    });
    mesh->setXExtent(1);
    mesh->setYExtent(1);
    mesh->setZExtent(1);
    cuboidEntity->addComponent(mat);
    cuboidEntity->addComponent(t);
    cuboidEntity->addComponent(mesh);
    cuboidEntity->addComponent(picker);
}

Scene3DView.qml:

import QtQuick.Scene3D 2.0
import Qt3D.Core 2.0
import Qt3D.Render 2.14
import Qt3D.Input 2.0
import Qt3D.Logic 2.0
import Qt3D.Extras 2.0

import Qt3DUtils 1.0

Scene3D {
    id: scene3d
    aspects: ["render", "logic", "input"]
    hoverEnabled: true // needed for ObjectPickers to handle hover events
    property alias helper: helper

    data: Scene3DViewHelper {
        id: helper
        rootEntity: rootEntity
    }

    entity: Entity {
        id: rootEntity
        components: [
            RenderSettings {
                ForwardRenderer {
                    id: forwardRenderer
                    camera: mainCamera
                }
                pickingSettings.pickMethod: PickingSettings.TrianglePicking
                pickingSettings.pickResultMode: PickingSettings.AllPicks
                pickingSettings.faceOrientationPickingMode: PickingSettings.FrontAndBackFace
            },
            InputSettings {}
        ]

        Camera {
            id: mainCamera
            projectionType: CameraLens.PerspectiveProjection
            fieldOfView: 45
            aspectRatio: 16/9
            nearPlane : 0.1
            farPlane : 1000.0
            position: Qt.vector3d(0.0, 0.0, -4.0)
            upVector: Qt.vector3d(0.0, 1.0, 0.0)
            viewCenter: Qt.vector3d(0.0, 0.5, 0.0)
        }

        /*Entity {
            id: cuboid0
            components: [
                CuboidMesh {
                    xExtent: 1
                    yExtent: 1
                    zExtent: 1
                },
                Transform {
                    translation.x: -1.5
                },
                PhongMaterial {
                    diffuse: Qt.rgba(0.85, 0.85, 1, 1)
                },
                ObjectPicker {
                    onClicked: console.log("clicked entity", cuboid0)
                }
            ]
        }*/
    }
}

main.qml:

import QtQuick.Window 2.13 as QtQuick

ApplicationWindow {
    id: mainWindow
    visible: true
    width: 1000
    height: 700

    MainMenu {
        onAddCuboid: scene3d.helper.addCuboid()
    }

    Scene3DView {
        id: scene3d
        anchors.fill: parent
    }
}

main. cpp:

#include <QApplication>
#include <QQmlApplicationEngine>

#include "scene3dviewhelper.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);
    qmlRegisterType<Scene3DViewHelper>("Qt3DUtils", 1, 0, "Scene3DViewHelper");
    const QUrl mainUrl(QStringLiteral("qrc:/main.qml"));
    QQmlApplicationEngine engine;
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [&](QObject *obj, const QUrl &objUrl) {
        if(!obj && mainUrl == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(mainUrl);
    return app.exec();
}

Проблема в том, что ObjectPicker не работает: я должен видеть сообщение "clicked entity Qt3DCore :: QEntity (0x7fa19f005300)" на консоли, когда я нажимаю на кубоид, но я не вижу его.

Если я раскомментирую сущность cuboid0, тогда выбор будет работать как для сущности cuboid0, так и для динамически создаваемого кубоида:

qml: clicked entity Qt3DCore :: Quick :: Quick3DEntity (0x7fa0d7c025e0)

щелкнувшая сущность Qt3DCore :: QEntity (0x7fa0d6527f10)

Что делает создание сущности в QML, чего я не делаю в void Scene3DViewHelper::addCuboid()

...