diff options
Diffstat (limited to 'src/render/jobs/pickboundingvolumeutils.cpp')
-rw-r--r-- | src/render/jobs/pickboundingvolumeutils.cpp | 141 |
1 files changed, 91 insertions, 50 deletions
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp index f08398a5a..a8367dc20 100644 --- a/src/render/jobs/pickboundingvolumeutils.cpp +++ b/src/render/jobs/pickboundingvolumeutils.cpp @@ -110,7 +110,8 @@ QVector<ViewportCameraAreaTriplet> ViewportCameraAreaGatherer::gather(FrameGraph return vcaTriplets; } -bool PickingUtils::ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const +bool ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, + const ViewportCameraAreaTriplet &vca) const { for (const ViewportCameraAreaTriplet &triplet : vcaTriplets) { if (vca.cameraId == triplet.cameraId && vca.viewport == triplet.viewport && vca.area == triplet.area) @@ -147,7 +148,35 @@ QVector<Entity *> EntityGatherer::entities() const return m_entities; } -void CollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c) + +class TriangleCollisionVisitor : public TrianglesVisitor +{ +public: + HitList hits; + + TriangleCollisionVisitor(NodeManagers* manager, const Entity *root, const RayCasting::QRay3D& ray, + bool frontFaceRequested, bool backFaceRequested) + : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0) + , m_frontFaceRequested(frontFaceRequested), m_backFaceRequested(backFaceRequested) + { + } + +private: + const Entity *m_root; + RayCasting::QRay3D m_ray; + uint m_triangleIndex; + bool m_frontFaceRequested; + bool m_backFaceRequested; + + void visit(uint andx, const QVector3D &a, + uint bndx, const QVector3D &b, + uint cndx, const QVector3D &c) Q_DECL_OVERRIDE; + bool intersectsSegmentTriangle(uint andx, const QVector3D &a, + uint bndx, const QVector3D &b, + uint cndx, const QVector3D &c); +}; + +void TriangleCollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c) { const QMatrix4x4 &mat = *m_root->worldTransform(); const QVector3D tA = mat * a; @@ -163,7 +192,7 @@ void CollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVe m_triangleIndex++; } -bool CollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c) +bool TriangleCollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c) { float t = 0.0f; QVector3D uvw; @@ -183,6 +212,32 @@ bool CollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a, return intersected; } +HitList reduceToFirstHit(HitList &result, const HitList &intermediate) +{ + if (!intermediate.empty()) { + if (result.empty()) + result.push_back(intermediate.front()); + float closest = result.front().m_distance; + for (const auto &v : intermediate) { + if (v.m_distance < closest) { + result.push_front(v); + closest = v.m_distance; + } + } + + while (result.size() > 1) + result.pop_back(); + } + return result; +} + +HitList reduceToAllHits(HitList &results, const HitList &intermediate) +{ + if (!intermediate.empty()) + results << intermediate; + return results; +} + AbstractCollisionGathererFunctor::AbstractCollisionGathererFunctor() : m_manager(nullptr) { } @@ -190,7 +245,7 @@ AbstractCollisionGathererFunctor::AbstractCollisionGathererFunctor() AbstractCollisionGathererFunctor::~AbstractCollisionGathererFunctor() { } -AbstractCollisionGathererFunctor::result_type AbstractCollisionGathererFunctor::operator ()(const Entity *entity) const +HitList AbstractCollisionGathererFunctor::operator ()(const Entity *entity) const { HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); @@ -205,44 +260,62 @@ AbstractCollisionGathererFunctor::result_type AbstractCollisionGathererFunctor:: ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle); if (objectPicker == nullptr || !objectPicker->isEnabled()) - return result_type(); // don't bother picking entities that don't - // have an object picker, or if it's disabled + return {}; // don't bother picking entities that don't + // have an object picker, or if it's disabled - RayCasting::QRayCastingService rayCasting; + return pick(entity); +} - return pick(&rayCasting, entity); +bool AbstractCollisionGathererFunctor::rayHitsEntity(const Entity *entity) const +{ + QRayCastingService rayCasting; + const QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, entity->worldBoundingVolume()); + return queryResult.m_distance >= 0.f; } -void AbstractCollisionGathererFunctor::sortHits(CollisionVisitor::HitList &results) +void AbstractCollisionGathererFunctor::sortHits(HitList &results) { - auto compareHitsDistance = [](const CollisionVisitor::HitList::value_type &a, - const CollisionVisitor::HitList::value_type &b) { + auto compareHitsDistance = [](const HitList::value_type &a, + const HitList::value_type &b) { return a.m_distance < b.m_distance; }; std::sort(results.begin(), results.end(), compareHitsDistance); } -AbstractCollisionGathererFunctor::result_type EntityCollisionGathererFunctor::pick(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const +HitList EntityCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested) { - result_type result; + const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit; + return QtConcurrent::blockingMappedReduced<HitList>(entities, *this, reducerOp); +} - const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume()); +HitList EntityCollisionGathererFunctor::pick(const Entity *entity) const +{ + HitList result; + + QRayCastingService rayCasting; + const QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, entity->worldBoundingVolume()); if (queryResult.m_distance >= 0.f) result.push_back(queryResult); return result; } -AbstractCollisionGathererFunctor::result_type TriangleCollisionGathererFunctor::pick(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const +HitList TriangleCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested) +{ + const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit; + return QtConcurrent::blockingMappedReduced<HitList>(entities, *this, reducerOp); +} + +HitList TriangleCollisionGathererFunctor::pick(const Entity *entity) const { - result_type result; + HitList result; GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>(); if (!gRenderer) return result; - if (rayHitsEntity(rayCasting, entity)) { - CollisionVisitor visitor(m_manager, entity, m_ray, m_frontFaceRequested, m_backFaceRequested); + if (rayHitsEntity(entity)) { + TriangleCollisionVisitor visitor(m_manager, entity, m_ray, m_frontFaceRequested, m_backFaceRequested); visitor.apply(gRenderer, entity->peerId()); result = visitor.hits; @@ -252,38 +325,6 @@ AbstractCollisionGathererFunctor::result_type TriangleCollisionGathererFunctor:: return result; } -bool TriangleCollisionGathererFunctor::rayHitsEntity(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const -{ - const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume()); - return queryResult.m_distance >= 0.f; -} - -CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate) -{ - if (!intermediate.empty()) { - if (result.empty()) - result.push_back(intermediate.front()); - float closest = result.front().m_distance; - for (const auto &v : intermediate) { - if (v.m_distance < closest) { - result.push_front(v); - closest = v.m_distance; - } - } - - while (result.size() > 1) - result.pop_back(); - } - return result; -} - -CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate) -{ - if (!intermediate.empty()) - results << intermediate; - return results; -} - HierarchicalEntityPicker::HierarchicalEntityPicker(const QRay3D &ray) : m_ray(ray) { |