Browse Source

SceneGraph: ability to affect order of items drawn by Camera.

pull/272/head
Vladimír Vondruš 8 years ago
parent
commit
fafcdcfa1c
  1. 2
      doc/changelog.dox
  2. 20
      doc/snippets/MagnumSceneGraph.cpp
  3. 20
      src/Magnum/SceneGraph/Camera.h
  4. 29
      src/Magnum/SceneGraph/Camera.hpp
  5. 11
      src/Magnum/SceneGraph/Drawable.h
  6. 59
      src/Magnum/SceneGraph/Test/CameraTest.cpp

2
doc/changelog.dox

@ -84,6 +84,8 @@ See also:
@ref SceneGraph::TranslationRotationScalingTransformation3D transformation @ref SceneGraph::TranslationRotationScalingTransformation3D transformation
implementations that store separate translation, rotation and scaling implementations that store separate translation, rotation and scaling
parameters for easier use with animated scenes 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 @subsubsection changelog-latest-new-shaders Shaders library

20
doc/snippets/MagnumSceneGraph.cpp

@ -23,6 +23,8 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include "Magnum/Math/Matrix4.h" #include "Magnum/Math/Matrix4.h"
#include "Magnum/SceneGraph/Animable.h" #include "Magnum/SceneGraph/Animable.h"
#include "Magnum/SceneGraph/AnimableGroup.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<std::pair<std::reference_wrapper<SceneGraph::Drawable3D>, Matrix4>>
drawableTransformations = camera.drawableTransformations(drawableGroup);
std::sort(drawableTransformations.begin(), drawableTransformations.end(),
[](const std::pair<std::reference_wrapper<SceneGraph::Drawable3D>, Matrix4>& a,
const std::pair<std::reference_wrapper<SceneGraph::Drawable3D>, Matrix4>& b) {
return a.second.translation().z() < b.second.translation().z();
});
camera.draw(drawableTransformations);
/* [Drawable-draw-order] */
}
} }

20
src/Magnum/SceneGraph/Camera.h

@ -186,13 +186,33 @@ template<UnsignedInt dimensions, class T> class Camera: public AbstractFeature<d
*/ */
void setViewport(const Vector2i& size); void setViewport(const Vector2i& size);
/**
* @brief Drawable transformations
*
* Returns calculated transformations for given group of drawables.
* Useful in combination with @ref draw(const std::vector<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>>&)
* to provide custom draw order. See @ref SceneGraph-Drawable-draw-order
* for more information.
*/
std::vector<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>> drawableTransformations(DrawableGroup<dimensions, T>& group);
/** /**
* @brief Draw * @brief Draw
* *
* Draws given group of drawables. * Draws given group of drawables.
* @see @ref draw(const std::vector<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>>&)
*/ */
void draw(DrawableGroup<dimensions, T>& group); void draw(DrawableGroup<dimensions, T>& 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<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>>& drawableTransformations);
private: private:
/** Recalculates camera matrix */ /** Recalculates camera matrix */
void cleanInverted(const MatrixTypeFor<dimensions, T>& invertedAbsoluteTransformationMatrix) override { void cleanInverted(const MatrixTypeFor<dimensions, T>& invertedAbsoluteTransformationMatrix) override {

29
src/Magnum/SceneGraph/Camera.hpp

@ -82,6 +82,30 @@ template<UnsignedInt dimensions, class T> void Camera<dimensions, T>::setViewpor
fixAspectRatio(); fixAspectRatio();
} }
template<UnsignedInt dimensions, class T> std::vector<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>> Camera<dimensions, T>::drawableTransformations(DrawableGroup<dimensions, T>& group) {
AbstractObject<dimensions, T>* scene = AbstractFeature<dimensions, T>::object().scene();
CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", {});
/* Compute camera matrix */
AbstractFeature<dimensions, T>::object().setClean();
/* Compute transformations of all objects in the group relative to the camera */
std::vector<std::reference_wrapper<AbstractObject<dimensions, T>>> objects;
objects.reserve(group.size());
for(std::size_t i = 0; i != group.size(); ++i)
objects.push_back(group[i].object());
std::vector<MatrixTypeFor<dimensions, T>> transformations =
scene->transformationMatrices(objects, _cameraMatrix);
/* Combine drawable references and transformation matrices */
std::vector<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>> 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<UnsignedInt dimensions, class T> void Camera<dimensions, T>::draw(DrawableGroup<dimensions, T>& group) { template<UnsignedInt dimensions, class T> void Camera<dimensions, T>::draw(DrawableGroup<dimensions, T>& group) {
AbstractObject<dimensions, T>* scene = AbstractFeature<dimensions, T>::object().scene(); AbstractObject<dimensions, T>* scene = AbstractFeature<dimensions, T>::object().scene();
CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", ); CORRADE_ASSERT(scene, "Camera::draw(): cannot draw when camera is not part of any scene", );
@ -102,6 +126,11 @@ template<UnsignedInt dimensions, class T> void Camera<dimensions, T>::draw(Drawa
group[i].draw(transformations[i], *this); group[i].draw(transformations[i], *this);
} }
template<UnsignedInt dimensions, class T> void Camera<dimensions, T>::draw(const std::vector<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>>& drawableTransformations) {
for(auto&& drawableTransformation: drawableTransformations)
drawableTransformation.first.get().draw(drawableTransformation.second, *this);
}
}} }}
#endif #endif

11
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 @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<std::pair<std::reference_wrapper<Drawable<dimensions, T>>, MatrixTypeFor<dimensions, T>>>&) 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 @section SceneGraph-Drawable-explicit-specializations Explicit template specializations
The following specializations are explicitly compiled into @ref SceneGraph The following specializations are explicitly compiled into @ref SceneGraph

59
src/Magnum/SceneGraph/Test/CameraTest.cpp

@ -23,7 +23,9 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include "Magnum/SceneGraph/Camera.hpp" /* only for aspectRatioFix(), so it doesn't have to be exported */ #include "Magnum/SceneGraph/Camera.hpp" /* only for aspectRatioFix(), so it doesn't have to be exported */
#include "Magnum/SceneGraph/Camera.h" #include "Magnum/SceneGraph/Camera.h"
@ -45,7 +47,9 @@ struct CameraTest: TestSuite::Tester {
void projectionSizeOrthographic(); void projectionSizeOrthographic();
void projectionSizePerspective(); void projectionSizePerspective();
void projectionSizeViewport(); void projectionSizeViewport();
void draw(); void draw();
void drawOrdered();
}; };
typedef SceneGraph::Object<SceneGraph::MatrixTransformation2D> Object2D; typedef SceneGraph::Object<SceneGraph::MatrixTransformation2D> Object2D;
@ -61,7 +65,9 @@ CameraTest::CameraTest() {
&CameraTest::projectionSizeOrthographic, &CameraTest::projectionSizeOrthographic,
&CameraTest::projectionSizePerspective, &CameraTest::projectionSizePerspective,
&CameraTest::projectionSizeViewport, &CameraTest::projectionSizeViewport,
&CameraTest::draw});
&CameraTest::draw,
&CameraTest::drawOrdered});
} }
void CameraTest::fixAspectRatio() { void CameraTest::fixAspectRatio() {
@ -210,6 +216,57 @@ void CameraTest::draw() {
CORRADE_COMPARE(thirdTransformation, Matrix4()); CORRADE_COMPARE(thirdTransformation, Matrix4());
} }
void CameraTest::drawOrdered() {
class Drawable: public SceneGraph::Drawable3D {
public:
Drawable(AbstractObject3D& object, DrawableGroup3D* group, std::vector<Matrix4>& result): SceneGraph::Drawable3D(object, group), _result(result) {}
protected:
void draw(const Matrix4& transformationMatrix, Camera3D&) override {
_result.push_back(transformationMatrix);
}
private:
std::vector<Matrix4>& _result;
};
DrawableGroup3D group;
Scene3D scene;
std::vector<Matrix4> 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<std::pair<std::reference_wrapper<SceneGraph::Drawable3D>, Matrix4>> drawableTransformations = camera.drawableTransformations(group);
std::sort(drawableTransformations.begin(), drawableTransformations.end(),
[](const std::pair<std::reference_wrapper<SceneGraph::Drawable3D>, Matrix4>& a,
const std::pair<std::reference_wrapper<SceneGraph::Drawable3D>, 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>{
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) CORRADE_TEST_MAIN(Magnum::SceneGraph::Test::CameraTest)

Loading…
Cancel
Save