From 02a6747b73588717b4c90a0717a38f222c9c74d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 18 Dec 2019 17:47:10 +0100 Subject: [PATCH] SceneGraph: show how to implement object culling on the drawable group. --- doc/snippets/MagnumSceneGraph.cpp | 31 +++++++++++++++++++++++++++++++ src/Magnum/SceneGraph/Camera.h | 12 ++++++------ src/Magnum/SceneGraph/Drawable.h | 21 ++++++++++++++++----- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/doc/snippets/MagnumSceneGraph.cpp b/doc/snippets/MagnumSceneGraph.cpp index 6d04c7f5e..bb911ac23 100644 --- a/doc/snippets/MagnumSceneGraph.cpp +++ b/doc/snippets/MagnumSceneGraph.cpp @@ -26,6 +26,7 @@ #include #include "Magnum/Math/Matrix4.h" +#include "Magnum/Math/Intersection.h" #include "Magnum/SceneGraph/Animable.h" #include "Magnum/SceneGraph/AnimableGroup.h" #include "Magnum/SceneGraph/AbstractGroupedFeature.h" @@ -349,4 +350,34 @@ camera.draw(drawableTransformations); /* [Drawable-draw-order] */ } +{ +Object3D cameraObject; +SceneGraph::Camera3D camera{cameraObject}; +SceneGraph::DrawableGroup3D drawableGroup; +/* [Drawable-culling] */ +struct CullableDrawable3D: SceneGraph::Drawable3D { + Range3D aabb; /* Relative to world origin */ + + // ... +}; + +/* Camera frustum relative to world origin */ +auto frustum = Frustum::fromMatrix(camera.projectionMatrix()*camera.cameraMatrix()); + +/* Erase all items that don't pass the frustum check */ +std::vector, Matrix4>> + drawableTransformations = camera.drawableTransformations(drawableGroup); +drawableTransformations.erase(std::remove_if( + drawableTransformations.begin(), drawableTransformations.end(), + [&](const std::pair, Matrix4>& a) { + Range3D aabb = static_cast(a.first.get()).aabb; + return !Math::Intersection::rangeFrustum(aabb, frustum); + }), + drawableTransformations.end()); + +/* Draw just the visible part */ +camera.draw(drawableTransformations); +/* [Drawable-culling] */ +} + } diff --git a/src/Magnum/SceneGraph/Camera.h b/src/Magnum/SceneGraph/Camera.h index 71c599fc1..820ffc4f4 100644 --- a/src/Magnum/SceneGraph/Camera.h +++ b/src/Magnum/SceneGraph/Camera.h @@ -189,10 +189,10 @@ template class Camera: public AbstractFeature>, MatrixTypeFor>>&) - * to provide custom draw order. See @ref SceneGraph-Drawable-draw-order - * for more information. + * Returns calculated camera-relative transformations for given group + * of drawables. Useful in combination with @ref draw(const std::vector>, MatrixTypeFor>>&) + * to implement custom draw order or object culling. See + * @ref SceneGraph-Drawable-draw-order for more information. */ std::vector>, MatrixTypeFor>> drawableTransformations(DrawableGroup& group); @@ -208,8 +208,8 @@ template class Camera: public AbstractFeature>, MatrixTypeFor>>& drawableTransformations); diff --git a/src/Magnum/SceneGraph/Drawable.h b/src/Magnum/SceneGraph/Drawable.h index 5d1dc7960..9a86f5232 100644 --- a/src/Magnum/SceneGraph/Drawable.h +++ b/src/Magnum/SceneGraph/Drawable.h @@ -111,17 +111,28 @@ 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 +@section SceneGraph-Drawable-draw-order Custom draw order and object culling -By default the contents of a drawable group are drawn in the order they were +By default all 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: +(for example to cull invisible objects away). That can be achieved using +@ref Camera::drawableTransformations() in combination with +@ref Camera::draw(const std::vector>, MatrixTypeFor>>&). +For example, to have the objects sorted back-to-front, apply @ref std::sort() +with a custom predicate on the drawable transformation list: @snippet MagnumSceneGraph.cpp Drawable-draw-order +Another use case is object-level culling --- assuming each drawable instance +provides an *absolute* AABB, one can calculate the transformations, cull them +via e.g. @ref Math::Intersection::rangeFrustum() and then pass the filtered +vector to @ref Camera::draw(). To be clear, this approach depends on AABBs +provided as relative to world origin, the actual object transformations don't +get used in any way except being passed to the draw function: + +@snippet MagnumSceneGraph.cpp Drawable-culling + @section SceneGraph-Drawable-explicit-specializations Explicit template specializations The following specializations are explicitly compiled into @ref SceneGraph