summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2020-07-16 13:35:15 +0100
committerMike Krus <mike.krus@kdab.com>2020-07-30 12:02:39 +0100
commiteb728b5501f0ffb61ca4916ff5975c496ab98970 (patch)
tree3c2652354b99e057460455ba94e478410c19b4df
parent3411f202fdfd6e3c69421ae143013920a65704ee (diff)
Add support for synchronous picking
World space and screen space raycasters gain method to do a pick query synchronously, returning the list of hits. Change-Id: I41cc3940b8d97c3619456d76127841907a9170cb Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r--src/quick3d/quick3drender/items/quick3draycaster.cpp76
-rw-r--r--src/quick3d/quick3drender/items/quick3draycaster_p.h7
-rw-r--r--src/quick3d/quick3drender/items/quick3draycaster_p_p.h7
-rw-r--r--src/quick3d/quick3drender/items/quick3dscreenraycaster.cpp21
-rw-r--r--src/quick3d/quick3drender/items/quick3dscreenraycaster_p.h9
-rw-r--r--src/quick3d/quick3drender/items/quick3dscreenraycaster_p_p.h5
-rw-r--r--src/render/jobs/raycastingjob.cpp76
-rw-r--r--src/render/jobs/raycastingjob_p.h3
-rw-r--r--src/render/picking/qabstractraycaster.cpp22
-rw-r--r--src/render/picking/qabstractraycaster_p.h1
-rw-r--r--src/render/picking/qraycaster.cpp10
-rw-r--r--src/render/picking/qraycaster.h2
-rw-r--r--src/render/picking/qraycasterhit.cpp38
-rw-r--r--src/render/picking/qraycasterhit.h12
-rw-r--r--src/render/picking/qscreenraycaster.cpp8
-rw-r--r--src/render/picking/qscreenraycaster.h2
-rw-r--r--tests/manual/raycasting-qml/CMakeLists.txt18
-rw-r--r--tests/manual/raycasting-qml/LineEntity.qml1
-rw-r--r--tests/manual/raycasting-qml/main.qml4
19 files changed, 175 insertions, 147 deletions
diff --git a/src/quick3d/quick3drender/items/quick3draycaster.cpp b/src/quick3d/quick3drender/items/quick3draycaster.cpp
index b8f086983..d0c282a1c 100644
--- a/src/quick3d/quick3drender/items/quick3draycaster.cpp
+++ b/src/quick3d/quick3drender/items/quick3draycaster.cpp
@@ -43,78 +43,12 @@
#include <Qt3DCore/QEntity>
-#include <QQmlEngine>
-#include <QJSValue>
-
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
namespace Quick {
-void Quick3DRayCasterPrivate::dispatchHits(const QAbstractRayCaster::Hits &hits)
-{
- m_hits = hits;
- updateHitEntites(m_hits, m_scene);
-
- Q_Q(Quick3DRayCaster);
- if (!m_engine)
- m_engine = qmlEngine(q->parent());
-
- m_jsHits = convertHits(m_hits, m_engine);
-
- bool v = q->blockNotifications(true);
- emit q->hitsChanged(m_jsHits);
- q->blockNotifications(v);
-}
-
-QJSValue Quick3DRayCasterPrivate::convertHits(const QAbstractRayCaster::Hits &hits, QQmlEngine *engine)
-{
- auto jsHits = engine->newArray(hits.length());
- for (int i=0; i<hits.size(); i++) {
- QJSValue v = engine->newObject();
- v.setProperty(QLatin1String("type"), hits[i].type());
- v.setProperty(QLatin1String("entity"), engine->newQObject(hits[i].entity()));
- v.setProperty(QLatin1String("distance"), hits[i].distance());
- {
- QJSValue p = engine->newObject();
- p.setProperty(QLatin1String("x"), hits[i].localIntersection().x());
- p.setProperty(QLatin1String("y"), hits[i].localIntersection().y());
- p.setProperty(QLatin1String("z"), hits[i].localIntersection().z());
- v.setProperty(QLatin1String("localIntersection"), p);
- }
- {
- QJSValue p = engine->newObject();
- p.setProperty(QLatin1String("x"), hits[i].worldIntersection().x());
- p.setProperty(QLatin1String("y"), hits[i].worldIntersection().y());
- p.setProperty(QLatin1String("z"), hits[i].worldIntersection().z());
- v.setProperty(QLatin1String("worldIntersection"), p);
- }
-
- switch (hits[i].type()) {
- case Qt3DRender::QRayCasterHit::TriangleHit:
- v.setProperty(QLatin1String("primitiveIndex"), hits[i].primitiveIndex());
- v.setProperty(QLatin1String("vertex1Index"), hits[i].vertex1Index());
- v.setProperty(QLatin1String("vertex2Index"), hits[i].vertex2Index());
- v.setProperty(QLatin1String("vertex3Index"), hits[i].vertex3Index());
- break;
- case Qt3DRender::QRayCasterHit::LineHit:
- v.setProperty(QLatin1String("primitiveIndex"), hits[i].primitiveIndex());
- v.setProperty(QLatin1String("vertex1Index"), hits[i].vertex1Index());
- v.setProperty(QLatin1String("vertex2Index"), hits[i].vertex2Index());
- break;
- case Qt3DRender::QRayCasterHit::PointHit:
- v.setProperty(QLatin1String("primitiveIndex"), hits[i].primitiveIndex());
- break;
- default: break;
- }
-
- jsHits.setProperty(i, v);
- }
-
- return jsHits;
-}
-
void Quick3DRayCasterPrivate::appendLayer(QQmlListProperty<QLayer> *list, QLayer *layer)
{
QAbstractRayCaster *filter = qobject_cast<QAbstractRayCaster *>(list->object);
@@ -134,7 +68,7 @@ int Quick3DRayCasterPrivate::layerCount(QQmlListProperty<QLayer> *list)
{
QAbstractRayCaster *filter = qobject_cast<QAbstractRayCaster *>(list->object);
if (filter)
- return filter->layers().count();
+ return int(filter->layers().size());
return 0;
}
@@ -153,15 +87,9 @@ Quick3DRayCaster::Quick3DRayCaster(QObject *parent)
{
}
-QJSValue Quick3DRayCaster::hits() const
-{
- Q_D(const Quick3DRayCaster);
- return d->m_jsHits;
-}
-
QQmlListProperty<Qt3DRender::QLayer> Qt3DRender::Render::Quick::Quick3DRayCaster::qmlLayers()
{
- return QQmlListProperty<QLayer>(this, 0,
+ return QQmlListProperty<QLayer>(this, nullptr,
&Quick3DRayCasterPrivate::appendLayer,
&Quick3DRayCasterPrivate::layerCount,
&Quick3DRayCasterPrivate::layerAt,
diff --git a/src/quick3d/quick3drender/items/quick3draycaster_p.h b/src/quick3d/quick3drender/items/quick3draycaster_p.h
index 31778dc3b..20a55a7bb 100644
--- a/src/quick3d/quick3drender/items/quick3draycaster_p.h
+++ b/src/quick3d/quick3drender/items/quick3draycaster_p.h
@@ -69,17 +69,12 @@ class Quick3DRayCasterPrivate;
class Q_3DQUICKRENDERSHARED_PRIVATE_EXPORT Quick3DRayCaster : public QRayCaster
{
Q_OBJECT
- Q_PROPERTY(QJSValue hits READ hits NOTIFY hitsChanged)
Q_PROPERTY(QQmlListProperty<Qt3DRender::QLayer> layers READ qmlLayers)
public:
- explicit Quick3DRayCaster(QObject *parent = 0);
+ explicit Quick3DRayCaster(QObject *parent = nullptr);
- QJSValue hits() const;
QQmlListProperty<QLayer> qmlLayers();
-Q_SIGNALS:
- void hitsChanged(const QJSValue &hits);
-
private:
Q_DECLARE_PRIVATE(Quick3DRayCaster)
};
diff --git a/src/quick3d/quick3drender/items/quick3draycaster_p_p.h b/src/quick3d/quick3drender/items/quick3draycaster_p_p.h
index ef875eb43..dec8dcfb6 100644
--- a/src/quick3d/quick3drender/items/quick3draycaster_p_p.h
+++ b/src/quick3d/quick3drender/items/quick3draycaster_p_p.h
@@ -57,8 +57,6 @@
#include <Qt3DQuickRender/private/quick3draycaster_p.h>
#include <Qt3DQuick/private/quick3dnode_p.h>
-#include <QtQml/QJSValue>
-
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -70,11 +68,6 @@ class Q_3DQUICKRENDERSHARED_PRIVATE_EXPORT Quick3DRayCasterPrivate : public QAbs
public:
explicit Quick3DRayCasterPrivate() : QAbstractRayCasterPrivate() { }
- QJSValue m_jsHits;
- QQmlEngine *m_engine = nullptr;
-
- void dispatchHits(const QAbstractRayCaster::Hits &hits) override;
- static QJSValue convertHits(const QAbstractRayCaster::Hits &hits, QQmlEngine *engine);
static void appendLayer(QQmlListProperty<QLayer> *list, QLayer *bar);
static QLayer *layerAt(QQmlListProperty<QLayer> *list, int index);
static int layerCount(QQmlListProperty<QLayer> *list);
diff --git a/src/quick3d/quick3drender/items/quick3dscreenraycaster.cpp b/src/quick3d/quick3drender/items/quick3dscreenraycaster.cpp
index dd3d1f758..03d6268c3 100644
--- a/src/quick3d/quick3drender/items/quick3dscreenraycaster.cpp
+++ b/src/quick3d/quick3drender/items/quick3dscreenraycaster.cpp
@@ -53,33 +53,14 @@ namespace Qt3DRender {
namespace Render {
namespace Quick {
-void Quick3DScreenRayCasterPrivate::dispatchHits(const QAbstractRayCaster::Hits &hits)
-{
- m_hits = hits;
- updateHitEntites(m_hits, m_scene);
-
- Q_Q(Quick3DScreenRayCaster);
- if (!m_engine)
- m_engine = qmlEngine(q->parent());
-
- m_jsHits = Quick3DRayCasterPrivate::convertHits(m_hits, m_engine);
- emit q->hitsChanged(m_jsHits);
-}
-
Quick3DScreenRayCaster::Quick3DScreenRayCaster(QObject *parent)
: QScreenRayCaster(*new Quick3DScreenRayCasterPrivate(), qobject_cast<Qt3DCore::QNode *>(parent))
{
}
-QJSValue Quick3DScreenRayCaster::hits() const
-{
- Q_D(const Quick3DScreenRayCaster);
- return d->m_jsHits;
-}
-
QQmlListProperty<Qt3DRender::QLayer> Qt3DRender::Render::Quick::Quick3DScreenRayCaster::qmlLayers()
{
- return QQmlListProperty<QLayer>(this, 0,
+ return QQmlListProperty<QLayer>(this, nullptr,
&Quick3DRayCasterPrivate::appendLayer,
&Quick3DRayCasterPrivate::layerCount,
&Quick3DRayCasterPrivate::layerAt,
diff --git a/src/quick3d/quick3drender/items/quick3dscreenraycaster_p.h b/src/quick3d/quick3drender/items/quick3dscreenraycaster_p.h
index 63d3f0428..4f1f19a1c 100644
--- a/src/quick3d/quick3drender/items/quick3dscreenraycaster_p.h
+++ b/src/quick3d/quick3drender/items/quick3dscreenraycaster_p.h
@@ -56,8 +56,6 @@
#include <Qt3DQuickRender/private/qt3dquickrender_global_p.h>
#include <Qt3DQuick/private/quick3dnode_p.h>
-#include <QtQml/QJSValue>
-
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -69,17 +67,12 @@ class Quick3DScreenRayCasterPrivate;
class Q_3DQUICKRENDERSHARED_PRIVATE_EXPORT Quick3DScreenRayCaster : public QScreenRayCaster
{
Q_OBJECT
- Q_PROPERTY(QJSValue hits READ hits NOTIFY hitsChanged)
Q_PROPERTY(QQmlListProperty<Qt3DRender::QLayer> layers READ qmlLayers)
public:
- explicit Quick3DScreenRayCaster(QObject *parent = 0);
+ explicit Quick3DScreenRayCaster(QObject *parent = nullptr);
- QJSValue hits() const;
QQmlListProperty<QLayer> qmlLayers();
-Q_SIGNALS:
- void hitsChanged(const QJSValue &hits);
-
private:
Q_DECLARE_PRIVATE(Quick3DScreenRayCaster)
};
diff --git a/src/quick3d/quick3drender/items/quick3dscreenraycaster_p_p.h b/src/quick3d/quick3drender/items/quick3dscreenraycaster_p_p.h
index ad5d0b941..e84430a7b 100644
--- a/src/quick3d/quick3drender/items/quick3dscreenraycaster_p_p.h
+++ b/src/quick3d/quick3drender/items/quick3dscreenraycaster_p_p.h
@@ -71,11 +71,6 @@ class Q_3DQUICKRENDERSHARED_PRIVATE_EXPORT Quick3DScreenRayCasterPrivate : publi
public:
explicit Quick3DScreenRayCasterPrivate() : QAbstractRayCasterPrivate() { }
- QJSValue m_jsHits;
- QQmlEngine *m_engine = nullptr;
-
- void dispatchHits(const QAbstractRayCaster::Hits &hits) override;
-
Q_DECLARE_PUBLIC(Quick3DScreenRayCaster)
};
diff --git a/src/render/jobs/raycastingjob.cpp b/src/render/jobs/raycastingjob.cpp
index 3718928b4..7c7ddc71a 100644
--- a/src/render/jobs/raycastingjob.cpp
+++ b/src/render/jobs/raycastingjob.cpp
@@ -66,13 +66,17 @@ class EntityCasterGatherer : public EntityVisitor
public:
using EntityCasterList = QList<QPair<Entity *, RayCaster *>>;
EntityCasterList m_result;
+ RayCaster *m_trigger;
- explicit EntityCasterGatherer(NodeManagers *manager) : EntityVisitor(manager) { setPruneDisabled(true); }
+ explicit EntityCasterGatherer(NodeManagers *manager, RayCaster *trigger = nullptr)
+ : EntityVisitor(manager), m_trigger(trigger) {
+ setPruneDisabled(true);
+ }
Operation visit(Entity *entity) override {
const std::vector<RayCaster *> &components = entity->renderComponents<RayCaster>();
for (const auto c: components) {
- if (c->isEnabled())
+ if ((m_trigger == nullptr && c->isEnabled()) || (m_trigger != nullptr && m_trigger == c))
m_result.push_back(qMakePair(entity, c));
}
@@ -159,22 +163,17 @@ bool RayCastingJob::runHelper()
if (!m_oneEnabledAtLeast)
return false;
- const bool trianglePickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::TrianglePicking);
- const bool edgePickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::LinePicking);
- const bool pointPickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::PointPicking);
- const bool primitivePickingRequested = pointPickingRequested | edgePickingRequested | trianglePickingRequested;
- const bool frontFaceRequested =
- m_renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace;
- const bool backFaceRequested =
- m_renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace;
- const float pickWorldSpaceTolerance = m_renderSettings->pickWorldSpaceTolerance();
-
EntityCasterGatherer gatherer(m_manager);
gatherer.apply(m_node);
const EntityCasterGatherer::EntityCasterList &entities = gatherer.m_result;
+ return pick(entities);
+}
- PickingUtils::ViewportCameraAreaGatherer vcaGatherer;
- const std::vector<PickingUtils::ViewportCameraAreaDetails> &vcaDetails = vcaGatherer.gather(m_frameGraphRoot);
+bool RayCastingJob::pick(const QList<QPair<Entity *, RayCaster *>> &entities)
+{
+ const PickingUtils::PickConfiguration pickConfiguration(m_frameGraphRoot, m_renderSettings);
+ if (pickConfiguration.vcaDetails.empty())
+ return false;
const float sceneRayLength = m_node->worldBoundingVolumeWithChildren()->radius() * 3.f;
@@ -189,7 +188,7 @@ bool RayCastingJob::runHelper()
rays.back().transform(*pair.first->worldTransform());
break;
case QAbstractRayCasterPrivate::ScreenScapeRayCaster:
- for (const PickingUtils::ViewportCameraAreaDetails &vca : vcaDetails) {
+ for (const PickingUtils::ViewportCameraAreaDetails &vca : pickConfiguration.vcaDetails) {
const auto ray = rayForViewportAndCamera(vca, nullptr, pair.second->position());
if (ray.isValid())
rays.push_back(ray);
@@ -204,10 +203,10 @@ bool RayCastingJob::runHelper()
PickingUtils::HierarchicalEntityPicker entityPicker(ray, false);
entityPicker.setFilterLayers(pair.second->layerIds(), pair.second->filterMode());
if (entityPicker.collectHits(m_manager, m_node)) {
- if (trianglePickingRequested) {
+ if (pickConfiguration.trianglePickingRequested) {
PickingUtils::TriangleCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_frontFaceRequested = frontFaceRequested;
- gathererFunctor.m_backFaceRequested = backFaceRequested;
+ gathererFunctor.m_frontFaceRequested = pickConfiguration.frontFaceRequested;
+ gathererFunctor.m_backFaceRequested = pickConfiguration.backFaceRequested;
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
gathererFunctor.m_objectPickersRequired = false;
@@ -216,11 +215,11 @@ bool RayCastingJob::runHelper()
std::make_move_iterator(hits.begin()),
std::make_move_iterator(hits.end()));
}
- if (edgePickingRequested) {
+ if (pickConfiguration.edgePickingRequested) {
PickingUtils::LineCollisionGathererFunctor gathererFunctor;
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
- gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
+ gathererFunctor.m_pickWorldSpaceTolerance = pickConfiguration.pickWorldSpaceTolerance;
gathererFunctor.m_objectPickersRequired = false;
const PickingUtils::HitList &hits = gathererFunctor.computeHits(entityPicker.entities(), QPickingSettings::AllPicks);
sphereHits.insert(sphereHits.end(),
@@ -228,11 +227,11 @@ bool RayCastingJob::runHelper()
std::make_move_iterator(hits.end()));
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
}
- if (pointPickingRequested) {
+ if (pickConfiguration.pointPickingRequested) {
PickingUtils::PointCollisionGathererFunctor gathererFunctor;
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
- gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
+ gathererFunctor.m_pickWorldSpaceTolerance = pickConfiguration.pickWorldSpaceTolerance;
gathererFunctor.m_objectPickersRequired = false;
const PickingUtils::HitList &hits = gathererFunctor.computeHits(entityPicker.entities(), QPickingSettings::AllPicks);
sphereHits.insert(sphereHits.end(),
@@ -240,7 +239,7 @@ bool RayCastingJob::runHelper()
std::make_move_iterator(hits.end()));
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
}
- if (!primitivePickingRequested) {
+ if (!pickConfiguration.primitivePickingRequested) {
const PickingUtils::HitList &hits = entityPicker.hits();
sphereHits.insert(sphereHits.end(),
std::make_move_iterator(hits.begin()),
@@ -256,6 +255,37 @@ bool RayCastingJob::runHelper()
return true;
}
+QAbstractRayCaster::Hits RayCastingJob::pick(Qt3DRender::QAbstractRayCaster *rayCaster)
+{
+ const PickingUtils::PickConfiguration pickConfiguration(m_frameGraphRoot, m_renderSettings);
+ if (pickConfiguration.vcaDetails.empty())
+ return {};
+
+ auto backendRayCaster = m_manager->rayCasterManager()->lookupResource(rayCaster->id());
+ if (!backendRayCaster)
+ return {};
+
+ backendRayCaster->syncFromFrontEnd(rayCaster, false);
+
+ EntityCasterGatherer gatherer(m_manager, backendRayCaster);
+ gatherer.apply(m_node);
+ const EntityCasterGatherer::EntityCasterList &entities = gatherer.m_result;
+
+ if (!pick(entities))
+ return {};
+
+ Q_D(RayCastingJob);
+ QAbstractRayCaster::Hits res;
+ for (const auto &hit: d->dispatches) {
+ if (hit.first->peerId() == rayCaster->id()) {
+ res = hit.second;
+ break;
+ }
+ }
+ d->dispatches.clear();
+ return res;
+}
+
void RayCastingJob::dispatchHits(RayCaster *rayCaster, const PickingUtils::HitList &sphereHits)
{
QAbstractRayCaster::Hits hits;
diff --git a/src/render/jobs/raycastingjob_p.h b/src/render/jobs/raycastingjob_p.h
index 061166918..fd9360501 100644
--- a/src/render/jobs/raycastingjob_p.h
+++ b/src/render/jobs/raycastingjob_p.h
@@ -79,6 +79,9 @@ public:
void markCastersDirty();
bool runHelper() override;
+ QAbstractRayCaster::Hits pick(QAbstractRayCaster *rayCaster);
+ bool pick(const QList<QPair<Entity *, RayCaster *>> &entities);
+
protected:
void dispatchHits(RayCaster *rayCaster, const PickingUtils::HitList &sphereHits);
diff --git a/src/render/picking/qabstractraycaster.cpp b/src/render/picking/qabstractraycaster.cpp
index f21d3b9ae..473a0d3e3 100644
--- a/src/render/picking/qabstractraycaster.cpp
+++ b/src/render/picking/qabstractraycaster.cpp
@@ -39,10 +39,14 @@
#include "qabstractraycaster.h"
#include "qabstractraycaster_p.h"
+#include <Qt3DCore/qaspectengine.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/private/qcomponent_p.h>
#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/private/qaspectengine_p.h>
#include <Qt3DRender/qlayer.h>
+#include <Qt3DRender/qrenderaspect.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
QT_BEGIN_NAMESPACE
@@ -71,6 +75,24 @@ void QAbstractRayCasterPrivate::updateHitEntites(QAbstractRayCaster::Hits &hits,
hits[i].setEntity(qobject_cast<Qt3DCore::QEntity *>(scene->lookupNode(hits[i].entityId())));
}
+QAbstractRayCaster::Hits QAbstractRayCasterPrivate::pick()
+{
+ Qt3DRender::QRenderAspect *renderAspect = nullptr;
+ const auto aspects = m_scene->engine()->aspects();
+ for (auto a: aspects) {
+ renderAspect = qobject_cast<Qt3DRender::QRenderAspect *>(a);
+ if (renderAspect)
+ break;
+ }
+ if (!renderAspect)
+ return {};
+
+ Q_Q(QAbstractRayCaster);
+ auto dRenderAspect = Qt3DRender::QRenderAspectPrivate::get(renderAspect);
+ dispatchHits(dRenderAspect->m_rayCastingJob->pick(q));
+ return m_hits;
+}
+
void QAbstractRayCasterPrivate::dispatchHits(const QAbstractRayCaster::Hits &hits)
{
Q_Q(QAbstractRayCaster);
diff --git a/src/render/picking/qabstractraycaster_p.h b/src/render/picking/qabstractraycaster_p.h
index 230832994..aef054938 100644
--- a/src/render/picking/qabstractraycaster_p.h
+++ b/src/render/picking/qabstractraycaster_p.h
@@ -88,6 +88,7 @@ public:
QAbstractRayCaster::FilterMode m_filterMode = QAbstractRayCaster::AcceptAnyMatchingLayers;
QList<QLayer *> m_layers;
+ QAbstractRayCaster::Hits pick();
virtual void dispatchHits(const QAbstractRayCaster::Hits &hits);
Q_DECLARE_PUBLIC(QAbstractRayCaster)
diff --git a/src/render/picking/qraycaster.cpp b/src/render/picking/qraycaster.cpp
index f32ea32f1..1f418b4c8 100644
--- a/src/render/picking/qraycaster.cpp
+++ b/src/render/picking/qraycaster.cpp
@@ -203,6 +203,16 @@ void QRayCaster::trigger(const QVector3D &origin, const QVector3D &direction, fl
setEnabled(true);
}
+QAbstractRayCaster::Hits QRayCaster::pick(const QVector3D &origin, const QVector3D &direction, float length)
+{
+ setOrigin(origin);
+ setDirection(direction);
+ setLength(length);
+
+ auto d = QAbstractRayCasterPrivate::get(this);
+ return d->pick();
+}
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/picking/qraycaster.h b/src/render/picking/qraycaster.h
index b565c2c25..950579068 100644
--- a/src/render/picking/qraycaster.h
+++ b/src/render/picking/qraycaster.h
@@ -72,6 +72,8 @@ public Q_SLOTS:
void trigger();
void trigger(const QVector3D& origin, const QVector3D& direction, float length);
+ Hits pick(const QVector3D& origin, const QVector3D& direction, float length);
+
Q_SIGNALS:
void originChanged(const QVector3D &origin);
void directionChanged(const QVector3D &direction);
diff --git a/src/render/picking/qraycasterhit.cpp b/src/render/picking/qraycasterhit.cpp
index 6e81c05d0..1a253dfb5 100644
--- a/src/render/picking/qraycasterhit.cpp
+++ b/src/render/picking/qraycasterhit.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qraycasterhit.h"
+#include <Qt3DCore/qentity.h>
QT_BEGIN_NAMESPACE
@@ -50,6 +51,10 @@ public:
QRayCasterHitData(QRayCasterHit::HitType type, Qt3DCore::QNodeId id, float distance,
const QVector3D &localIntersect, const QVector3D &worldIntersect,
uint primitiveIndex, uint v1 = 0, uint v2 = 0, uint v3 = 0);
+ QRayCasterHitData(const QRayCasterHitData& other) : m_type(other.m_type), m_entityId(other.m_entityId), m_entity(other.m_entity),
+ m_distance(other.m_distance), m_localIntersection(other.m_localIntersection),
+ m_worldIntersection(other.m_worldIntersection), m_primitiveIndex(other.m_primitiveIndex),
+ m_vertex1Index(other.m_vertex1Index), m_vertex2Index(other.m_vertex2Index), m_vertex3Index(other.m_vertex3Index) { }
QRayCasterHit::HitType m_type = QRayCasterHit::EntityHit;
Qt3DCore::QNodeId m_entityId;
@@ -121,7 +126,6 @@ QRayCasterHit::QRayCasterHit(QRayCasterHit::HitType type, Qt3DCore::QNodeId id,
uint primitiveIndex, uint v1, uint v2, uint v3)
: d(new QRayCasterHitData(type, id, distance, localIntersect, worldIntersect, primitiveIndex, v1, v2, v3))
{
-
}
QRayCasterHit::QRayCasterHit(const QRayCasterHit &other)
@@ -221,6 +225,38 @@ uint QRayCasterHit::vertex3Index() const
return d->m_vertex3Index;
}
+QString QRayCasterHit::toString()
+{
+ QString res;
+ if (!d->m_entity)
+ return QLatin1String("{}");
+ if (d->m_entity->objectName().length())
+ res = d->m_entity->objectName();
+ else
+ res = QLatin1String("Entity");
+
+ res += QString(QLatin1String(" (%1) Distance: %2 Local: (%3, %4, %5) World: (%6, %7, %8)"))
+ .arg(d->m_entity->id().id()).arg(double(d->m_distance))
+ .arg(double(d->m_localIntersection.x())).arg(double(d->m_localIntersection.y())).arg(double(d->m_localIntersection.z()))
+ .arg(double(d->m_worldIntersection.x())).arg(double(d->m_worldIntersection.y())).arg(double(d->m_worldIntersection.z()));
+
+ switch (d->m_type) {
+ case TriangleHit:
+ res += QString(QLatin1String(" Type: Triangle Index: %1 Vertices: %2 / %3 / %4")).arg(d->m_primitiveIndex).arg(d->m_vertex1Index).arg(d->m_vertex2Index).arg(d->m_vertex3Index);
+ break;
+ case LineHit:
+ res += QString(QLatin1String(" Type: Line Index: %1 Vertices: %2 / %3")).arg(d->m_primitiveIndex).arg(d->m_vertex1Index).arg(d->m_vertex2Index);
+ break;
+ case PointHit:
+ res += QString(QLatin1String(" Type: Point Index: %1")).arg(d->m_primitiveIndex);
+ break;
+ case EntityHit:
+ res += QLatin1String(" Type: Entity");
+ break;
+ }
+ return res;
+}
+
/*! \internal */
void QRayCasterHit::setEntity(Qt3DCore::QEntity *entity) const
{
diff --git a/src/render/picking/qraycasterhit.h b/src/render/picking/qraycasterhit.h
index 9f62889fd..3b1f64921 100644
--- a/src/render/picking/qraycasterhit.h
+++ b/src/render/picking/qraycasterhit.h
@@ -56,6 +56,16 @@ class QAbstractRayCasterPrivate;
class Q_3DRENDERSHARED_EXPORT QRayCasterHit
{
Q_GADGET
+ Q_PROPERTY(QRayCasterHit::HitType type READ type CONSTANT)
+ Q_PROPERTY(Qt3DCore::QNodeId entityId READ entityId CONSTANT)
+ Q_PROPERTY(Qt3DCore::QEntity *entity READ entity CONSTANT)
+ Q_PROPERTY(float distance READ distance CONSTANT)
+ Q_PROPERTY(QVector3D localIntersection READ localIntersection CONSTANT)
+ Q_PROPERTY(QVector3D worldIntersection READ worldIntersection CONSTANT)
+ Q_PROPERTY(uint primitiveIndex READ primitiveIndex CONSTANT)
+ Q_PROPERTY(uint vertex1Index READ vertex1Index CONSTANT)
+ Q_PROPERTY(uint vertex2Index READ vertex2Index CONSTANT)
+ Q_PROPERTY(uint vertex3Index READ vertex3Index CONSTANT)
public:
enum HitType {
TriangleHit,
@@ -85,6 +95,8 @@ public:
uint vertex2Index() const;
uint vertex3Index() const;
+ Q_INVOKABLE QString toString();
+
private:
friend class QAbstractRayCasterPrivate;
void setEntity(Qt3DCore::QEntity *entity) const;
diff --git a/src/render/picking/qscreenraycaster.cpp b/src/render/picking/qscreenraycaster.cpp
index 3e47c2a01..a8535187f 100644
--- a/src/render/picking/qscreenraycaster.cpp
+++ b/src/render/picking/qscreenraycaster.cpp
@@ -140,6 +140,14 @@ void QScreenRayCaster::trigger(const QPoint &position)
setEnabled(true);
}
+QAbstractRayCaster::Hits QScreenRayCaster::pick(const QPoint &position)
+{
+ setPosition(position);
+
+ auto d = QAbstractRayCasterPrivate::get(this);
+ return d->pick();
+}
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/picking/qscreenraycaster.h b/src/render/picking/qscreenraycaster.h
index 216ed47f5..800f5f7f9 100644
--- a/src/render/picking/qscreenraycaster.h
+++ b/src/render/picking/qscreenraycaster.h
@@ -52,7 +52,6 @@ namespace Qt3DRender {
class Q_3DRENDERSHARED_EXPORT QScreenRayCaster : public QAbstractRayCaster
{
Q_OBJECT
-
Q_PROPERTY(QPoint position READ position WRITE setPosition NOTIFY positionChanged)
public:
explicit QScreenRayCaster(QNode *parent = nullptr);
@@ -65,6 +64,7 @@ public Q_SLOTS:
void trigger();
void trigger(const QPoint &position);
+ Hits pick(const QPoint &position);
Q_SIGNALS:
void positionChanged(const QPoint &position);
diff --git a/tests/manual/raycasting-qml/CMakeLists.txt b/tests/manual/raycasting-qml/CMakeLists.txt
index 7b1549f3f..24be78aae 100644
--- a/tests/manual/raycasting-qml/CMakeLists.txt
+++ b/tests/manual/raycasting-qml/CMakeLists.txt
@@ -21,7 +21,16 @@ qt_add_manual_test(raycasting-qml
# Resources:
set(raycasting-qml_resource_files
- "main.qml"
+ main.qml
+ CylinderEntity.qml
+ LineEntity.qml
+ LineMaterial.qml
+)
+set(raycasting-shader_resource_files
+ shaders/es2/simpleColor.frag
+ shaders/es2/simpleColor.vert
+ shaders/gl3/simpleColor.frag
+ shaders/gl3/simpleColor.vert
)
qt_add_resource(raycasting-qml "raycasting-qml"
@@ -31,6 +40,13 @@ qt_add_resource(raycasting-qml "raycasting-qml"
${raycasting-qml_resource_files}
)
+qt_add_resource(raycasting-qml "shaders"
+ PREFIX
+ "/"
+ FILES
+ ${raycasting-shader_resource_files}
+)
+target_sources(raycasting-qml PRIVATE ${raycasting-qml_resource_files} ${raycasting-shader_resource_files})
#### Keys ignored in scope 1:.:.:raycasting-qml.pro:<TRUE>:
# OTHER_FILES = "main.qml"
diff --git a/tests/manual/raycasting-qml/LineEntity.qml b/tests/manual/raycasting-qml/LineEntity.qml
index 6071881f3..62cf911d1 100644
--- a/tests/manual/raycasting-qml/LineEntity.qml
+++ b/tests/manual/raycasting-qml/LineEntity.qml
@@ -83,7 +83,6 @@ Entity {
Buffer {
id: vertexBuffer
- type: Buffer.VertexBuffer
data: buildVertexBufferData(root.origin, root.direction, root.length)
}
diff --git a/tests/manual/raycasting-qml/main.qml b/tests/manual/raycasting-qml/main.qml
index c6cc8445f..33aa96752 100644
--- a/tests/manual/raycasting-qml/main.qml
+++ b/tests/manual/raycasting-qml/main.qml
@@ -121,6 +121,10 @@ Entity {
if (event.text.toLowerCase() == "s") { raycaster.origin.y += .1; raycaster.trigger() }
if (event.text.toLowerCase() == "d") { raycaster.origin.y -= .1; raycaster.trigger() }
}
+ onSpacePressed: {
+ var syncHits = raycaster.pick(raycaster.origin, raycaster.direction, raycaster.length)
+ printHits("Synchronous hits", syncHits)
+ }
}
components: [ external_forward_renderer, inputSettings, headLight, raycaster, screenRayCaster, mouseHandler, kbHandler ]