From fafcdcfa1caf606bbc8769f068ffad9f9d63cb13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2018 10:47:39 +0200 Subject: [PATCH] SceneGraph: ability to affect order of items drawn by Camera. --- doc/changelog.dox | 2 + doc/snippets/MagnumSceneGraph.cpp | 20 ++++++++ src/Magnum/SceneGraph/Camera.h | 20 ++++++++ src/Magnum/SceneGraph/Camera.hpp | 29 +++++++++++ src/Magnum/SceneGraph/Drawable.h | 11 +++++ src/Magnum/SceneGraph/Test/CameraTest.cpp | 59 ++++++++++++++++++++++- 6 files changed, 140 insertions(+), 1 deletion(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 84568ddb8..bc1218500 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -84,6 +84,8 @@ See also: @ref SceneGraph::TranslationRotationScalingTransformation3D transformation implementations that store separate translation, rotation and scaling parameters for easier use with animated scenes +- Ability to affect order of items drawn by @ref SceneGraph::Camera --- see + @ref SceneGraph-Drawable-draw-order for more information @subsubsection changelog-latest-new-shaders Shaders library diff --git a/doc/snippets/MagnumSceneGraph.cpp b/doc/snippets/MagnumSceneGraph.cpp index 3f5ac596f..31bc80029 100644 --- a/doc/snippets/MagnumSceneGraph.cpp +++ b/doc/snippets/MagnumSceneGraph.cpp @@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Math/Matrix4.h" #include "Magnum/SceneGraph/Animable.h" #include "Magnum/SceneGraph/AnimableGroup.h" @@ -329,4 +331,22 @@ camera.setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.001 } +{ +Object3D cameraObject; +SceneGraph::Camera3D camera{cameraObject}; +SceneGraph::DrawableGroup3D drawableGroup; +/* [Drawable-draw-order] */ +std::vector, Matrix4>> + drawableTransformations = camera.drawableTransformations(drawableGroup); + +std::sort(drawableTransformations.begin(), drawableTransformations.end(), + [](const std::pair, Matrix4>& a, + const std::pair, Matrix4>& b) { + return a.second.translation().z() < b.second.translation().z(); + }); + +camera.draw(drawableTransformations); +/* [Drawable-draw-order] */ +} + } diff --git a/src/Magnum/SceneGraph/Camera.h b/src/Magnum/SceneGraph/Camera.h index 140cdfc8b..61e9c87f3 100644 --- a/src/Magnum/SceneGraph/Camera.h +++ b/src/Magnum/SceneGraph/Camera.h @@ -186,13 +186,33 @@ template class Camera: public AbstractFeature>, MatrixTypeFor>>&) + * to provide custom draw order. See @ref SceneGraph-Drawable-draw-order + * for more information. + */ + std::vector>, MatrixTypeFor>> drawableTransformations(DrawableGroup& group); + /** * @brief Draw * * Draws given group of drawables. + * @see @ref draw(const std::vector>, MatrixTypeFor>>&) */ void draw(DrawableGroup& group); + /** + * @brief Draw given drawables with transformations + * + * Useful in combination with @ref drawableTransformations() for + * drawing in a custom order. See @ref SceneGraph-Drawable-draw-order + * for more information. + */ + void draw(const std::vector>, MatrixTypeFor>>& drawableTransformations); + private: /** Recalculates camera matrix */ void cleanInverted(const MatrixTypeFor& invertedAbsoluteTransformationMatrix) override { diff --git a/src/Magnum/SceneGraph/Camera.hpp b/src/Magnum/SceneGraph/Camera.hpp index 38a74ed2a..b13e3495c 100644 --- a/src/Magnum/SceneGraph/Camera.hpp +++ b/src/Magnum/SceneGraph/Camera.hpp @@ -82,6 +82,30 @@ template void Camera::setViewpor fixAspectRatio(); } +template std::vector>, MatrixTypeFor>> Camera::drawableTransformations(DrawableGroup& group) { + AbstractObject* scene = AbstractFeature::object().scene(); + CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", {}); + + /* Compute camera matrix */ + AbstractFeature::object().setClean(); + + /* Compute transformations of all objects in the group relative to the camera */ + std::vector>> objects; + objects.reserve(group.size()); + for(std::size_t i = 0; i != group.size(); ++i) + objects.push_back(group[i].object()); + std::vector> transformations = + scene->transformationMatrices(objects, _cameraMatrix); + + /* Combine drawable references and transformation matrices */ + std::vector>, MatrixTypeFor>> combined; + combined.reserve(group.size()); + for(std::size_t i = 0; i != group.size(); ++i) + combined.emplace_back(group[i], transformations[i]); + + return combined; +} + template void Camera::draw(DrawableGroup& group) { AbstractObject* scene = AbstractFeature::object().scene(); CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", ); @@ -102,6 +126,11 @@ template void Camera::draw(Drawa group[i].draw(transformations[i], *this); } +template void Camera::draw(const std::vector>, MatrixTypeFor>>& drawableTransformations) { + for(auto&& drawableTransformation: drawableTransformations) + drawableTransformation.first.get().draw(drawableTransformation.second, *this); +} + }} #endif diff --git a/src/Magnum/SceneGraph/Drawable.h b/src/Magnum/SceneGraph/Drawable.h index aa79f8b38..730b33c70 100644 --- a/src/Magnum/SceneGraph/Drawable.h +++ b/src/Magnum/SceneGraph/Drawable.h @@ -111,6 +111,17 @@ parameters once for whole group instead of setting them again in each @snippet MagnumSceneGraph-gl.cpp Drawable-multiple-groups +@section SceneGraph-Drawable-draw-order Custom draw order + +By default the contents of a drawable group are drawn in the order they were +added. In some cases you may want to draw them in a different order (for +example to have correctly sorted transparent objects) or draw just a subset +(for example to cull invisible objects way). That can be achieved using @ref Camera::drawableTransformations() +in combination with @ref Camera::draw(const std::vector>, MatrixTypeFor>>&) and applying @ref std::sort() with a custom +predicate on the drawable transformation list: + +@snippet MagnumSceneGraph.cpp Drawable-draw-order + @section SceneGraph-Drawable-explicit-specializations Explicit template specializations The following specializations are explicitly compiled into @ref SceneGraph diff --git a/src/Magnum/SceneGraph/Test/CameraTest.cpp b/src/Magnum/SceneGraph/Test/CameraTest.cpp index a2153185d..88905e300 100644 --- a/src/Magnum/SceneGraph/Test/CameraTest.cpp +++ b/src/Magnum/SceneGraph/Test/CameraTest.cpp @@ -23,7 +23,9 @@ DEALINGS IN THE SOFTWARE. */ +#include #include +#include #include "Magnum/SceneGraph/Camera.hpp" /* only for aspectRatioFix(), so it doesn't have to be exported */ #include "Magnum/SceneGraph/Camera.h" @@ -45,7 +47,9 @@ struct CameraTest: TestSuite::Tester { void projectionSizeOrthographic(); void projectionSizePerspective(); void projectionSizeViewport(); + void draw(); + void drawOrdered(); }; typedef SceneGraph::Object Object2D; @@ -61,7 +65,9 @@ CameraTest::CameraTest() { &CameraTest::projectionSizeOrthographic, &CameraTest::projectionSizePerspective, &CameraTest::projectionSizeViewport, - &CameraTest::draw}); + + &CameraTest::draw, + &CameraTest::drawOrdered}); } void CameraTest::fixAspectRatio() { @@ -210,6 +216,57 @@ void CameraTest::draw() { CORRADE_COMPARE(thirdTransformation, Matrix4()); } +void CameraTest::drawOrdered() { + class Drawable: public SceneGraph::Drawable3D { + public: + Drawable(AbstractObject3D& object, DrawableGroup3D* group, std::vector& result): SceneGraph::Drawable3D(object, group), _result(result) {} + + protected: + void draw(const Matrix4& transformationMatrix, Camera3D&) override { + _result.push_back(transformationMatrix); + } + + private: + std::vector& _result; + }; + + DrawableGroup3D group; + Scene3D scene; + + std::vector transformations; + + Object3D first(&scene); + first.scale(Vector3(5.0f)) + .translate(Vector3::zAxis(-1.0f)); + new Drawable{first, &group, transformations}; + + Object3D second(&scene); + second.translate(Vector3::zAxis(3.0f)); + new Drawable{second, &group, transformations}; + + Object3D third(&second); + third.translate(Vector3::zAxis(-1.5f)); + new Drawable{third, &group, transformations}; + + Camera3D camera(third); + + std::vector, Matrix4>> drawableTransformations = camera.drawableTransformations(group); + std::sort(drawableTransformations.begin(), drawableTransformations.end(), + [](const std::pair, Matrix4>& a, + const std::pair, Matrix4>& b) { + return a.second.translation().z() < b.second.translation().z(); + }); + + camera.draw(drawableTransformations); + + /* Should be ordered front to back, most negative Z first */ + CORRADE_COMPARE_AS(transformations, (std::vector{ + Matrix4::translation(Vector3::zAxis(-2.5f))*Matrix4::scaling(Vector3{5.0f}), /* first */ + Matrix4{}, /* third */ + Matrix4::translation(Vector3::zAxis(1.5f)) /* second */ + }), TestSuite::Compare::Container); +} + }}} CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::CameraTest)