diff options
author | Mike Krus <mike.krus@kdab.com> | 2015-12-10 15:58:05 +0000 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2016-01-25 14:13:13 +0000 |
commit | 28ec1ca1883e0fe9b8b0e0de4049564ae652bd90 (patch) | |
tree | 3722809fc54b75d08b08fb68bd5d9d56fbe24342 /src | |
parent | 4ad00b344bc79e34f2ba2f8355e65c7948791389 (diff) |
Refactor picking to use one thread per entity
Added triangle visitor by refactor the triangle volume extractor
Added ability to do a ray intersection with a single volume without using a thread
Added entity collector
Use one thread for each entity
Ignore entities that don’t have a pick object
Removed list of triangle volumes stored on each entity
Use triangle visitor to test each triangle by creating a single volume on the stack
Added triangle and 3 vertex index to the pick event
Change-Id: Id3fd53549bf3ea07805426ef868df174f30e176b
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/render/backend/render-backend.pri | 2 | ||||
-rw-r--r-- | src/render/backend/trianglesextractor.cpp | 447 | ||||
-rw-r--r-- | src/render/backend/trianglesextractor_p.h | 13 | ||||
-rw-r--r-- | src/render/backend/trianglesvisitor.cpp | 518 | ||||
-rw-r--r-- | src/render/backend/trianglesvisitor_p.h | 91 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 13 | ||||
-rw-r--r-- | src/render/jobs/calcboundingvolumejob.cpp | 2 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob.cpp | 440 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob_p.h | 13 | ||||
-rw-r--r-- | src/render/picking/qpickevent.cpp | 35 | ||||
-rw-r--r-- | src/render/picking/qpickevent.h | 11 | ||||
-rw-r--r-- | src/render/raycasting/qabstractcollisionqueryservice_p.h | 3 | ||||
-rw-r--r-- | src/render/raycasting/qcollisionqueryresult_p.h | 2 | ||||
-rw-r--r-- | src/render/raycasting/qraycastingservice.cpp | 20 | ||||
-rw-r--r-- | src/render/raycasting/qraycastingservice_p.h | 4 |
15 files changed, 936 insertions, 678 deletions
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri index 0b7efa5e7..5d2018b7d 100644 --- a/src/render/backend/render-backend.pri +++ b/src/render/backend/render-backend.pri @@ -27,6 +27,7 @@ HEADERS += \ $$PWD/triangleboundingvolume_p.h \ $$PWD/openglvertexarrayobject_p.h \ $$PWD/trianglesextractor_p.h \ + $$PWD/trianglesvisitor_p.h \ $$PWD/abstractrenderer_p.h \ $$PWD/computejob_p.h \ $$PWD/renderersettings_p.h @@ -53,5 +54,6 @@ SOURCES += \ $$PWD/nodemanagers.cpp \ $$PWD/triangleboundingvolume.cpp \ $$PWD/trianglesextractor.cpp \ + $$PWD/trianglesvisitor.cpp \ $$PWD/computejob.cpp \ $$PWD/renderersettings.cpp diff --git a/src/render/backend/trianglesextractor.cpp b/src/render/backend/trianglesextractor.cpp index 85eba29df..9e63c1c1e 100644 --- a/src/render/backend/trianglesextractor.cpp +++ b/src/render/backend/trianglesextractor.cpp @@ -35,11 +35,13 @@ ****************************************************************************/ #include "trianglesextractor_p.h" +#include <Qt3DCore/qentity.h> #include <Qt3DRender/qgeometryrenderer.h> #include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/buffermanager_p.h> #include <Qt3DRender/private/geometryrenderer_p.h> +#include <Qt3DRender/private/geometryrenderermanager_p.h> #include <Qt3DRender/private/geometry_p.h> #include <Qt3DRender/private/attribute_p.h> #include <Qt3DRender/private/buffer_p.h> @@ -51,448 +53,23 @@ namespace Qt3DRender { namespace Render { -namespace { - -bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_NOEXCEPT -{ - switch (type) { - case Qt3DRender::QGeometryRenderer::Triangles: - case Qt3DRender::QGeometryRenderer::TriangleStrip: - case Qt3DRender::QGeometryRenderer::TriangleFan: - case Qt3DRender::QGeometryRenderer::TrianglesAdjacency: - case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: - return true; - default: - return false; - } -} - -struct BufferInfo -{ - BufferInfo() - : type(QAttribute::DataType::Float) - , dataSize(0) - , count(0) - , byteStride(0) - , byteOffset(0) - {} - - QByteArray data; - QAttribute::DataType type; - uint dataSize; - uint count; - uint byteStride; - uint byteOffset; -}; - -// TO DO: Add methods for triangle strip adjacency -// What about primitive restart ? - -// indices, vertices are already offset -template<typename index, typename vertex> -QVector<QBoundingVolume *> traverseTrianglesIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - while (i < indexInfo.count) { - for (uint u = 0; u < 3; ++u) { - uint idx = indices[i + u] * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - i += 3; - } - - return tris; -} - -// vertices are already offset -template<typename vertex> -QVector<QBoundingVolume *> traverseTriangles(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - uint i = 0; - - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - while (i < vertexInfo.count) { - for (uint u = 0; u < 3; ++u) { - uint idx = (i + u) * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - i += 3; - } - return tris; -} - -// indices, vertices are already offset -template<typename index, typename vertex> -QVector<QBoundingVolume *> traverseTriangleStripIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - while (i < indexInfo.count) { - for (uint u = 0; u < 3; ++u) { - uint idx = indices[i + u] * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - ++i; - } - - return tris; -} - -// vertices are already offset -template<typename vertex> -QVector<QBoundingVolume *> traverseTriangleStrip(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - uint i = 0; - - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - while (i < vertexInfo.count) { - for (uint u = 0; u < 3; ++u) { - uint idx = (i + u) * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - ++i; - } - return tris; -} - -// indices, vertices are already offset -template<typename index, typename vertex> -QVector<QBoundingVolume *> traverseTriangleFanIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[0][j] = vertices[static_cast<int>(indices[0]) * verticesStride + j]; - } - - uint i = 1; - while (i < indexInfo.count) { - for (uint u = 0; u < 2; ++u) { - uint idx = indices[i + u] * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u + 1][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - i += 2; - } - - return tris; -} - -// vertices are already offset -template<typename vertex> -QVector<QBoundingVolume *> traverseTriangleFan(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[0][j] = vertices[j]; - } - - uint i = 1; - while (i < vertexInfo.count) { - for (uint u = 0; u < 2; ++u) { - uint idx = (i + u) * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u + 1][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - i += 2; - } - return tris; -} - -// indices, vertices are already offset -template<typename index, typename vertex> -QVector<QBoundingVolume *> traverseTriangleAdjacencyIndexed(index *indices, - vertex *vertices, - const BufferInfo &indexInfo, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - uint i = 0; - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - while (i < indexInfo.count) { - for (uint u = 0; u < 6; u += 2) { - uint idx = indices[i + u] * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u / 2][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - i += 6; - } - - return tris; -} - -// vertices are already offset -template<typename vertex> -QVector<QBoundingVolume *> traverseTriangleAdjacency(vertex *vertices, - const BufferInfo &vertexInfo, - const Qt3DCore::QNodeId id) -{ - QVector<QBoundingVolume *> tris; - uint i = 0; - - const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); - const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); - - QVector3D abc[3]; - while (i < vertexInfo.count) { - for (uint u = 0; u < 6; u += 2) { - uint idx = (i + u) * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) { - abc[u / 2][j] = vertices[idx + j]; - } - } - tris.push_back(new TriangleBoundingVolume(id, abc[2], abc[1], abc[0])); - i += 6; - } - return tris; -} - - -template <QAttribute::DataType> struct EnumToType; -template <> struct EnumToType<QAttribute::Byte> { typedef const char type; }; -template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; }; -template <> struct EnumToType<QAttribute::Short> { typedef const short type; }; -template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; }; -template <> struct EnumToType<QAttribute::Int> { typedef const int type; }; -template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; }; -template <> struct EnumToType<QAttribute::Float> { typedef const float type; }; -template <> struct EnumToType<QAttribute::Double> { typedef const double type; }; - -template<QAttribute::DataType v> -typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset) -{ - return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset); -} - -template<typename ReturnType, typename Func> -QVector<QBoundingVolume *> processBuffer(const BufferInfo &info, Func &f) -{ - switch (info.type) { - case QAttribute::Byte: return f(info, castToType<QAttribute::Byte>(info.data, info.byteOffset)); - case QAttribute::UnsignedByte: return f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset)); - case QAttribute::Short: return f(info, castToType<QAttribute::Short>(info.data, info.byteOffset)); - case QAttribute::UnsignedShort: return f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset)); - case QAttribute::Int: return f(info, castToType<QAttribute::Int>(info.data, info.byteOffset)); - case QAttribute::UnsignedInt: return f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset)); - case QAttribute::Float: return f(info, castToType<QAttribute::Float>(info.data, info.byteOffset)); - case QAttribute::Double: return f(info, castToType<QAttribute::Double>(info.data, info.byteOffset)); - default: - return ReturnType(); - } -} - -template<typename Index, typename ReturnType> -struct IndexedVertexExecutor -{ - template<typename Vertex> - ReturnType operator ()(const BufferInfo &vertexInfo, Vertex * vertices) - { - switch (primitiveType) { - case Qt3DRender::QGeometryRenderer::Triangles: - return traverseTrianglesIndexed(indices, vertices, indexBufferInfo, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TriangleStrip: - return traverseTriangleStripIndexed(indices, vertices, indexBufferInfo, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TriangleFan: - return traverseTriangleFanIndexed(indices, vertices, indexBufferInfo, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TrianglesAdjacency: - return traverseTriangleAdjacencyIndexed(indices, vertices, indexBufferInfo, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: - default: - return ReturnType(); - } - } - - BufferInfo indexBufferInfo; - Index *indices; - Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType; - Qt3DCore::QNodeId id; -}; - -template<typename ReturnType> -struct IndexExecutor -{ - BufferInfo vertexBufferInfo; - - template<typename Index> - ReturnType operator ()( const BufferInfo &indexInfo, Index *indices) - { - IndexedVertexExecutor<Index, ReturnType> exec; - exec.primitiveType = primitiveType; - exec.indices = indices; - exec.indexBufferInfo = indexInfo; - exec.id = id; - return processBuffer<ReturnType>(vertexBufferInfo, exec); - } - - Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType; - Qt3DCore::QNodeId id; -}; - -template<typename ReturnType> -struct VertexExecutor -{ - template<typename Vertex> - ReturnType operator ()(const BufferInfo &vertexInfo, Vertex *vertices) - { - switch (primitiveType) { - case Qt3DRender::QGeometryRenderer::Triangles: - return traverseTriangles(vertices, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TriangleStrip: - return traverseTriangleStrip(vertices, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TriangleFan: - return traverseTriangleFan(vertices, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TrianglesAdjacency: - return traverseTriangleAdjacency(vertices, vertexInfo, id); - case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: - default: - return ReturnType(); - } - } - - Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType; - Qt3DCore::QNodeId id; -}; - -} // anonymous - TrianglesExtractor::TrianglesExtractor(GeometryRenderer *renderer, NodeManagers *manager) - : m_renderer(renderer) - , m_manager(manager) + : TrianglesVisitor(manager) + , m_renderer(renderer) { } QVector<QBoundingVolume *> TrianglesExtractor::extract(const Qt3DCore::QNodeId id) { - if (m_renderer && m_renderer->instanceCount() == 1 && isTriangleBased(m_renderer->primitiveType())) { - Attribute *positionAttribute = Q_NULLPTR; - Attribute *indexAttribute = Q_NULLPTR; - Buffer *positionBuffer = Q_NULLPTR; - Buffer *indexBuffer = Q_NULLPTR; - Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(m_renderer->geometryId()); - - if (geom) { - Qt3DRender::Render::Attribute *attribute = Q_NULLPTR; - Q_FOREACH (const Qt3DCore::QNodeId attrId, geom->attributes()) { - attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId); - if (attribute){ - if (attribute->name() == QAttribute::defaultPositionAttributeName()) - positionAttribute = attribute; - else if (attribute->attributeType() == QAttribute::IndexAttribute) - indexAttribute = attribute; - } - } - - if (positionAttribute) - positionBuffer = m_manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId()); - if (indexAttribute) - indexBuffer = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId()); - - if (positionBuffer) { - - BufferInfo vertexBufferInfo; - vertexBufferInfo.data = positionBuffer->data(); - vertexBufferInfo.type = positionAttribute->dataType(); - vertexBufferInfo.byteOffset = positionAttribute->byteOffset(); - vertexBufferInfo.byteStride = positionAttribute->byteStride(); - vertexBufferInfo.dataSize = positionAttribute->dataSize(); - vertexBufferInfo.count = positionAttribute->count(); - - if (indexBuffer) { // Indexed - - BufferInfo indexBufferInfo; - indexBufferInfo.data = indexBuffer->data(); - indexBufferInfo.type = indexAttribute->dataType(); - indexBufferInfo.byteOffset = indexAttribute->byteOffset(); - indexBufferInfo.byteStride = indexAttribute->byteStride(); - indexBufferInfo.count = indexAttribute->count(); - - IndexExecutor<QVector<QBoundingVolume *> > executor; - executor.vertexBufferInfo = vertexBufferInfo; - executor.primitiveType = m_renderer->primitiveType(); - executor.id = id; - - return processBuffer<QVector<QBoundingVolume *> >(indexBufferInfo, executor); - - } else { // Non Indexed - - // Check into which type the buffer needs to be casted - VertexExecutor<QVector<QBoundingVolume *> > executor; - executor.primitiveType = m_renderer->primitiveType(); - executor.id = id; + qDeleteAll(m_volumes); + apply(m_renderer, id); + return m_volumes; +} - return processBuffer<QVector<QBoundingVolume *> >(vertexBufferInfo, executor); - } - } - } - } - return QVector<QBoundingVolume *>(); +void TrianglesExtractor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c) +{ + Q_UNUSED(andx); Q_UNUSED(bndx); Q_UNUSED(cndx); + m_volumes.push_back(new TriangleBoundingVolume(m_nodeId, a, b, c)); } } // namespace Render diff --git a/src/render/backend/trianglesextractor_p.h b/src/render/backend/trianglesextractor_p.h index 7353278fe..0cb6d9b40 100644 --- a/src/render/backend/trianglesextractor_p.h +++ b/src/render/backend/trianglesextractor_p.h @@ -48,7 +48,7 @@ // We mean it. // -#include <Qt3DCore/qnodeid.h> +#include "trianglesvisitor_p.h" QT_BEGIN_NAMESPACE @@ -58,10 +58,7 @@ class QBoundingVolume; namespace Render { -class GeometryRenderer; -class NodeManagers; - -class Q_AUTOTEST_EXPORT TrianglesExtractor +class Q_AUTOTEST_EXPORT TrianglesExtractor : private TrianglesVisitor { public: explicit TrianglesExtractor(GeometryRenderer *renderer, @@ -70,8 +67,12 @@ public: QVector<QBoundingVolume *> extract(const Qt3DCore::QNodeId id); private: + void visit(uint andx, const QVector3D &a, + uint bndx, const QVector3D &b, + uint cndx, const QVector3D &c) Q_DECL_OVERRIDE; + GeometryRenderer *m_renderer; - NodeManagers *m_manager; + QVector<QBoundingVolume *> m_volumes; }; } // namespace Render diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp new file mode 100644 index 000000000..de4f833d5 --- /dev/null +++ b/src/render/backend/trianglesvisitor.cpp @@ -0,0 +1,518 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "trianglesvisitor_p.h" +#include <Qt3DCore/qentity.h> +#include <Qt3DRender/qgeometryrenderer.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/buffermanager_p.h> +#include <Qt3DRender/private/geometryrenderer_p.h> +#include <Qt3DRender/private/geometryrenderermanager_p.h> +#include <Qt3DRender/private/geometry_p.h> +#include <Qt3DRender/private/attribute_p.h> +#include <Qt3DRender/private/buffer_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +namespace { + +bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_NOEXCEPT +{ + switch (type) { + case Qt3DRender::QGeometryRenderer::Triangles: + case Qt3DRender::QGeometryRenderer::TriangleStrip: + case Qt3DRender::QGeometryRenderer::TriangleFan: + case Qt3DRender::QGeometryRenderer::TrianglesAdjacency: + case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: + return true; + default: + return false; + } +} + +struct BufferInfo +{ + BufferInfo() + : type(QAttribute::DataType::Float) + , dataSize(0) + , count(0) + , byteStride(0) + , byteOffset(0) + {} + + QByteArray data; + QAttribute::DataType type; + uint dataSize; + uint count; + uint byteStride; + uint byteOffset; +}; + +// TO DO: Add methods for triangle strip adjacency +// What about primitive restart ? + +// indices, vertices are already offset +template<typename index, typename vertex> +void traverseTrianglesIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + uint i = 0; + const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + while (i < indexInfo.count) { + for (uint u = 0; u < 3; ++u) { + uint idx = indices[i + u] * verticesStride; + ndx[u] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); + i += 3; + } +} + +// vertices are already offset +template<typename vertex> +void traverseTriangles(vertex *vertices, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + uint i = 0; + + const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + while (i < vertexInfo.count) { + for (uint u = 0; u < 3; ++u) { + uint idx = (i + u) * verticesStride; + ndx[u] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); + i += 3; + } +} + +// indices, vertices are already offset +template<typename index, typename vertex> +void traverseTriangleStripIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + uint i = 0; + const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + while (i < indexInfo.count) { + for (uint u = 0; u < 3; ++u) { + uint idx = indices[i + u] * verticesStride; + ndx[u] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); + ++i; + } +} + +// vertices are already offset +template<typename vertex> +void traverseTriangleStrip(vertex *vertices, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + uint i = 0; + + const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + while (i < vertexInfo.count) { + for (uint u = 0; u < 3; ++u) { + uint idx = (i + u) * verticesStride; + ndx[u] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[2], abc[0]); + ++i; + } +} + +// indices, vertices are already offset +template<typename index, typename vertex> +void traverseTriangleFanIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[0][j] = vertices[static_cast<int>(indices[0]) * verticesStride + j]; + } + + uint i = 1; + while (i < indexInfo.count) { + for (uint u = 0; u < 2; ++u) { + uint idx = indices[i + u] * verticesStride; + ndx[i] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u + 1][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); + i += 2; + } +} + +// vertices are already offset +template<typename vertex> +void traverseTriangleFan(vertex *vertices, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[0][j] = vertices[j]; + } + + uint i = 1; + while (i < vertexInfo.count) { + for (uint u = 0; u < 2; ++u) { + uint idx = (i + u) * verticesStride; + ndx[u] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u + 1][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); + i += 2; + } +} + +// indices, vertices are already offset +template<typename index, typename vertex> +void traverseTriangleAdjacencyIndexed(index *indices, + vertex *vertices, + const BufferInfo &indexInfo, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + uint i = 0; + const uint verticesStride = vertexInfo.byteStride / sizeof(vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + while (i < indexInfo.count) { + for (uint u = 0; u < 6; u += 2) { + uint idx = indices[i + u] * verticesStride; + ndx[u] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u / 2][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); + i += 6; + } +} + +// vertices are already offset +template<typename Vertex> +void traverseTriangleAdjacency(Vertex *vertices, + const BufferInfo &vertexInfo, + TrianglesVisitor* visitor) +{ + uint i = 0; + + const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex); + const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); + + uint ndx[3]; + QVector3D abc[3]; + while (i < vertexInfo.count) { + for (uint u = 0; u < 6; u += 2) { + uint idx = (i + u) * verticesStride; + ndx[u] = idx; + for (uint j = 0; j < maxVerticesDataSize; ++j) { + abc[u / 2][j] = vertices[idx + j]; + } + } + visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); + i += 6; + } +} + + +template <QAttribute::DataType> struct EnumToType; +template <> struct EnumToType<QAttribute::Byte> { typedef const char type; }; +template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; }; +template <> struct EnumToType<QAttribute::Short> { typedef const short type; }; +template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; }; +template <> struct EnumToType<QAttribute::Int> { typedef const int type; }; +template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; }; +template <> struct EnumToType<QAttribute::Float> { typedef const float type; }; +template <> struct EnumToType<QAttribute::Double> { typedef const double type; }; + +template<QAttribute::DataType v> +typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset) +{ + return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset); +} + +template<typename Func> +void processBuffer(const BufferInfo &info, Func &f) +{ + switch (info.type) { + case QAttribute::Byte: f(info, castToType<QAttribute::Byte>(info.data, info.byteOffset)); + return; + case QAttribute::UnsignedByte: f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset)); + return; + case QAttribute::Short: f(info, castToType<QAttribute::Short>(info.data, info.byteOffset)); + return; + case QAttribute::UnsignedShort: f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset)); + return; + case QAttribute::Int: f(info, castToType<QAttribute::Int>(info.data, info.byteOffset)); + return; + case QAttribute::UnsignedInt: f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset)); + return; + case QAttribute::Float: f(info, castToType<QAttribute::Float>(info.data, info.byteOffset)); + return; + case QAttribute::Double: f(info, castToType<QAttribute::Double>(info.data, info.byteOffset)); + return; + default: + return; + } +} + +template<typename Index> +struct IndexedVertexExecutor +{ + template<typename Vertex> + void operator ()(const BufferInfo &vertexInfo, Vertex * vertices) + { + switch (primitiveType) { + case Qt3DRender::QGeometryRenderer::Triangles: + traverseTrianglesIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TriangleStrip: + traverseTriangleStripIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TriangleFan: + traverseTriangleFanIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TrianglesAdjacency: + traverseTriangleAdjacencyIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through + default: + return; + } + } + + BufferInfo indexBufferInfo; + Index *indices; + Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType; + TrianglesVisitor* visitor; +}; + +struct IndexExecutor +{ + BufferInfo vertexBufferInfo; + + template<typename Index> + void operator ()( const BufferInfo &indexInfo, Index *indices) + { + IndexedVertexExecutor<Index> exec; + exec.primitiveType = primitiveType; + exec.indices = indices; + exec.indexBufferInfo = indexInfo; + exec.visitor = visitor; + processBuffer(vertexBufferInfo, exec); + } + + Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType; + TrianglesVisitor* visitor; +}; + +struct VertexExecutor +{ + template<typename Vertex> + void operator ()(const BufferInfo &vertexInfo, Vertex *vertices) + { + switch (primitiveType) { + case Qt3DRender::QGeometryRenderer::Triangles: + traverseTriangles(vertices, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TriangleStrip: + traverseTriangleStrip(vertices, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TriangleFan: + traverseTriangleFan(vertices, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TrianglesAdjacency: + traverseTriangleAdjacency(vertices, vertexInfo, visitor); + return; + case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through + default: + return; + } + } + + Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType; + TrianglesVisitor* visitor; +}; + +} // anonymous + + +TrianglesVisitor::~TrianglesVisitor() +{ + +} + +void TrianglesVisitor::apply(const Qt3DCore::QEntity *entity) +{ + GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(entity->id()); + apply(renderer, entity->id()); +} + +void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id) +{ + m_nodeId = id; + if (renderer && renderer->instanceCount() == 1 && isTriangleBased(renderer->primitiveType())) { + Attribute *positionAttribute = Q_NULLPTR; + Attribute *indexAttribute = Q_NULLPTR; + Buffer *positionBuffer = Q_NULLPTR; + Buffer *indexBuffer = Q_NULLPTR; + Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId()); + + if (geom) { + Qt3DRender::Render::Attribute *attribute = Q_NULLPTR; + Q_FOREACH (const Qt3DCore::QNodeId attrId, geom->attributes()) { + attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId); + if (attribute){ + if (attribute->name() == QAttribute::defaultPositionAttributeName()) + positionAttribute = attribute; + else if (attribute->attributeType() == QAttribute::IndexAttribute) + indexAttribute = attribute; + } + } + + if (positionAttribute) + positionBuffer = m_manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId()); + if (indexAttribute) + indexBuffer = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId()); + + if (positionBuffer) { + + BufferInfo vertexBufferInfo; + vertexBufferInfo.data = positionBuffer->data(); + vertexBufferInfo.type = positionAttribute->dataType(); + vertexBufferInfo.byteOffset = positionAttribute->byteOffset(); + vertexBufferInfo.byteStride = positionAttribute->byteStride(); + vertexBufferInfo.dataSize = positionAttribute->dataSize(); + vertexBufferInfo.count = positionAttribute->count(); + + if (indexBuffer) { // Indexed + + BufferInfo indexBufferInfo; + indexBufferInfo.data = indexBuffer->data(); + indexBufferInfo.type = indexAttribute->dataType(); + indexBufferInfo.byteOffset = indexAttribute->byteOffset(); + indexBufferInfo.byteStride = indexAttribute->byteStride(); + indexBufferInfo.count = indexAttribute->count(); + + IndexExecutor executor; + executor.vertexBufferInfo = vertexBufferInfo; + executor.primitiveType = renderer->primitiveType(); + executor.visitor = this; + + return processBuffer(indexBufferInfo, executor); + + } else { // Non Indexed + + // Check into which type the buffer needs to be casted + VertexExecutor executor; + executor.primitiveType = renderer->primitiveType(); + executor.visitor = this; + + return processBuffer(vertexBufferInfo, executor); + } + } + } + } +} + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h new file mode 100644 index 000000000..b2ee8dd36 --- /dev/null +++ b/src/render/backend/trianglesvisitor_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_TRIANGLESVISITOR_P_H +#define QT3DRENDER_RENDER_TRIANGLESVISITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DCore/qnodeid.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DCore { +class QEntity; +} + +namespace Qt3DRender { + +namespace Render { + +class GeometryRenderer; +class NodeManagers; + +class Q_AUTOTEST_EXPORT TrianglesVisitor +{ +public: + explicit TrianglesVisitor(NodeManagers *manager) : m_manager(manager) { } + virtual ~TrianglesVisitor(); + + void apply(const Qt3DCore::QEntity *entity); + void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id); + + virtual void visit(uint andx, const QVector3D &a, + uint bndx, const QVector3D &b, + uint cndx, const QVector3D &c) = 0; + +protected: + NodeManagers *m_manager; + Qt3DCore::QNodeId m_nodeId; +}; + +} // namespace Render + +} // namespace Qt3DRender + +QT_END_NAMESPACE + + +#endif // QT3DRENDER_RENDER_TRIANGLESVISITOR_P_H diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index bd14694cd..71ca42b80 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -371,19 +371,10 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) const QVector<QAspectJobPtr> geometryJobs = createGeometryRendererJobs(); jobs.append(geometryJobs); - - const QVector<QNodeId> geometryRendererTriangleUpdates = manager->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh(); - Q_FOREACH (const QNodeId geomRendererId, geometryRendererTriangleUpdates) { - Render::CalcGeometryTriangleVolumesPtr triangleComputeJob(new Render::CalcGeometryTriangleVolumes(geomRendererId, manager)); - triangleComputeJob->addDependency(d->m_framePreparationJob); - pickBoundingVolumeJob->addDependency(triangleComputeJob); - jobs.append(triangleComputeJob); - } - // Only add dependency if not already present const QVector<QWeakPointer<QAspectJob> > dependencies = pickBoundingVolumeJob->dependencies(); - if (std::find(dependencies.begin(), dependencies.end(), d->m_updateBoundingVolumeJob) == dependencies.end()) - pickBoundingVolumeJob->addDependency(d->m_updateBoundingVolumeJob); + if (std::find(dependencies.begin(), dependencies.end(), d->m_framePreparationJob) == dependencies.end()) + pickBoundingVolumeJob->addDependency(d->m_framePreparationJob); // Add all jobs to queue jobs.append(d->m_calculateBoundingVolumeJob); diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp index feeb7c422..ccffe2c84 100644 --- a/src/render/jobs/calcboundingvolumejob.cpp +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -123,9 +123,11 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node) const int stride = pickVolumeAttribute->byteStride() ? pickVolumeAttribute->byteStride() : sizeof(float) * pickVolumeAttribute->dataSize(); QVector<QVector3D> vertices(pickVolumeAttribute->count()); + // TODO avoid copying the vertices for (int c = 0, vC = vertices.size(); c < vC; ++c) { QVector3D v; const float *fptr = reinterpret_cast<const float*>(rawBuffer); + // TODO unwrap loop (switch?) for (uint i = 0, m = qMin(pickVolumeAttribute->dataSize(), 3U); i < m; ++i) v[i] = fptr[i]; vertices[c] = v; diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp index c592b348f..383127c27 100644 --- a/src/render/jobs/pickboundingvolumejob.cpp +++ b/src/render/jobs/pickboundingvolumejob.cpp @@ -47,7 +47,7 @@ #include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/sphere_p.h> #include <Qt3DRender/private/geometryrenderer_p.h> -#include <Qt3DRender/private/trianglesextractor_p.h> +#include <Qt3DRender/private/trianglesvisitor_p.h> #include <Qt3DRender/private/triangleboundingvolume_p.h> #include <Qt3DRender/private/qraycastingservice_p.h> #include <Qt3DRender/qgeometryrenderer.h> @@ -124,89 +124,159 @@ public: }; -QVector<QBoundingVolume *> gatherBoundingVolumes(Entity *entity) +QVector<Entity *> gatherEntities(Entity *entity) { - QVector<QBoundingVolume *> volumes; + QVector<Entity *> entities; if (entity != Q_NULLPTR) { - volumes.push_back(entity->worldBoundingVolume()); + entities.push_back(entity); // Traverse children Q_FOREACH (Entity *child, entity->children()) - volumes += gatherBoundingVolumes(child); + entities += gatherEntities(child); } - return volumes; + return entities; } -class SphereBoundingVolumesGatherer : public QBoundingVolumeProvider +class EntityGatherer { public: - explicit SphereBoundingVolumesGatherer(Entity *root) - : QBoundingVolumeProvider() - , m_root(root) + explicit EntityGatherer(Entity *root) + : m_root(root) , m_needsRefresh(true) { } - QVector<QBoundingVolume *> boundingVolumes() const Q_DECL_FINAL + QVector<Entity *> entities() const { if (m_needsRefresh) { - m_volumes = gatherBoundingVolumes(m_root); + m_entities = gatherEntities(m_root); m_needsRefresh = false; } - return m_volumes; + return m_entities; } private: Entity *m_root; - mutable QVector<QBoundingVolume *> m_volumes; + mutable QVector<Entity *> m_entities; mutable bool m_needsRefresh; }; - -class TriangleVolumeGatherer : public QBoundingVolumeProvider +class CollisionVisitor : public TrianglesVisitor { public: - explicit TriangleVolumeGatherer(Entity *root, NodeManagers *manager) - : QBoundingVolumeProvider() - , m_root(root) - , m_manager(manager) + typedef QVector<QCollisionQueryResult::Hit> HitList; + HitList hits; + + CollisionVisitor(NodeManagers* manager, const Entity *root, const Qt3DCore::QRay3D& ray) : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0) { } +private: + const Entity *m_root; + Qt3DCore::QRay3D m_ray; + Qt3DRender::QRayCastingService rayCasting; + uint m_triangleIndex; + + void visit(uint andx, const QVector3D &a, + uint bndx, const QVector3D &b, + uint cndx, const QVector3D &c) { - m_volumes = buildTriangleBoundingVolumes(); + TriangleBoundingVolume volume(m_root->peerUuid(), a, b, c); + volume = volume.transform(*m_root->worldTransform()); + + QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, &volume); + if (queryResult.m_distance > 0.) { + queryResult.m_triangleIndex = m_triangleIndex; + queryResult.m_vertexIndex[0] = andx; + queryResult.m_vertexIndex[1] = bndx; + queryResult.m_vertexIndex[2] = cndx; + hits.push_back(queryResult); + } + + m_triangleIndex++; } +}; + +struct CollisionGathererFunctor +{ + CollisionGathererFunctor() : m_renderer(0) { } + Renderer *m_renderer; + Qt3DCore::QRay3D m_ray; + + typedef CollisionVisitor::HitList result_type; - ~TriangleVolumeGatherer() + result_type operator ()(const Entity *entity) const { - qDeleteAll(m_volumes); + result_type result; + + HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + + // If the Entity which actually received the hit doesn't have + // an object picker component, we need to check the parent if it has one ... + while (objectPickerHandle.isNull() && entity != Q_NULLPTR) { + entity = entity->parent(); + if (entity != Q_NULLPTR) + objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + } + + ObjectPicker *objectPicker = m_renderer->nodeManagers()->objectPickerManager()->data(objectPickerHandle); + if (objectPicker == Q_NULLPTR) + return result; // don't bother picking entities that don't have an object picker + + GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>(); + if (!gRenderer) + return result; + + Qt3DRender::QRayCastingService rayCasting; + + if (rayHitsEntity(&rayCasting, entity)) { + CollisionVisitor visitor(m_renderer->nodeManagers(), entity, m_ray); + visitor.apply(gRenderer, entity->peerUuid()); + result = visitor.hits; + + struct + { + bool operator()(const result_type::value_type &a, const result_type::value_type &b) + { + return a.m_distance < b.m_distance; + } + } compareHitsDistance; + std::sort(result.begin(), result.end(), compareHitsDistance); + } + + return result; } - QVector<QBoundingVolume *> boundingVolumes() const Q_DECL_FINAL + bool rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const { - return m_volumes; + const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume()); + return queryResult.m_distance >= 0.f; } +}; -private: - QVector<QBoundingVolume *> buildTriangleBoundingVolumes() - { - QVector<QBoundingVolume *> volumes; - if (m_root) { - GeometryRenderer *gRenderer = m_root->renderComponent<GeometryRenderer>(); - if (gRenderer) { - const QVector<QBoundingVolume *> localVolumes = gRenderer->triangleData(); - volumes.reserve(localVolumes.size()); - Q_FOREACH (const QBoundingVolume *v, localVolumes) { - TriangleBoundingVolume *worldVolume = new TriangleBoundingVolume(); - *worldVolume = static_cast<const TriangleBoundingVolume *>(v)->transformed(*m_root->worldTransform()); - volumes.push_back(worldVolume); - } +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; + Q_FOREACH (const CollisionVisitor::HitList::value_type& v, intermediate) { + if (v.m_distance < closest) { + result.push_front(v); + closest = v.m_distance; } } - return volumes; + + while (result.size() > 1) + result.pop_back(); } + return result; +} - Entity *m_root; - NodeManagers *m_manager; - QVector<QBoundingVolume *> m_volumes; -}; +// Unordered +CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate) +{ + if (!intermediate.empty()) + results << intermediate; + return results; +} } // anonymous @@ -240,146 +310,125 @@ void PickBoundingVolumeJob::run() if (m_mouseEvents.empty()) return; - Qt3DCore::QServiceLocator *services = m_renderer->services(); - QAbstractCollisionQueryService *rayCasting = services->service<QAbstractCollisionQueryService> - (Qt3DCore::QServiceLocator::CollisionService); + ViewportCameraGatherer vcGatherer; + const QVector<ViewportCameraPair> vcPairs = vcGatherer.gather(m_renderer->frameGraphRoot()); - if (rayCasting == Q_NULLPTR) { - Qt3DRender::QRayCastingService *rayCastingService = new QRayCastingService(); - services->registerServiceProvider(Qt3DCore::QServiceLocator::CollisionService, rayCastingService); - rayCasting = rayCastingService; - } + EntityGatherer entitiesGatherer(m_node); - if (rayCasting != Q_NULLPTR) { - ViewportCameraGatherer vcGatherer; - const QVector<ViewportCameraPair> vcPairs = vcGatherer.gather(m_renderer->frameGraphRoot()); - - SphereBoundingVolumesGatherer sphereGatherer(m_node); - - if (!vcPairs.empty()) { - Q_FOREACH (const QMouseEvent &event, m_mouseEvents) { - m_hoveredPickersToClear = m_hoveredPickers; - ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); - Q_FOREACH (const ViewportCameraPair &vc, vcPairs) { - QVector<QCollisionQueryResult::Hit> sphereHits = sphereHitsForViewportAndCamera(event.pos(), - vc.viewport, - vc.cameraId, - rayCasting, - &sphereGatherer); -#if 0 - Q_FOREACH (const Qt3DCore::QCollisionQueryResult::Hit sphereHit, sphereHits) { - if (triangleHitsForViewportAndCamera(event.pos(), - vc.viewport, - vc.cameraId, - sphereHit.m_entityId, - rayCasting).isEmpty()) - sphereHits.removeAll(sphereHit); - } -#endif + if (!vcPairs.empty()) { + Q_FOREACH (const QMouseEvent &event, m_mouseEvents) { + m_hoveredPickersToClear = m_hoveredPickers; + ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); - // If we have hits - if (!sphereHits.isEmpty()) { - // Note: how can we control that we want the first/last/all elements along the ray to be picked + Q_FOREACH (const ViewportCameraPair &vc, vcPairs) { + typedef CollisionGathererFunctor::result_type HitList; + CollisionGathererFunctor gathererFunctor; + gathererFunctor.m_renderer = m_renderer; + gathererFunctor.m_ray = rayForViewportAndCamera(event.pos(), vc.viewport, vc.cameraId); + HitList sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reduceToAllHits); - // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having - // an ObjectPicker component when it comes + // If we have hits + if (!sphereHits.isEmpty()) { + // Note: how can we control that we want the first/last/all elements along the ray to be picked - // We want to gather hits against triangles - // build a triangle based bounding volume + // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having + // an ObjectPicker component when it comes - Q_FOREACH (const QCollisionQueryResult::Hit &hit, sphereHits) { - Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId); - HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + // We want to gather hits against triangles + // build a triangle based bounding volume - // If the Entity which actually received the hit doesn't have - // an object picker component, we need to check the parent if it has one ... - while (objectPickerHandle.isNull() && entity != Q_NULLPTR) { - entity = entity->parent(); - if (entity != Q_NULLPTR) - objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); - } + Q_FOREACH (const QCollisionQueryResult::Hit &hit, sphereHits) { + Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId); + HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); - ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle); - - if (objectPicker != Q_NULLPTR) { - // Send the corresponding event - QVector3D localIntersection = hit.m_intersection; - if (entity && entity->worldTransform()) - localIntersection = hit.m_intersection * entity->worldTransform()->inverted(); - QPickEventPtr pickEvent(new QPickEvent(hit.m_intersection, localIntersection, hit.m_distance)); - - switch (event.type()) { - case QEvent::MouseButtonPress: { - // Store pressed object handle - m_currentPicker = objectPickerHandle; - // Send pressed event to m_currentPicker - objectPicker->onPressed(pickEvent); - } - break; + // If the Entity which actually received the hit doesn't have + // an object picker component, we need to check the parent if it has one ... + while (objectPickerHandle.isNull() && entity != Q_NULLPTR) { + entity = entity->parent(); + if (entity != Q_NULLPTR) + objectPickerHandle = entity->componentHandle<ObjectPicker, 16>(); + } - case QEvent::MouseButtonRelease: { - // Send release event to m_currentPicker - if (lastCurrentPicker != Q_NULLPTR) { - lastCurrentPicker->onClicked(pickEvent); - lastCurrentPicker->onReleased(pickEvent); - } - break; - } + ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle); + + if (objectPicker != Q_NULLPTR) { + // Send the corresponding event + QVector3D localIntersection = hit.m_intersection; + if (entity && entity->worldTransform()) + localIntersection = hit.m_intersection * entity->worldTransform()->inverted(); + QPickEventPtr pickEvent(new QPickEvent(hit.m_intersection, localIntersection, hit.m_distance, + hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2])); + + switch (event.type()) { + case QEvent::MouseButtonPress: { + // Store pressed object handle + m_currentPicker = objectPickerHandle; + // Send pressed event to m_currentPicker + objectPicker->onPressed(pickEvent); + } + break; - case Qt::TapGesture: { - objectPicker->onClicked(pickEvent); - break; + case QEvent::MouseButtonRelease: { + // Send release event to m_currentPicker + if (lastCurrentPicker != Q_NULLPTR) { + lastCurrentPicker->onClicked(pickEvent); + lastCurrentPicker->onReleased(pickEvent); } + break; + } - case QEvent::HoverMove: - case QEvent::MouseMove: { - if (!m_hoveredPickers.contains(objectPickerHandle)) { - if (objectPicker->hoverEnabled()) { - // Send entered event to objectPicker - objectPicker->onEntered(); - // and save it in the hoveredPickers - m_hoveredPickers.push_back(objectPickerHandle); - } + case Qt::TapGesture: { + objectPicker->onClicked(pickEvent); + break; + } + + case QEvent::HoverMove: + case QEvent::MouseMove: { + if (!m_hoveredPickers.contains(objectPickerHandle)) { + if (objectPicker->hoverEnabled()) { + // Send entered event to objectPicker + objectPicker->onEntered(); + // and save it in the hoveredPickers + m_hoveredPickers.push_back(objectPickerHandle); } - break; } + break; + } - default: - break; - } + default: + break; } + } - // The ObjectPicker was hit -> it is still being hovered - m_hoveredPickersToClear.removeAll(objectPickerHandle); + // The ObjectPicker was hit -> it is still being hovered + m_hoveredPickersToClear.removeAll(objectPickerHandle); - lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); - } + lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker); + } - // Otherwise no hits - } else { - switch (event.type()) { - case QEvent::MouseButtonRelease: { - // Send release event to m_currentPicker - if (lastCurrentPicker != Q_NULLPTR) { - QPickEventPtr pickEvent(new QPickEvent); - lastCurrentPicker->onReleased(pickEvent); - } - break; - } - default: - break; + // Otherwise no hits + } else { + switch (event.type()) { + case QEvent::MouseButtonRelease: { + // Send release event to m_currentPicker + if (lastCurrentPicker != Q_NULLPTR) { + QPickEventPtr pickEvent(new QPickEvent); + lastCurrentPicker->onReleased(pickEvent); } + break; + } + default: + break; } } } - - // Clear Hovered elements that needs to be cleared - // Send exit event to object pickers on which we - // had set the hovered flag for a previous frame - // and that aren't being hovered any longer - clearPreviouslyHoveredPickers(); - } + + // Clear Hovered elements that needs to be cleared + // Send exit event to object pickers on which we + // had set the hovered flag for a previous frame + // and that aren't being hovered any longer + clearPreviouslyHoveredPickers(); } // Clear mouse events so that they aren't processed again for the next frame @@ -402,70 +451,36 @@ void PickBoundingVolumeJob::viewMatrixForCamera(const Qt3DCore::QNodeId &cameraI QRect PickBoundingVolumeJob::windowViewport(const QRectF &relativeViewport) const { - // // TO DO: find another way to retrieve the size since this won't work with Scene3D - // const QSurface *s = m_renderer->surface(); - // if (s) { - // const int surfaceWidth = s->size().width(); - // const int surfaceHeight = s->size().height(); - // return QRect(relativeViewport.x() * surfaceWidth, - // (1.0 - relativeViewport.y() - relativeViewport.height()) * surfaceHeight, - // relativeViewport.width() * surfaceWidth, - // relativeViewport.height() * surfaceHeight); - // } - // return relativeViewport.toRect(); - return QRect(); -} - - -QVector<QCollisionQueryResult::Hit> PickBoundingVolumeJob::sphereHitsForViewportAndCamera(const QPoint &pos, - const QRectF &relativeViewport, - const Qt3DCore::QNodeId &cameraId, - QAbstractCollisionQueryService *rayCasting, - QBoundingVolumeProvider *volumeProvider) const -{ - QMatrix4x4 viewMatrix; - QMatrix4x4 projectionMatrix; - viewMatrixForCamera(cameraId, viewMatrix, projectionMatrix); - const QRect viewport = windowViewport(relativeViewport); - - // const QSurface *s = m_renderer->surface(); // TO DO: find another way to retrieve the size since this won't work with Scene3D - // In GL the y is inverted compared to Qt - // const QPoint glCorrectPos = s ? QPoint(pos.x(), s->size().height() - pos.y()) : pos; - const QPoint glCorrectPos = pos; - const Qt3DCore::QRay3D ray = intersectionRay(glCorrectPos, viewMatrix, projectionMatrix, viewport); - const QQueryHandle rayCastingHandle = rayCasting->query(ray, QAbstractCollisionQueryService::AllHits, volumeProvider); - const QCollisionQueryResult queryResult = rayCasting->fetchResult(rayCastingHandle); - return queryResult.hits(); + // const QSize s = m_renderer->surfaceSize(); + // if (s.isValid()) { + // const int surfaceWidth = s.width(); + // const int surfaceHeight = s.height(); + // return QRect(relativeViewport.x() * surfaceWidth, + // (1.0 - relativeViewport.y() - relativeViewport.height()) * surfaceHeight, + // relativeViewport.width() * surfaceWidth, + // relativeViewport.height() * surfaceHeight); + // } + // return relativeViewport.toRect(); + return QRect(); } -QVector<QCollisionQueryResult::Hit> PickBoundingVolumeJob::triangleHitsForViewportAndCamera(const QPoint &pos, - const QRectF &relativeViewport, - const Qt3DCore::QNodeId &cameraId, - const Qt3DCore::QNodeId &entityId, - QAbstractCollisionQueryService *rayCasting) const +Qt3DCore::QRay3D PickBoundingVolumeJob::rayForViewportAndCamera(const QPoint &pos, + const QRectF &relativeViewport, + const Qt3DCore::QNodeId &cameraId) const { QMatrix4x4 viewMatrix; QMatrix4x4 projectionMatrix; viewMatrixForCamera(cameraId, viewMatrix, projectionMatrix); const QRect viewport = windowViewport(relativeViewport); - // const QSurface *s = m_renderer->surface(); // TO DO: find another way to retrieve the size since this won't work with Scene3D - // In GL the y is inverted compared to Qt - // const QPoint glCorrectPos = s ? QPoint(pos.x(), s->size().height() - pos.y()) : pos; + // const QSize s = m_renderer->surfaceSize(); + // // In GL the y is inverted compared to Qt + // const QPoint glCorrectPos = s.isValid() ? QPoint(pos.x(), s.height() - pos.y()) : pos; const QPoint glCorrectPos = pos; const Qt3DCore::QRay3D ray = intersectionRay(glCorrectPos, viewMatrix, projectionMatrix, viewport); - - // Note: improve this further to only compute this once and not every time - TriangleVolumeGatherer boundingVolumeProvider(m_manager->lookupResource<Entity, EntityManager>(entityId), - m_manager); - - const QQueryHandle rayCastingHandle = rayCasting->query(ray, - QAbstractCollisionQueryService::AllHits, - &boundingVolumeProvider); - const QCollisionQueryResult queryResult = rayCasting->fetchResult(rayCastingHandle); - return queryResult.hits(); + return ray; } void PickBoundingVolumeJob::clearPreviouslyHoveredPickers() @@ -484,4 +499,3 @@ void PickBoundingVolumeJob::clearPreviouslyHoveredPickers() } // namespace Qt3DRender QT_END_NAMESPACE - diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h index 37f5bcc41..459b88e9e 100644 --- a/src/render/jobs/pickboundingvolumejob_p.h +++ b/src/render/jobs/pickboundingvolumejob_p.h @@ -96,16 +96,9 @@ private: QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix) const; QRect windowViewport(const QRectF &relativeViewport) const; - QVector<QCollisionQueryResult::Hit> sphereHitsForViewportAndCamera(const QPoint &pos, - const QRectF &relativeViewport, - const Qt3DCore::QNodeId &cameraId, - QAbstractCollisionQueryService *rayCasting, - QBoundingVolumeProvider *volumeProvider) const; - QVector<QCollisionQueryResult::Hit> triangleHitsForViewportAndCamera(const QPoint &pos, - const QRectF &relativeViewport, - const Qt3DCore::QNodeId &cameraId, - const Qt3DCore::QNodeId &entityId, - QAbstractCollisionQueryService *rayCasting) const; + Qt3DCore::QRay3D rayForViewportAndCamera(const QPoint &pos, + const QRectF &relativeViewport, + const Qt3DCore::QNodeId &cameraId) const; void clearPreviouslyHoveredPickers(); HObjectPicker m_currentPicker; QVector<HObjectPicker> m_hoveredPickers; diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp index 420bab16f..a8f15dd08 100644 --- a/src/render/picking/qpickevent.cpp +++ b/src/render/picking/qpickevent.cpp @@ -55,6 +55,10 @@ public: QVector3D m_worldIntersection; QVector3D m_localIntersection; float m_distance; + uint m_triangleIndex; + uint m_vertex1Index; + uint m_vertex2Index; + uint m_vertex3Index; }; QPickEvent::QPickEvent() @@ -62,13 +66,18 @@ QPickEvent::QPickEvent() { } -QPickEvent::QPickEvent(const QVector3D &intersection, const QVector3D &localIntersection, float distance) +QPickEvent::QPickEvent(const QVector3D &intersection, const QVector3D &localIntersection, float distance, + uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index) : QObject(*new QPickEventPrivate()) { Q_D(QPickEvent); d->m_distance = distance; d->m_worldIntersection = intersection; d->m_localIntersection = localIntersection; + d->m_triangleIndex = triangleIndex; + d->m_vertex1Index = vertex1Index; + d->m_vertex2Index = vertex2Index; + d->m_vertex3Index = vertex3Index; } QPickEvent::~QPickEvent() @@ -108,6 +117,30 @@ const QVector3D &QPickEvent::localIntersection() const return d->m_localIntersection; } +uint QPickEvent::triangleIndex() const +{ + Q_D(const QPickEvent); + return d->m_triangleIndex; +} + +uint QPickEvent::vertex1Index() const +{ + Q_D(const QPickEvent); + return d->m_vertex1Index; +} + +uint QPickEvent::vertex2Index() const +{ + Q_D(const QPickEvent); + return d->m_vertex2Index; +} + +uint QPickEvent::vertex3Index() const +{ + Q_D(const QPickEvent); + return d->m_vertex3Index; +} + } // Qt3DRender QT_END_NAMESPACE diff --git a/src/render/picking/qpickevent.h b/src/render/picking/qpickevent.h index 4734a912d..4c705ffc6 100644 --- a/src/render/picking/qpickevent.h +++ b/src/render/picking/qpickevent.h @@ -57,9 +57,14 @@ class QT3DRENDERSHARED_EXPORT QPickEvent : public QObject Q_PROPERTY(float distance READ distance CONSTANT) Q_PROPERTY(QVector3D localIntersection READ localIntersection CONSTANT) Q_PROPERTY(QVector3D worldIntersection READ worldIntersection CONSTANT) + Q_PROPERTY(uint triangleIndex READ triangleIndex CONSTANT) + Q_PROPERTY(uint vertex1Index READ vertex1Index CONSTANT) + Q_PROPERTY(uint vertex2Index READ vertex2Index CONSTANT) + Q_PROPERTY(uint vertex3Index READ vertex3Index CONSTANT) public: QPickEvent(); - QPickEvent(const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance); + QPickEvent(const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance, + uint triangleIndex = 0, uint vertex1Index = 0, uint vertex2Index = 0, uint vertex3Index = 0); ~QPickEvent(); bool isAccepted() const; @@ -70,6 +75,10 @@ public Q_SLOTS: float distance() const; const QVector3D &worldIntersection() const; const QVector3D &localIntersection() const; + uint triangleIndex() const; + uint vertex1Index() const; + uint vertex2Index() const; + uint vertex3Index() const; Q_SIGNALS: void acceptedChanged(bool accepted); diff --git a/src/render/raycasting/qabstractcollisionqueryservice_p.h b/src/render/raycasting/qabstractcollisionqueryservice_p.h index 051946d5e..524a6d9f9 100644 --- a/src/render/raycasting/qabstractcollisionqueryservice_p.h +++ b/src/render/raycasting/qabstractcollisionqueryservice_p.h @@ -62,8 +62,10 @@ namespace Qt3DCore { class QRay3D; } +class QAbstractCollisionQueryServicePrivate; namespace Qt3DRender { +class QBoundingVolume; class QBoundingVolumeProvider; class QAbstractCollisionQueryServicePrivate : public Qt3DCore::QAbstractServiceProviderPrivate @@ -83,6 +85,7 @@ public: }; virtual QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode, QBoundingVolumeProvider *provider) = 0; + virtual QCollisionQueryResult::Hit query(const Qt3DCore::QRay3D &ray, const QBoundingVolume* volume) = 0; virtual QCollisionQueryResult fetchResult(const QQueryHandle &handle) = 0; virtual QVector<QCollisionQueryResult> fetchAllResults() const = 0; diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h index 21035e6a8..ca3f5b286 100644 --- a/src/render/raycasting/qcollisionqueryresult_p.h +++ b/src/render/raycasting/qcollisionqueryresult_p.h @@ -70,6 +70,8 @@ public: Qt3DCore::QNodeId m_entityId; QVector3D m_intersection; float m_distance; + uint m_triangleIndex; + uint m_vertexIndex[3]; }; QCollisionQueryResult(); diff --git a/src/render/raycasting/qraycastingservice.cpp b/src/render/raycasting/qraycastingservice.cpp index 0b183f087..f584e5f74 100644 --- a/src/render/raycasting/qraycastingservice.cpp +++ b/src/render/raycasting/qraycastingservice.cpp @@ -141,6 +141,19 @@ QCollisionQueryResult QRayCastingServicePrivate::collides(const Qt3DCore::QRay3D return result; } +QCollisionQueryResult::Hit QRayCastingServicePrivate::collides(const Qt3DCore::QRay3D &ray, const Qt3DRender::QBoundingVolume *volume) +{ + QCollisionQueryResult::Hit result; + Hit hit = volumeRayIntersection(volume, ray); + if (hit.intersects) + { + result.m_distance = hit.distance; + result.m_entityId = hit.id; + result.m_intersection = hit.intersection; + } + return result; +} + QRayCastingServicePrivate::QRayCastingServicePrivate(const QString &description) : QAbstractCollisionQueryServicePrivate(description) , m_handlesCount(0) @@ -170,6 +183,13 @@ QQueryHandle QRayCastingService::query(const Qt3DCore::QRay3D &ray, return handle; } +QCollisionQueryResult::Hit QRayCastingService::query(const Qt3DCore::QRay3D &ray, const QBoundingVolume *volume) +{ + Q_D(QRayCastingService); + + return d->collides(ray, volume); +} + QCollisionQueryResult QRayCastingService::fetchResult(const QQueryHandle &handle) { Q_D(QRayCastingService); diff --git a/src/render/raycasting/qraycastingservice_p.h b/src/render/raycasting/qraycastingservice_p.h index b4fdc1549..66c24fb8d 100644 --- a/src/render/raycasting/qraycastingservice_p.h +++ b/src/render/raycasting/qraycastingservice_p.h @@ -60,7 +60,6 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -class QBoundingVolume; class QBoundingVolumeProvider; class QRayCastingServicePrivate; @@ -72,6 +71,7 @@ public: QRayCastingService(); QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode, QBoundingVolumeProvider *provider) Q_DECL_OVERRIDE; + QCollisionQueryResult::Hit query(const Qt3DCore::QRay3D &ray, const QBoundingVolume *volume) Q_DECL_OVERRIDE; QCollisionQueryResult fetchResult(const QQueryHandle &handle) Q_DECL_OVERRIDE; QVector<QCollisionQueryResult> fetchAllResults() const Q_DECL_OVERRIDE; @@ -93,6 +93,8 @@ public: QBoundingVolumeProvider *provider, QAbstractCollisionQueryService::QueryMode mode, const QQueryHandle &handle); + QCollisionQueryResult::Hit collides(const Qt3DCore::QRay3D &ray, + const QBoundingVolume *volume); Q_DECLARE_PUBLIC(QRayCastingService) |