diff options
Diffstat (limited to 'src/render')
-rw-r--r-- | src/render/backend/cameralens.cpp | 4 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 11 | ||||
-rw-r--r-- | src/render/jobs/filterlayerentityjob.cpp | 51 | ||||
-rw-r--r-- | src/render/jobs/filterlayerentityjob_p.h | 1 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob.cpp | 6 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob_p.h | 1 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumeutils.cpp | 116 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumeutils_p.h | 9 | ||||
-rw-r--r-- | src/render/jobs/raycastingjob.cpp | 2 | ||||
-rw-r--r-- | src/render/shadergraph/qshadernode.cpp | 14 |
10 files changed, 117 insertions, 98 deletions
diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp index 9b8d7d710..743749210 100644 --- a/src/render/backend/cameralens.cpp +++ b/src/render/backend/cameralens.cpp @@ -133,12 +133,12 @@ void CameraLens::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTim const Matrix4x4 projectionMatrix(node->projectionMatrix()); if (projectionMatrix != m_projection) { m_projection = projectionMatrix; - markDirty(AbstractRenderer::AllDirty); + markDirty(AbstractRenderer::ParameterDirty); } if (!qFuzzyCompare(node->exposure(), m_exposure)) { m_exposure = node->exposure(); - markDirty(AbstractRenderer::AllDirty); + markDirty(AbstractRenderer::ParameterDirty); } const QCameraLensPrivate *d = static_cast<const QCameraLensPrivate *>(QNodePrivate::get(node)); diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 4e8967e6e..bbf1013d9 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -322,7 +322,9 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) m_expandBoundingVolumeJob->addDependency(m_updateWorldBoundingVolumeJob); m_updateLevelOfDetailJob->addDependency(m_expandBoundingVolumeJob); m_pickBoundingVolumeJob->addDependency(m_expandBoundingVolumeJob); + m_pickBoundingVolumeJob->addDependency(m_updateEntityLayersJob); m_rayCastingJob->addDependency(m_expandBoundingVolumeJob); + m_rayCastingJob->addDependency(m_updateEntityLayersJob); } /*! \internal */ @@ -717,17 +719,20 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) if (entitiesEnabledDirty) jobs.push_back(d->m_updateTreeEnabledJob); - if (dirtyBitsForFrame & AbstractRenderer::TransformDirty) { + if (entitiesEnabledDirty || + dirtyBitsForFrame & AbstractRenderer::TransformDirty) { jobs.push_back(d->m_worldTransformJob); jobs.push_back(d->m_updateWorldBoundingVolumeJob); } - if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty || + if (entitiesEnabledDirty || + dirtyBitsForFrame & AbstractRenderer::GeometryDirty || dirtyBitsForFrame & AbstractRenderer::BuffersDirty) { jobs.push_back(d->m_calculateBoundingVolumeJob); } - if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty || + if (entitiesEnabledDirty || + dirtyBitsForFrame & AbstractRenderer::GeometryDirty || dirtyBitsForFrame & AbstractRenderer::TransformDirty) { jobs.push_back(d->m_expandBoundingVolumeJob); } diff --git a/src/render/jobs/filterlayerentityjob.cpp b/src/render/jobs/filterlayerentityjob.cpp index ae3cced59..401bbc148 100644 --- a/src/render/jobs/filterlayerentityjob.cpp +++ b/src/render/jobs/filterlayerentityjob.cpp @@ -75,6 +75,33 @@ void FilterLayerEntityJob::run() std::sort(m_filteredEntities.begin(), m_filteredEntities.end()); } +void FilterLayerEntityJob::filterEntityAgainstLayers(Entity *entity, + const Qt3DCore::QNodeIdVector &layerIds, + const QLayerFilter::FilterMode filterMode) +{ + // Perform filtering + switch (filterMode) { + case QLayerFilter::AcceptAnyMatchingLayers: { + filterAcceptAnyMatchingLayers(entity, layerIds); + break; + } + case QLayerFilter::AcceptAllMatchingLayers: { + filterAcceptAllMatchingLayers(entity, layerIds); + break; + } + case QLayerFilter::DiscardAnyMatchingLayers: { + filterDiscardAnyMatchingLayers(entity, layerIds); + break; + } + case QLayerFilter::DiscardAllMatchingLayers: { + filterDiscardAllMatchingLayers(entity, layerIds); + break; + } + default: + Q_UNREACHABLE(); + } +} + // We accept the entity if it contains any of the layers that are in the layer filter void FilterLayerEntityJob::filterAcceptAnyMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds) @@ -181,28 +208,8 @@ void FilterLayerEntityJob::filterLayerAndEntity() const QLayerFilter::FilterMode filterMode = layerFilter->filterMode(); // Perform filtering - for (Entity *entity : entitiesToFilter) { - switch (filterMode) { - case QLayerFilter::AcceptAnyMatchingLayers: { - filterAcceptAnyMatchingLayers(entity, layerIds); - break; - } - case QLayerFilter::AcceptAllMatchingLayers: { - filterAcceptAllMatchingLayers(entity, layerIds); - break; - } - case QLayerFilter::DiscardAnyMatchingLayers: { - filterDiscardAnyMatchingLayers(entity, layerIds); - break; - } - case QLayerFilter::DiscardAllMatchingLayers: { - filterDiscardAllMatchingLayers(entity, layerIds); - break; - } - default: - Q_UNREACHABLE(); - } - } + for (Entity *entity : entitiesToFilter) + filterEntityAgainstLayers(entity, layerIds, filterMode); // Entities to filter for the next frame are the filtered result of the // current LayerFilter diff --git a/src/render/jobs/filterlayerentityjob_p.h b/src/render/jobs/filterlayerentityjob_p.h index 33023775f..6e8636f28 100644 --- a/src/render/jobs/filterlayerentityjob_p.h +++ b/src/render/jobs/filterlayerentityjob_p.h @@ -80,6 +80,7 @@ public: // QAspectJob interface void run() final; + void filterEntityAgainstLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds, const QLayerFilter::FilterMode filterMode); void filterAcceptAnyMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds); void filterAcceptAllMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds); void filterDiscardAnyMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds); diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index eebacc681..7519cbd9c 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -330,6 +330,7 @@ bool PickBoundingVolumeJob::runHelper() } PickingUtils::HierarchicalEntityPicker entityPicker(ray); + entityPicker.setLayerFilterIds(vca.layersFilters); if (entityPicker.collectHits(m_manager, m_node)) { if (trianglePickingRequested) { PickingUtils::TriangleCollisionGathererFunctor gathererFunctor; @@ -472,6 +473,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, case QEvent::MouseButtonPress: { // Store pressed object handle m_currentPicker = objectPickerHandle; + m_currentViewport = viewportNodeId; // Send pressed event to m_currentPicker d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId}); objectPicker->setPressed(true); @@ -489,6 +491,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, PickBoundingVolumeJobPrivate::MouseButtonClick, pickEvent, viewportNodeId}); m_currentPicker = HObjectPicker(); + m_currentViewport = {}; } break; } @@ -533,8 +536,9 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event, switch (event.type()) { case QEvent::MouseButtonRelease: { // Send release event to m_currentPicker - if (lastCurrentPicker != nullptr) { + if (lastCurrentPicker != nullptr && m_currentViewport == viewportNodeId) { m_currentPicker = HObjectPicker(); + m_currentViewport = {}; QPickEventPtr pickEvent(new QPickEvent); lastCurrentPicker->setPressed(false); d->dispatches.push_back({lastCurrentPicker->peerId(), event.type(), pickEvent, viewportNodeId}); diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h index 4f2c4340e..286bbb051 100644 --- a/src/render/jobs/pickboundingvolumejob_p.h +++ b/src/render/jobs/pickboundingvolumejob_p.h @@ -112,6 +112,7 @@ private: bool m_pickersDirty; bool m_oneHoverAtLeast; HObjectPicker m_currentPicker; + Qt3DCore::QNodeId m_currentViewport; QVector<HObjectPicker> m_hoveredPickers; QVector<HObjectPicker> m_hoveredPickersToClear; }; diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp index 1d22e8645..f4c5cc094 100644 --- a/src/render/jobs/pickboundingvolumeutils.cpp +++ b/src/render/jobs/pickboundingvolumeutils.cpp @@ -52,6 +52,9 @@ #include <Qt3DRender/private/segmentsvisitor_p.h> #include <Qt3DRender/private/pointsvisitor_p.h> #include <Qt3DRender/private/layer_p.h> +#include <Qt3DRender/private/layerfilternode_p.h> +#include <Qt3DRender/private/rendersettings_p.h> +#include <Qt3DRender/private/filterlayerentityjob_p.h> #include <vector> #include <algorithm> @@ -105,6 +108,11 @@ ViewportCameraAreaDetails ViewportCameraAreaGatherer::gatherUpViewportCameraArea // prevent picking in the presence of a NoPicking node return {}; } + case FrameGraphNode::LayerFilter: { + auto fnode = static_cast<const LayerFilterNode *>(node); + vca.layersFilters.push_back(fnode->peerId()); + break; + } default: break; } @@ -139,7 +147,8 @@ bool ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaDetail if (vca.cameraId == listItem.cameraId && vca.viewport == listItem.viewport && vca.surface == listItem.surface && - vca.area == listItem.area) + vca.area == listItem.area && + vca.layersFilters == listItem.layersFilters) return false; } return true; @@ -700,16 +709,19 @@ HitList PointCollisionGathererFunctor::pick(const Entity *entity) const HierarchicalEntityPicker::HierarchicalEntityPicker(const QRay3D &ray, bool requireObjectPicker) : m_ray(ray) , m_objectPickersRequired(requireObjectPicker) - , m_filterMode(QAbstractRayCaster::AcceptAnyMatchingLayers) { +} +void HierarchicalEntityPicker::setLayerFilterIds(const Qt3DCore::QNodeIdVector &layerFilterIds) +{ + m_layerFilterIds = layerFilterIds; } -void HierarchicalEntityPicker::setFilterLayers(const Qt3DCore::QNodeIdVector &layerIds, QAbstractRayCaster::FilterMode mode) +void HierarchicalEntityPicker::setLayerIds(const Qt3DCore::QNodeIdVector &layerIds, + QAbstractRayCaster::FilterMode mode) { - m_filterMode = mode; m_layerIds = layerIds; - std::sort(m_layerIds.begin(), m_layerIds.end()); + m_layerFilterMode = mode; } bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root) @@ -722,60 +734,37 @@ bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root) struct EntityData { Entity* entity; bool hasObjectPicker; - Qt3DCore::QNodeIdVector recursiveLayers; int priority; }; std::vector<EntityData> worklist; - worklist.push_back({root, !root->componentHandle<ObjectPicker>().isNull(), {}, 0}); - - LayerManager *layerManager = manager->layerManager(); + worklist.push_back({root, !root->componentHandle<ObjectPicker>().isNull(), 0}); + + // Record all entities that satisfy layerFiltering. We can then check against + // that to see if a picked Entity also satisfies the layer filtering + + // Note: PickBoundingVolumeJob filters against LayerFilter nodes (FG) whereas + // the RayCastingJob filters only against a set of Layers and a filter Mode + const bool hasLayerFilters = m_layerFilterIds.size() > 0; + const bool hasLayers = m_layerIds.size() > 0; + const bool hasLayerFiltering = hasLayerFilters || hasLayers; + QVector<Entity *> layerFilterEntities; + FilterLayerEntityJob layerFilterJob; + layerFilterJob.setManager(manager); + + if (hasLayerFilters) { + // Note: we expect UpdateEntityLayersJob was called beforehand to handle layer recursivness + // Filtering against LayerFilters (PickBoundingVolumeJob) + if (m_layerFilterIds.size()) { + layerFilterJob.setLayerFilters(m_layerFilterIds); + layerFilterJob.run(); + layerFilterEntities = layerFilterJob.filteredEntities(); + } + } while (!worklist.empty()) { EntityData current = worklist.back(); worklist.pop_back(); - bool accepted = true; - if (m_layerIds.size()) { - // TODO investigate reusing logic from LayerFilter job - Qt3DCore::QNodeIdVector filterLayers = current.recursiveLayers + current.entity->componentsUuid<Layer>(); - - // remove disabled layers - filterLayers.erase(std::remove_if(filterLayers.begin(), filterLayers.end(), - [layerManager](const Qt3DCore::QNodeId layerId) { - Layer *layer = layerManager->lookupResource(layerId); - return !layer || !layer->isEnabled(); - }), filterLayers.end()); - - std::sort(filterLayers.begin(), filterLayers.end()); - - Qt3DCore::QNodeIdVector commonIds; - std::set_intersection(m_layerIds.cbegin(), m_layerIds.cend(), - filterLayers.cbegin(), filterLayers.cend(), - std::back_inserter(commonIds)); - - switch (m_filterMode) { - case QAbstractRayCaster::AcceptAnyMatchingLayers: { - accepted = !commonIds.empty(); - break; - } - case QAbstractRayCaster::AcceptAllMatchingLayers: { - accepted = commonIds == m_layerIds; - break; - } - case QAbstractRayCaster::DiscardAnyMatchingLayers: { - accepted = commonIds.empty(); - break; - } - case QAbstractRayCaster::DiscardAllMatchingLayers: { - accepted = !(commonIds == m_layerIds); - break; - } - default: - Q_UNREACHABLE(); - break; - } - } - // first pick entry sub-scene-graph QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, current.entity->worldBoundingVolumeWithChildren()); @@ -784,21 +773,27 @@ bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root) // if we get a hit, we check again for this specific entity queryResult = rayCasting.query(m_ray, current.entity->worldBoundingVolume()); - if (accepted && queryResult.m_distance >= 0.f && (current.hasObjectPicker || !m_objectPickersRequired)) { + + // Check Entity is in selected Layers if we have LayerIds or LayerFilterIds + // Note: it's not because a parent doesn't satisfy the layerFiltering that a child might not. + // Therefore we need to keep traversing children in all cases + + // Are we filtering against layerIds (RayCastingJob) + if (hasLayers) { + // QLayerFilter::FilterMode and QAbstractRayCaster::FilterMode are the same + layerFilterJob.filterEntityAgainstLayers(current.entity, m_layerIds, static_cast<QLayerFilter::FilterMode>(m_layerFilterMode)); + layerFilterEntities = layerFilterJob.filteredEntities(); + } + + const bool isInLayers = !hasLayerFiltering || layerFilterEntities.contains(current.entity); + + if (isInLayers && queryResult.m_distance >= 0.f && (current.hasObjectPicker || !m_objectPickersRequired)) { m_entities.push_back(current.entity); m_hits.push_back(queryResult); // Record entry for entity/priority m_entityToPriorityTable.insert(current.entity->peerId(), current.priority); } - Qt3DCore::QNodeIdVector recursiveLayers; - const Qt3DCore::QNodeIdVector entityLayers = current.entity->componentsUuid<Layer>(); - for (const Qt3DCore::QNodeId layerId : entityLayers) { - Layer *layer = layerManager->lookupResource(layerId); - if (layer->recursive()) - recursiveLayers << layerId; - } - // and pick children const auto childrenHandles = current.entity->childrenHandles(); for (const HEntity &handle : childrenHandles) { @@ -806,7 +801,6 @@ bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root) if (child) { ObjectPicker *childPicker = child->renderComponent<ObjectPicker>(); worklist.push_back({child, current.hasObjectPicker || childPicker, - current.recursiveLayers + recursiveLayers, (childPicker ? childPicker->priority() : current.priority)}); } } diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h index fa3e701c2..1fe81fc46 100644 --- a/src/render/jobs/pickboundingvolumeutils_p.h +++ b/src/render/jobs/pickboundingvolumeutils_p.h @@ -83,8 +83,9 @@ struct Q_AUTOTEST_EXPORT ViewportCameraAreaDetails QRectF viewport; QSize area; QSurface *surface = nullptr; + Qt3DCore::QNodeIdVector layersFilters; }; -QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaDetails, Q_PRIMITIVE_TYPE) +QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaDetails, Q_COMPLEX_TYPE) class Q_AUTOTEST_EXPORT ViewportCameraAreaGatherer { @@ -108,7 +109,8 @@ class Q_AUTOTEST_EXPORT HierarchicalEntityPicker public: explicit HierarchicalEntityPicker(const RayCasting::QRay3D &ray, bool requireObjectPicker = true); - void setFilterLayers(const Qt3DCore::QNodeIdVector &layerIds, QAbstractRayCaster::FilterMode mode); + void setLayerFilterIds(const Qt3DCore::QNodeIdVector &layerFilterIds); + void setLayerIds(const Qt3DCore::QNodeIdVector &layerIds, QAbstractRayCaster::FilterMode mode); bool collectHits(NodeManagers *manager, Entity *root); inline HitList hits() const { return m_hits; } @@ -120,8 +122,9 @@ private: HitList m_hits; QVector<Entity *> m_entities; bool m_objectPickersRequired; + Qt3DCore::QNodeIdVector m_layerFilterIds; Qt3DCore::QNodeIdVector m_layerIds; - QAbstractRayCaster::FilterMode m_filterMode; + QAbstractRayCaster::FilterMode m_layerFilterMode = QAbstractRayCaster::AcceptAnyMatchingLayers; QHash<Qt3DCore::QNodeId, int> m_entityToPriorityTable; }; diff --git a/src/render/jobs/raycastingjob.cpp b/src/render/jobs/raycastingjob.cpp index b7d4c4b7c..56f681a2c 100644 --- a/src/render/jobs/raycastingjob.cpp +++ b/src/render/jobs/raycastingjob.cpp @@ -202,7 +202,7 @@ bool RayCastingJob::runHelper() for (const QRay3D &ray: qAsConst(rays)) { PickingUtils::HitList sphereHits; PickingUtils::HierarchicalEntityPicker entityPicker(ray, false); - entityPicker.setFilterLayers(pair.second->layerIds(), pair.second->filterMode()); + entityPicker.setLayerIds(pair.second->layerIds(), pair.second->filterMode()); if (entityPicker.collectHits(m_manager, m_node)) { if (trianglePickingRequested) { PickingUtils::TriangleCollisionGathererFunctor gathererFunctor; diff --git a/src/render/shadergraph/qshadernode.cpp b/src/render/shadergraph/qshadernode.cpp index e0421e006..56c9961f3 100644 --- a/src/render/shadergraph/qshadernode.cpp +++ b/src/render/shadergraph/qshadernode.cpp @@ -152,11 +152,15 @@ QVector<QShaderFormat> QShaderNode::availableFormats() const QShaderNode::Rule QShaderNode::rule(const QShaderFormat &format) const { - const auto it = std::find_if(m_rules.crbegin(), m_rules.crend(), - [format](const QPair<QShaderFormat, Rule> &entry) { - return format.supports(entry.first); - }); - return it != m_rules.crend() ? it->second : Rule(); + const QPair<QShaderFormat, Rule> *selected = nullptr; + for (auto it = m_rules.crbegin(); it != m_rules.crend(); ++it) { + const auto &entry = *it; + if (format.supports(entry.first)) { + if (!selected || entry.first.version() > selected->first.version()) + selected = &entry; + } + } + return selected ? selected->second : Rule(); } QShaderNode::Rule::Rule(const QByteArray &subs, const QByteArrayList &snippets) noexcept |