summaryrefslogtreecommitdiffstats
path: root/src/render/services
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2015-11-13 16:31:00 +0100
committerAndy Nichols <andy.nichols@theqtcompany.com>2015-11-24 14:56:49 +0000
commitaadaafa3ce3d5b58cfc51b0bcbb99374c17cc658 (patch)
tree0e65d884f7104289488e9b85342dd998ffecb47f /src/render/services
parentdee5562b22034702e2555f08271d9fc09fd458dc (diff)
QRayCastingService improvements
Change-Id: Id8072015f153bebf3e44b9d0a6ad9e2e9254aa83 Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
Diffstat (limited to 'src/render/services')
-rw-r--r--src/render/services/qraycastingservice.cpp120
-rw-r--r--src/render/services/qraycastingservice.h4
-rw-r--r--src/render/services/qraycastingservice_p.h4
3 files changed, 90 insertions, 38 deletions
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<Hit> reduceToAllHits(QVector<Hit> &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<QBoundingVolume *> spheres(provider->boundingVolumes());
+ const QVector<QBoundingVolume *> 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<Hit>(volumes, gathererFunctor, reduceToFirstHit);
+ if (firstHit.intersects)
+ q->addEntityHit(result, firstHit.id);
+ } else {
+ QVector<Hit> hits = QtConcurrent::blockingMappedReduced<QVector<Hit> >(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<Qt3DCore::QCollisionQueryResult> 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<Qt3DCore::QCollisionQueryResult> 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<Qt3DCore::QQueryHandle, FutureQueryResult> m_results;
QAtomicInt m_handlesCount;
-
- Qt3DCore::QBoundingVolumeProvider *m_boundingProvider;
};
} // namespace Qt3DRender