diff options
author | RĂ©mi Benoit <remi.benoit@kdab.com> | 2015-07-08 17:31:53 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2015-08-09 21:08:24 +0000 |
commit | 7ecc1c72a1ad9d636b4314181e418e830d37e424 (patch) | |
tree | 3450b88488c4a6c475e2584aae49508e49962e93 /tests | |
parent | 4c5e74986b0e649e4aadbc76022ad18c17ef44dc (diff) |
QRayCastingService implementation using bounding volumes
Bounding volumes are used to compute the collisions.
Returns all hits or only first bounding volume hit.
Change-Id: Ie40ffde56d126a63b1bdd498cdb7afae6eff1a9c
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/render/raycasting/raycasting.pro | 9 | ||||
-rw-r--r-- | tests/auto/render/raycasting/tst_raycasting.cpp | 303 | ||||
-rw-r--r-- | tests/auto/render/render.pro | 3 |
3 files changed, 314 insertions, 1 deletions
diff --git a/tests/auto/render/raycasting/raycasting.pro b/tests/auto/render/raycasting/raycasting.pro new file mode 100644 index 000000000..e389ef3d7 --- /dev/null +++ b/tests/auto/render/raycasting/raycasting.pro @@ -0,0 +1,9 @@ +TEMPLATE = app + +TARGET = tst_raycasting + +QT += 3dcore 3dcore-private 3drenderer 3drenderer-private testlib + +CONFIG += testcase + +SOURCES += tst_raycasting.cpp diff --git a/tests/auto/render/raycasting/tst_raycasting.cpp b/tests/auto/render/raycasting/tst_raycasting.cpp new file mode 100644 index 000000000..6b0a9d80a --- /dev/null +++ b/tests/auto/render/raycasting/tst_raycasting.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** 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 <QtTest/QtTest> +#include <Qt3DRenderer/private/renderentity_p.h> +#include <Qt3DRenderer/qraycastingservice.h> +#include <Qt3DRenderer/sphere.h> +#include <Qt3DCore/qboundingvolumeprovider.h> +#include <Qt3DCore/qray3d.h> + +using namespace Qt3D; +using namespace Qt3D::Render; + +class tst_RayCasting : public QObject +{ + Q_OBJECT +public: + tst_RayCasting() {} + ~tst_RayCasting() {} + +private Q_SLOTS: + void shouldReturnValidHandle(); + void shouldReturnResultForEachHandle(); + void shouldReturnAllResults(); + void shouldReturnHits(); + void shouldReturnHits_data(); + void shouldIntersect_data(); + void shouldIntersect(); + void shouldUseProvidedBoudingVolumes(); + + void cleanupTestCase(); + +private: + Sphere *volumeAt(int index); + QVector<Sphere> boundingVolumes; +}; + +void tst_RayCasting::shouldIntersect_data() +{ + QTest::addColumn<QRay3D>("ray"); + QTest::addColumn<Sphere>("sphere"); + QTest::addColumn<int>("shouldIntersect"); + + QRay3D ray(QVector3D(1, 1, 1), QVector3D(0, 0, 1)); + + Sphere sphere1(QVector3D(1, 1, 1), 2); + Sphere sphere2(QVector3D(0, 0, 0), 3); + Sphere sphere3(QVector3D(0, 1, 3), 1); + Sphere sphere4(QVector3D(4, 4, 5), 1); + Sphere sphere5(QVector3D(2, 2, 11), 5); + Sphere sphere6(QVector3D(2, 2, 13), 1); + Sphere sphere7(QVector3D(2, 2, 15), 5); + + QTest::newRow("Ray starts inside sphere") << ray << sphere1 << 1; + QTest::newRow("Ray starts inside sphere") << ray << sphere2 << 1; + QTest::newRow("Ray intersects sphere tangentially") << ray << sphere3 << 1; + QTest::newRow("No intersection") << ray << sphere4 << 0; + QTest::newRow("Ray intersect sphere") << ray << sphere5 << 1; + QTest::newRow("No intersection") << ray << sphere6 << 0; + QTest::newRow("Ray intersect sphere") << ray << sphere7 << 1; +} + +void tst_RayCasting::shouldIntersect() +{ + QFETCH(QRay3D, ray); + QFETCH(Sphere, sphere); + QFETCH(int, shouldIntersect); + + QVector3D intersectionPoint; + + QCOMPARE(sphere.intersects(ray, &intersectionPoint), shouldIntersect); +} + +class MyBoudingVolumesProvider : public QBoundingVolumeProvider +{ +public: + MyBoudingVolumesProvider(QVector<QBoundingVolume *> volumes) + : m_volumes(volumes) + {} + + QVector<QBoundingVolume *> boundingVolumes() const + { + return m_volumes; + } + +private: + QVector<QBoundingVolume *> m_volumes; +}; + +void tst_RayCasting::shouldReturnValidHandle() +{ + // GIVEN + QRay3D ray; + Sphere v1; + MyBoudingVolumesProvider provider = QVector<QBoundingVolume *>() << &v1; + + QRayCastingService service(&provider); + + // WHEN + QQueryHandle handle = service.query(ray, QAbstractCollisionQueryService::AllHits); + + // THEN + QVERIFY(handle >= 0); + + // Wait the query to finish + service.fetchResult(handle); +} + +void tst_RayCasting::shouldReturnResultForEachHandle() +{ + // GIVEN + QRay3D ray; + QVector<QBoundingVolume *> volumes; + MyBoudingVolumesProvider provider(volumes); + + QRayCastingService service(&provider); + + QQueryHandle handle1 = service.query(ray, QAbstractCollisionQueryService::AllHits); + QQueryHandle handle2 = service.query(ray, QAbstractCollisionQueryService::FirstHit); + + // WHEN + QCollisionQueryResult result2 = service.fetchResult(handle2); + QCollisionQueryResult result1 = service.fetchResult(handle1); + + // THEN + QCOMPARE(result1.handle(), handle1); + QCOMPARE(result2.handle(), handle2); +} + +void tst_RayCasting::shouldReturnAllResults() +{ + // GIVEN + QRay3D ray; + QVector<QBoundingVolume *> volumes; + MyBoudingVolumesProvider provider(volumes); + + QRayCastingService service(&provider); + + QVector<QQueryHandle> handles; + handles.append(service.query(ray, QAbstractCollisionQueryService::AllHits)); + handles.append(service.query(ray, QAbstractCollisionQueryService::FirstHit)); + + // WHEN + QVector<QCollisionQueryResult> results = service.fetchAllResults(); + + // THEN + bool expectedHandlesFound = true; + Q_FOREACH (QQueryHandle expected, handles) { + bool found = false; + Q_FOREACH (QCollisionQueryResult result, results) { + if (result.handle() == expected) + found = true; + } + + expectedHandlesFound &= found; + } + + QVERIFY(expectedHandlesFound); +} + +void tst_RayCasting::shouldReturnHits_data() +{ + QTest::addColumn<QRay3D>("ray"); + QTest::addColumn<QVector<QBoundingVolume *> >("volumes"); + QTest::addColumn<QVector<QNodeId> >("hits"); + QTest::addColumn<QAbstractCollisionQueryService::QueryMode >("queryMode"); + + QRay3D ray(QVector3D(1, 1, 1), QVector3D(0, 0, 1)); + + this->boundingVolumes.clear(); + this->boundingVolumes.append(QVector<Sphere>() << Sphere(QVector3D(1, 1, 1), 3, QNodeId::createId()) + << Sphere(QVector3D(0, 0, 0), 3, QNodeId::createId()) + << Sphere(QVector3D(0, 1, 3), 1, QNodeId::createId()) + << Sphere(QVector3D(4, 4, 5), 1, QNodeId::createId()) + << Sphere(QVector3D(2, 2, 11), 5, QNodeId::createId()) + << Sphere(QVector3D(2, 2, 13), 1, QNodeId::createId()) + << Sphere(QVector3D(2, 2, 15), 5, QNodeId::createId())); + + QTest::newRow("All hits, One sphere intersect") << ray + << (QVector<QBoundingVolume *> () << volumeAt(0) << volumeAt(3)) + << (QVector<QNodeId>() << volumeAt(0)->id()) + << QAbstractCollisionQueryService::AllHits; + + QTest::newRow("All hits, Three sphere intersect") << ray + << (QVector<QBoundingVolume *> () << volumeAt(0) << volumeAt(3) << volumeAt(6) << volumeAt(2)) + << (QVector<QNodeId>() << volumeAt(0)->id() << volumeAt(6)->id() << volumeAt(2)->id()) + << QAbstractCollisionQueryService::AllHits; + + QTest::newRow("All hits, No sphere intersect") << ray + << (QVector<QBoundingVolume *> () << volumeAt(3) << volumeAt(5)) + << (QVector<QNodeId>()) + << QAbstractCollisionQueryService::AllHits; + + QTest::newRow("Sphere 1 intersect, returns First Hit") << ray + << (QVector<QBoundingVolume *> () << volumeAt(0) << volumeAt(3) << volumeAt(1)) + << (QVector<QNodeId>() << volumeAt(0)->id()) + << QAbstractCollisionQueryService::FirstHit; + + QTest::newRow("Sphere 3 and 5 intersects, returns First Hit") << ray + << (QVector<QBoundingVolume *> () << volumeAt(3) << volumeAt(6) << volumeAt(4)) + << (QVector<QNodeId>() << volumeAt(4)->id()) + << QAbstractCollisionQueryService::FirstHit; + + QTest::newRow("Sphere 5 and 3 intersects, unordered list, returns First Hit") << ray + << (QVector<QBoundingVolume *> () << volumeAt(4) << volumeAt(3) << volumeAt(6)) + << (QVector<QNodeId>() << volumeAt(4)->id()) + << QAbstractCollisionQueryService::FirstHit; + + QTest::newRow("No sphere intersect, returns First Hit") << ray + << (QVector<QBoundingVolume *> () << volumeAt(3) << volumeAt(5)) + << (QVector<QNodeId>()) + << QAbstractCollisionQueryService::FirstHit; +} + +void tst_RayCasting::shouldReturnHits() +{ + // GIVEN + QFETCH(QRay3D, ray); + QFETCH(QVector<QBoundingVolume *>, volumes); + QFETCH(QVector<QNodeId>, hits); + QFETCH(QAbstractCollisionQueryService::QueryMode, queryMode); + + MyBoudingVolumesProvider provider(volumes); + QRayCastingService service(&provider); + + // WHEN + QQueryHandle handle = service.query(ray, queryMode); + QCollisionQueryResult result = service.fetchResult(handle); + + // THEN + QCOMPARE(result.entitiesHit().size(), hits.size()); + QCOMPARE(result.entitiesHit(), hits); +} + +void tst_RayCasting::shouldUseProvidedBoudingVolumes() +{ + // GIVEN + QRay3D ray(QVector3D(1, 1, 1), QVector3D(0, 0, 1)); + + Sphere sphere1(QVector3D(1, 1, 1), 3); + Sphere sphere3(QVector3D(0, 1, 3), 1); + Sphere sphere4(QVector3D(4, 4, 5), 1); + + MyBoudingVolumesProvider provider(QVector<QBoundingVolume *>() << &sphere1 << &sphere4 << &sphere3); + QVector<QNodeId> hits(QVector<QNodeId>() << sphere1.id() << sphere3.id()); + + QRayCastingService service(&provider); + + // WHEN + QQueryHandle handle = service.query(ray, QAbstractCollisionQueryService::AllHits); + QCollisionQueryResult result = service.fetchResult(handle); + + // THEN + QCOMPARE(result.entitiesHit().size(), hits.size()); + QCOMPARE(result.entitiesHit(), hits); +} + +void tst_RayCasting::cleanupTestCase() +{ + this->boundingVolumes.clear(); +} + +Sphere *tst_RayCasting::volumeAt(int index) +{ + return &*(boundingVolumes.begin() + index); +} + +QTEST_APPLESS_MAIN(tst_RayCasting) + +#include "tst_raycasting.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index f008bee8a..f9bf2b7d4 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -20,5 +20,6 @@ contains(QT_CONFIG, private_tests) { renderbuffer \ renderattribute \ rendergeometry \ - rendergeometryrenderer + rendergeometryrenderer \ + raycasting } |