4

How to use Qt3DRender::QObjectPicker with touch events?

I'm adding Qt3DRender::QObjectPicker component to my Qt3D entities by this method:

Qt3DRender::QObjectPicker *MyClass::createObjectPickerForEntity(Qt3DCore::QEntity *entity)
{
    Qt3DRender::QObjectPicker *picker = new Qt3DRender::QObjectPicker(entity);
    picker->setHoverEnabled(false);
    entity->addComponent(picker);
    connect(picker, &Qt3DRender::QObjectPicker::pressed, this, &MyClass::handlePickerPress);

    return picker;
}

My object picker works with mouse clicks, but it doesn't work with touch events. Does anybody know how I can use Qt3D object picker with touch events on smartphones?

Megidd
  • 7,089
  • 6
  • 65
  • 142
  • 1
    Are you using Qt >= 5.11? In this case you could use [QScreenRayCaster](https://www.kdab.com/new-in-qt-3d-5-11-generalized-ray-casting/) to manually receive the touch events and forward them to the ray caster. – Florian Blume Jan 07 '19 at 13:28
  • @FlorianBlume Thanks! Yes, I'm using version `5.11.3` Actually the link you provided was a great read and I believe it can solve my problem :) – Megidd Jan 08 '19 at 05:56
  • @FlorianBlume I couldn't find any C++ examples of `QRayCaster`. By any chance, do you know C++ code snippets? Thanks! – Megidd Jan 08 '19 at 10:46
  • @FlorianBlume On C++, as far as I understand, I need to add a `QRayCaster` instance to each 3D entity by `addComponent`. Then for every touch/click event, I need to set length/direction/origin for all the `QRayCaster` components and trigger them one by one. I'm not sure! – Megidd Jan 08 '19 at 10:55
  • 1
    I think you need to use the `QScreenRayCaster`, because that's the class that casts a ray from the 2D mouse location into the world. The trick is (if I remember correctly) to add the ray caster as a component to the _root_ entity of your scene graph. – Florian Blume Jan 08 '19 at 12:56
  • 1
    I answered a question about the ray caster [here](https://stackoverflow.com/questions/52666741/qscreenraycaster-not-finding-entity-what-am-i-doiong-wrong/52669324#52669324). – Florian Blume Jan 08 '19 at 12:57
  • @FlorianBlume Wow! I appreciate :) – Megidd Jan 08 '19 at 13:21
  • 1
    I'm glad I could help :) If you have a working solution don't forget to post it. – Florian Blume Jan 09 '19 at 15:18

1 Answers1

4

@FlorianBlume helped me to solve the problem. Touch on Qt3D entities can be detected with QScreenRayCaster. I had to add a QScreenRayCaster component to my root entity:

 /*
  * You have to add the ray caster to the root entity as a component
  * Perform ray casting tests by specifying "touch" coordinates in screen space
  */
    m_screenRayCaster = new Qt3DRender::QScreenRayCaster(m_rootEntity);
    m_screenRayCaster->setRunMode(Qt3DRender::QAbstractRayCaster::SingleShot);
    m_rootEntity->addComponent(m_screenRayCaster);

 /*
  * Handle ray casting results by signal-slot connection
  * "QScreenRayCaster::hitsChanged" signal contains ray casting result for any hit
  * "MyClass::handleScreenRayCasterHits" slot needs to be implemented to handle hit results
  */
    QObject::connect(m_screenRayCaster, &Qt3DRender::QScreenRayCaster::hitsChanged, this, &MyClass::handleScreenRayCasterHits);

I trigger QScreenRayCaster tests by touch events like this using m_screenRayCaster->trigger() method:

void MyClass::HandleTouchEvent(QTouchEvent *event)
{
    switch (event->type()) {
    case QEvent::TouchBegin:
        break;
    case QEvent::TouchEnd:
        if (event->touchPoints().count() == 1) {
            QPointF point = event->touchPoints().at(0).pos();
            m_screenRayCaster->trigger(QPoint(static_cast<int>(point.x()), static_cast<int>(point.y())));
        }
        break;
    default:
        break;
    }

}

Handling ray casting results in MyClass::handleScreenRayCasterHits slot:

void MyClass::handleScreenRayCasterHits(const Qt3DRender::QAbstractRayCaster::Hits hits)
{
    for (int i = 0; i < hits.length(); ++i) {
        qDebug() << __func__ << "Hit Type: " << hits.at(i).type();
        qDebug() << __func__ << "Hit entity name: " << hits.at(i).entity()->objectName();
    }
}
Megidd
  • 7,089
  • 6
  • 65
  • 142