From aadaafa3ce3d5b58cfc51b0bcbb99374c17cc658 Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 13 Nov 2015 16:31:00 +0100 Subject: QRayCastingService improvements Change-Id: Id8072015f153bebf3e44b9d0a6ad9e2e9254aa83 Reviewed-by: Andy Nichols --- src/render/services/qraycastingservice.cpp | 120 +++++++++++++++++++++-------- src/render/services/qraycastingservice.h | 4 +- src/render/services/qraycastingservice_p.h | 4 +- 3 files changed, 90 insertions(+), 38 deletions(-) (limited to 'src/render/services') diff --git a/src/render/services/qraycastingservice.cpp b/src/render/services/qraycastingservice.cpp index 93dbc4e2e..af06b06d7 100644 --- a/src/render/services/qraycastingservice.cpp +++ b/src/render/services/qraycastingservice.cpp @@ -52,66 +52,120 @@ using namespace Qt3DCore; namespace Qt3DRender { +namespace { + +struct Hit +{ + Hit() + : intersects(false) + , distance(-1.0f) + {} + + bool intersects; + float distance; + Qt3DCore::QNodeId id; + QVector3D intersection; +}; + +bool compareHitsDistance(const Hit &a, const Hit &b) +{ + return a.distance < b.distance; +} + +Hit volumeRayIntersection(const QBoundingVolume *volume, const Qt3DCore::QRay3D &ray) +{ + Hit hit; + if ((hit.intersects = volume->intersects(ray, &hit.intersection))) { + hit.distance = ray.projectedDistance(hit.intersection); + hit.id = volume->id(); + } + return hit; +} + +Hit reduceToFirstHit(Hit &result, const Hit &intermediate) +{ + if (intermediate.intersects) { + if (result.distance == -1.0f || + (intermediate.distance >= 0.0f && + intermediate.distance < result.distance)) + result = intermediate; + } + return result; +} + +// Unordered +QVector reduceToAllHits(QVector &results, const Hit &intermediate) +{ + if (intermediate.intersects) + results.push_back(intermediate); + return results; +} + +struct CollisionGathererFunctor +{ + Qt3DCore::QRay3D ray; + + typedef Hit result_type; + + Hit operator ()(const QBoundingVolume *volume) const + { + return volumeRayIntersection(volume, ray); + } +}; + +} // anonymous + + QCollisionQueryResult QRayCastingServicePrivate::collides(const Qt3DCore::QRay3D &ray, Qt3DCore::QBoundingVolumeProvider *provider, Qt3DCore::QAbstractCollisionQueryService::QueryMode mode, const Qt3DCore::QQueryHandle &handle) { Q_Q(QRayCastingService); - const QVector spheres(provider->boundingVolumes()); + const QVector volumes(provider->boundingVolumes()); QCollisionQueryResult result; q->setResultHandle(result, handle); + CollisionGathererFunctor gathererFunctor; + gathererFunctor.ray = ray; + if (mode == QAbstractCollisionQueryService::FirstHit) { - QVector3D intersection; - float collidingPointDistance = -1.0f; - QNodeId collidingSphere; - - Q_FOREACH (QBoundingVolume *bs, spheres) { - if (bs->intersects(ray, &intersection)) { - const float distanceFromRay = ray.projectedDistance(intersection); - - if (collidingPointDistance == -1.0f || (distanceFromRay >= 0.0f && distanceFromRay < collidingPointDistance)) { - collidingPointDistance = distanceFromRay; - collidingSphere = bs->id(); - } - } - } - - if (!collidingSphere.isNull()) { - q->addEntityHit(result, collidingSphere); - } - - } else if (mode == QAbstractCollisionQueryService::AllHits) { - Q_FOREACH (QBoundingVolume *bs, spheres) { - if (bs->intersects(ray)) - q->addEntityHit(result, bs->id()); - } + Hit firstHit = QtConcurrent::blockingMappedReduced(volumes, gathererFunctor, reduceToFirstHit); + if (firstHit.intersects) + q->addEntityHit(result, firstHit.id); + } else { + QVector hits = QtConcurrent::blockingMappedReduced >(volumes, gathererFunctor, reduceToAllHits); + std::sort(hits.begin(), hits.end(), compareHitsDistance); + Q_FOREACH (const Hit &hit, hits) + q->addEntityHit(result, hit.id); } + return result; } -QRayCastingServicePrivate::QRayCastingServicePrivate(const QString &description, QBoundingVolumeProvider *provider) +QRayCastingServicePrivate::QRayCastingServicePrivate(const QString &description) : QAbstractCollisionQueryServicePrivate(description) , m_handlesCount(0) - , m_boundingProvider(provider) { } -QRayCastingService::QRayCastingService(Qt3DCore::QBoundingVolumeProvider *provider) - : QAbstractCollisionQueryService(*new QRayCastingServicePrivate(QStringLiteral("Collision detection service using Ray Casting"), - provider)) +QRayCastingService::QRayCastingService() + : QAbstractCollisionQueryService(*new QRayCastingServicePrivate(QStringLiteral("Collision detection service using Ray Casting"))) { } -Qt3DCore::QQueryHandle QRayCastingService::query(const Qt3DCore::QRay3D &ray, QAbstractCollisionQueryService::QueryMode mode) +Qt3DCore::QQueryHandle QRayCastingService::query(const Qt3DCore::QRay3D &ray, + QAbstractCollisionQueryService::QueryMode mode, + Qt3DCore::QBoundingVolumeProvider *provider) { Q_D(QRayCastingService); QQueryHandle handle = d->m_handlesCount.fetchAndStoreOrdered(1); - // TODO: Implement run using jobs to avoid multiple threadpool + + // Blocking mapReduce + FutureQueryResult future = QtConcurrent::run(d, &QRayCastingServicePrivate::collides, - ray, d->m_boundingProvider, mode, handle); + ray, provider, mode, handle); d->m_results.insert(handle, future); return handle; diff --git a/src/render/services/qraycastingservice.h b/src/render/services/qraycastingservice.h index 680d4c092..2982c161c 100644 --- a/src/render/services/qraycastingservice.h +++ b/src/render/services/qraycastingservice.h @@ -54,9 +54,9 @@ class QRayCastingServicePrivate; class QT3DRENDERSHARED_EXPORT QRayCastingService : public Qt3DCore::QAbstractCollisionQueryService { public: - explicit QRayCastingService(Qt3DCore::QBoundingVolumeProvider *provider); + QRayCastingService(); - Qt3DCore::QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode) Q_DECL_OVERRIDE; + Qt3DCore::QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode, Qt3DCore::QBoundingVolumeProvider *provider) Q_DECL_OVERRIDE; Qt3DCore::QCollisionQueryResult fetchResult(const Qt3DCore::QQueryHandle &handle) Q_DECL_OVERRIDE; QVector fetchAllResults() const Q_DECL_OVERRIDE; diff --git a/src/render/services/qraycastingservice_p.h b/src/render/services/qraycastingservice_p.h index 95b455ee1..252c50bfd 100644 --- a/src/render/services/qraycastingservice_p.h +++ b/src/render/services/qraycastingservice_p.h @@ -71,7 +71,7 @@ typedef QFuture FutureQueryResult; class QRayCastingServicePrivate : public Qt3DCore::QAbstractCollisionQueryServicePrivate { public: - QRayCastingServicePrivate(const QString &description, Qt3DCore::QBoundingVolumeProvider *provider); + QRayCastingServicePrivate(const QString &description); Qt3DCore::QCollisionQueryResult collides(const Qt3DCore::QRay3D &ray, Qt3DCore::QBoundingVolumeProvider *provider, @@ -89,8 +89,6 @@ public: QHash m_results; QAtomicInt m_handlesCount; - - Qt3DCore::QBoundingVolumeProvider *m_boundingProvider; }; } // namespace Qt3DRender -- cgit v1.2.3