From 9fd25a1fd8fa38ae1f761ddd69b29b183ab12bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Jan 2015 02:12:41 +0100 Subject: [PATCH] SceneGraph: there is never enough documentation. --- doc/scenegraph.dox | 217 +++++++++++++----- src/Magnum/AbstractFramebuffer.cpp | 2 +- src/Magnum/SceneGraph/AbstractFeature.h | 58 ++--- src/Magnum/SceneGraph/AbstractObject.h | 10 +- .../SceneGraph/AbstractTransformation.h | 3 +- src/Magnum/SceneGraph/AbstractTranslation.h | 8 +- .../AbstractTranslationRotation2D.h | 4 +- .../AbstractTranslationRotation3D.h | 4 +- .../AbstractTranslationRotationScaling2D.h | 4 +- .../AbstractTranslationRotationScaling3D.h | 4 +- src/Magnum/SceneGraph/Animable.h | 21 +- src/Magnum/SceneGraph/Camera2D.h | 8 +- src/Magnum/SceneGraph/Camera3D.h | 10 +- src/Magnum/SceneGraph/Drawable.h | 77 +++++-- .../SceneGraph/DualComplexTransformation.h | 2 +- .../SceneGraph/DualQuaternionTransformation.h | 2 +- .../SceneGraph/MatrixTransformation2D.h | 2 +- .../SceneGraph/MatrixTransformation3D.h | 3 +- src/Magnum/SceneGraph/Object.h | 5 +- .../SceneGraph/RigidMatrixTransformation2D.h | 2 +- .../SceneGraph/RigidMatrixTransformation3D.h | 3 +- .../SceneGraph/TranslationTransformation.h | 10 +- 22 files changed, 297 insertions(+), 162 deletions(-) diff --git a/doc/scenegraph.dox b/doc/scenegraph.dox index a333a1594..e4fb15e32 100644 --- a/doc/scenegraph.dox +++ b/doc/scenegraph.dox @@ -56,41 +56,83 @@ three main components: @section scenegraph-transformation Transformations Transformation handles object position, rotation etc. and its basic property -is dimension count (2D or 3D) and underlying floating-point type. +is dimension count (2D or 3D) and underlying floating-point type. All classes +in @ref SceneGraph are templated on underlying type. However, in most cases +@ref Float "Float" is used and thus nearly all classes have convenience aliases +so you don't have to explicitly specify it. + +Scene graph has various transformation implementations for both 2D and 3D. Each +implementation has its own advantages and disadvantages -- for example when +using matrices you can have nearly arbitrary transformations, but composing +transformations, computing their inverse and accounting for floating-point +drift is rather costly operation. On the other hand quaternions won't allow you +to scale or shear objects, but have far better performance characteristics. -@note All classes in @ref SceneGraph are templated on underlying type. However, - in most cases @ref Float "Float" is used and thus nearly all classes have - convenience aliases so you don't have to explicitly specify it. +It's also possible to implement your own transformation class for specific +needs, see source of builtin transformation classes for more information. + +Magnum provides the following transformation classes. See documentation of each +class for more detailed information: + +- @ref SceneGraph::BasicMatrixTransformation2D "SceneGraph::MatrixTransformation2D" -- + arbitrary 2D transformations but with slow inverse transformations and no + floating-point drift reduction +- @ref SceneGraph::BasicMatrixTransformation3D "SceneGraph::MatrixTransformation3D" -- + arbitrary 3D transformations but with slow inverse transformations and no + floating-point drift reduction +- @ref SceneGraph::BasicRigidMatrixTransformation2D "SceneGraph::RigidMatrixTransformation2D" -- + 2D translation, rotation and reflection (no scaling), with relatively fast + inverse transformations and floating-point drift reduction +- @ref SceneGraph::BasicRigidMatrixTransformation3D "SceneGraph::RigidMatrixTransformation3D" -- + 3D translation, rotation and reflection (no scaling), with relatively fast + inverse transformations and floating-point drift reduction +- @ref SceneGraph::BasicDualComplexTransformation "SceneGraph::DualComplexTransformation" -- + 2D translation and rotation with fast inverse transformations and + floating-point drift reduction +- @ref SceneGraph::BasicDualQuaternionTransformation "SceneGraph::DualQuaternionTransformation" -- + 3D translation and rotation with fast inverse transformation and + floating-point drift reduction +- @ref SceneGraph::TranslationTransformation "SceneGraph::TranslationTransformation*D" -- + Just 2D/3D translation (no rotation, scaling or anything else) + +Common usage of transformation classes is to typedef Scene and Object with +desired transformation type to save unnecessary typing later: +@code +typedef SceneGraph::Scene Scene3D; +typedef SceneGraph::Object Object3D; +@endcode -Scene graph has implementation of transformations in both 2D and 3D, using -either matrices or combination of position and rotation. Each implementation -has its own advantages and disadvantages -- for example when using matrices -you can have nearly arbitrary transformations, but composing transformations -and computing their inverse is costly operation. On the other hand quaternions -won't allow you to scale or shear objects, but are more memory efficient than -matrices. +@attention Note that you have to include both @ref Magnum/SceneGraph/Object.h + and desired transformation class (e.g. @ref Magnum/SceneGraph/MatrixTransformation3D.h) + to be able to use the resulting type. -It's also possible to implement your own transformation class for specific -needs, see source of other transformation classes for more information. +The object type is subclassed from the transformation type and so the +`Object3D` type will then contain all members from both @ref SceneGraph::Object +and @ref SceneGraph::MatrixTransformation3D. For convenience you can use method +chaining: +@code +Scene3D scene; + +Object3D object; +object.setParent(&scene) + .rotateY(15.0_degf) + .translate(Vector3::xAxis(5.0f)); +@endcode @section scenegraph-hierarchy Scene hierarchy Scene hierarchy is skeleton part of scene graph. In the root there is @ref SceneGraph::Scene and its children are @ref SceneGraph::Object instances. -The hierarchy has some transformation type, identical for all objects (because +Whole hierarchy has one transformation type, identical for all objects (because for example having part of the tree in 2D and part in 3D just wouldn't make -sense). Common usage is to typedef Scene and Object with desired transformation -type to save unnecessary typing later: -@code -typedef SceneGraph::Scene Scene3D; -typedef SceneGraph::Object Object3D; -@endcode +sense). Then you can start building the hierarchy by *parenting* one object to another. -Parent object can be either passed in constructor or using +Parent object can be either passed in constructor or set using @ref SceneGraph::Object::setParent(). Scene is always root object, so it -naturally cannot have parent object. List of object children can be accessed -through @ref SceneGraph::Object::children(). +naturally cannot have parent object. Parent and children relationships can be +observed through @ref SceneGraph::Object::parent() and +@ref SceneGraph::Object::children(). @code Scene3D scene; @@ -98,52 +140,62 @@ auto first = new Object3D(&scene); auto second = new Object3D(first); @endcode -The hierarchy takes care of memory management - when an object is destroyed, +The hierarchy takes care of memory management -- when an object is destroyed, all its children are destroyed too. See detailed explanation of @ref scenegraph-object-construction-order "construction and destruction order" -for information about possible issues. - -The object is derived from the transformation you specified earlier in the -`typedef`, so you can directly transform the objects using methods of given -transformation implementation. Scene, as a root object, cannot have any -transformation. For convenience you can use method chaining: -@code -auto next = new Object3D; -next->setParent(another) - .translate(Vector3::yAxis(3.0f)) - .rotateY(35.0_degf); -@endcode +below for information about possible issues. @section scenegraph-features Object features The object itself handles only parent/child relationship and transformation. -To make the object renderable, animatable, add collision shape to it etc., you +To make the object renderable, animable, add collision shape to it etc., you have to add a *feature* to it. -Each feature takes reference to holder object in constructor, so adding a -feature to an object might look just like this, as in some cases you don't even -need to keep the pointer to it. List of object features is accessible through -@ref SceneGraph::Object::features(). +Magnum provides the following builtin features. See documentation of each class +for more detailed information and usage examples: + +- @ref SceneGraph::AbstractCamera "SceneGraph::Camera*D" -- Handles + projection matrix, aspect ratio correction etc.. Used for rendering parts + of the scene. +- @ref SceneGraph::Drawable "SceneGraph::Drawable*D" -- Adds drawing + functionality to given object. Group of drawables can be then rendered + using the camera feature. +- @ref SceneGraph::Animable "SceneGraph::Animable*D" -- Adds animation + functionality to given object. Group of animables can be then controlled + using @ref SceneGraph::AnimableGroup "SceneGraph::AnimableGroup*D". +- @ref Shapes::Shape -- Adds collision shape to given object. Group of shapes + can be then controlled using @ref Shapes::ShapeGroup "Shapes::ShapeGroup*D". + See @ref shapes for more information. +- @ref DebugTools::ObjectRenderer "DebugTools::ObjectRenderer*D", + @ref DebugTools::ShapeRenderer "DebugTools::ShapeRenderer*D", + @ref DebugTools::ForceRenderer "DebugTools::ForceRenderer*D" -- Visualize + object properties, object shape or force vector for debugging purposes. See + @ref debug-tools for more information. + +Each feature takes reference to *holder object* in constructor, so adding a +feature to an object might look just like the following, as in some cases you +don't even need to keep the pointer to it. List of object features is +accessible through @ref SceneGraph::Object::features(). @code Object3D* o; -new MyFeature(o); +new MyFeature{*o}; @endcode Some features are passive, some active. Passive features can be just added to -an object like above, without any additional work (for example collision -shape). Active features require the user to implement some virtual function -(for example to draw the object on screen or perform animation step). To make -things convenient, features can be added directly to object itself using -multiple inheritance, so you can conveniently add all the active features you -want and implement needed functions in your own @ref SceneGraph::Object +an object, with no additional work except for possible configuration (for +example collision shape). Active features require the user to implement some +virtual function (for example to draw the object on screen or perform animation +step). To make things convenient, features can be added directly to object +itself using multiple inheritance, so you can conveniently add all the active +features you want and implement needed functions in your own @ref SceneGraph::Object subclass without having to subclass each feature individually (and making the code overly verbose). Simplified example: @code -class Bomb: public Object3D, SceneGraph::Drawable3D, SceneGraph::Animable3D { +class BouncingBall: public Object3D, SceneGraph::Drawable3D, SceneGraph::Animable3D { public: - Bomb(Object3D* parent): Object3D(parent), SceneGraph::Drawable3D(*this), SceneGraph::Animable3D(*this) {} + explicit BouncingBall(Object3D* parent): Object3D{parent}, SceneGraph::Drawable3D{*this}, SceneGraph::Animable3D{*this} {} - protected: + private: // drawing implementation for Drawable feature void draw(...) override; @@ -161,15 +213,15 @@ member and inherited) are destroyed. See detailed explanation of @ref scenegraph-feature-construction-order "construction and destruction order" for information about possible issues. -@section scenegraph-caching Transformation caching +@subsection scenegraph-features-caching Transformation caching in features Some features need to operate with absolute transformations and their -inversions - for example camera needs its inverse transformation to render the +inversions -- for example camera needs its inverse transformation to render the scene, collision detection needs to know about positions of surrounding objects etc. To avoid computing the transformations from scratch every time, the feature can cache them. -The cached data stay until the object is marked as dirty - that is by changing +The cached data stay until the object is marked as dirty -- that is by changing transformation, changing parent or explicitly calling @ref SceneGraph::Object::setDirty(). If the object is marked as dirty, all its children are marked as dirty too and @ref SceneGraph::AbstractFeature::markDirty() is called on every feature. @@ -189,17 +241,17 @@ and then implement corresponding cleaning function(s): @code class CachingObject: public Object3D, SceneGraph::AbstractFeature3D { public: - CachingObject(Object3D* parent): SceneGraph::AbstractFeature3D(*this) { + explicit CachingObject(Object3D* parent): Object3D{parent}, SceneGraph::AbstractFeature3D{*this} { setCachedTransformations(SceneGraph::CachedTransformation::Absolute); } protected: void clean(const Matrix4& absoluteTransformation) override { - absolutePosition = absoluteTransformation.translation(); + _absolutePosition = absoluteTransformation.translation(); } private: - Vector3 absolutePosition; + Vector3 _absolutePosition; }; @endcode @@ -208,7 +260,56 @@ by calling @ref SceneGraph::Object::setClean(). @ref SceneGraph::Camera3D "Camer for example, calls it automatically before it starts rendering, as it needs its own inverse transformation to properly draw the objects. -See @ref SceneGraph-AbstractFeature-subclassing-caching for more information. +@subsection scenegraph-features-transformation Polymorphic access to object transformation + +Features by default have access only to @ref SceneGraph::AbstractObject, which +doesn't know about any particular transformation implementation. This has the +advantage that features don't have to be implemented for all possible +transformation implementations. But, as a consequence, it is impossible to +transform the object using only pointer to @ref SceneGraph::AbstractObject. + +To solve this, the transformation classes are subclassed from interfaces +sharing common functionality, so the feature can use that interface instead of +being specialized for all relevant transformation implementations. The +following interfaces are available, each having its own set of virtual +functions to control the transformation: + +- @ref SceneGraph::AbstractTransformation "SceneGraph::AbstractTransformation*D" -- + base for all transformations +- @ref SceneGraph::AbstractTranslation "SceneGraph::AbstractTranslation*D" -- + base for all transformations providing translation +- @ref SceneGraph::AbstractBasicTranslationRotation2D "SceneGraph::AbstractTranslationRotation2D", + @ref SceneGraph::AbstractBasicTranslationRotation3D "SceneGraph::AbstractTranslationRotation3D" -- + base for all transformations providing translation and rotation +- @ref SceneGraph::AbstractBasicTranslationRotationScaling2D "SceneGraph::AbstractBasicTranslationRotationScaling2D", + @ref SceneGraph::AbstractBasicTranslationRotationScaling3D "SceneGraph::AbstractBasicTranslationRotationScaling3D" -- + base for all transformations providing translation, rotation and scaling + +These interfaces provide virtual functions which can be used to modify object +transformations. The virtual calls are used only when calling through the +interface and not when using the concrete implementation directly to avoid +negative performance effects. There are no functions to retrieve object +transformation, you need to use the above transformation caching mechanism for +that. + +In the following example we are able to get pointer to both +@ref SceneGraph::AbstractObject and needed transformation from one +constructor parameter using small trick: +@code +class TransformingFeature: public SceneGraph::AbstractFeature3D { + public: + template TransformingFeature(SceneGraph::Object& object): + SceneGraph::AbstractFeature3D(object), transformation(object) {} + + private: + SceneGraph::AbstractTranslationRotation3D& transformation; +}; +@endcode +If we take for example @ref SceneGraph::Object "SceneGraph::Object", +it is derived from @ref SceneGraph::AbstractObject "SceneGraph::AbstractObject3D" +and @ref SceneGraph::BasicMatrixTransformation3D "SceneGraph::MatrixTransformation3D", +thus the reference to @ref SceneGraph::AbstractBasicTranslationRotation3D "SceneGraph::AbstractTranslationRotation3D", +is automatically extracted from the reference in our constructor. @section scenegraph-construction-order Construction and destruction order diff --git a/src/Magnum/AbstractFramebuffer.cpp b/src/Magnum/AbstractFramebuffer.cpp index 80a70cce1..e158fc6c2 100644 --- a/src/Magnum/AbstractFramebuffer.cpp +++ b/src/Magnum/AbstractFramebuffer.cpp @@ -224,7 +224,7 @@ void AbstractFramebuffer::setViewportInternal() { glViewport(_viewport.left(), _viewport.bottom(), _viewport.sizeX(), _viewport.sizeY()); } -AbstractFramebuffer& AbstractFramebuffer::clear(FramebufferClearMask mask) { +AbstractFramebuffer& AbstractFramebuffer::clear(const FramebufferClearMask mask) { #ifndef MAGNUM_TARGET_GLES2 bindInternal(FramebufferTarget::Draw); #else diff --git a/src/Magnum/SceneGraph/AbstractFeature.h b/src/Magnum/SceneGraph/AbstractFeature.h index 8a2a6da8c..127ff95ac 100644 --- a/src/Magnum/SceneGraph/AbstractFeature.h +++ b/src/Magnum/SceneGraph/AbstractFeature.h @@ -40,7 +40,7 @@ namespace Magnum { namespace SceneGraph { /** @brief Which transformation to cache in given feature -@see @ref scenegraph-caching, @ref CachedTransformations, +@see @ref scenegraph-features-caching, @ref CachedTransformations, @ref AbstractFeature::setCachedTransformations(), @ref AbstractFeature::clean(), @ref AbstractFeature::cleanInverted() @todo Provide also simpler representations from which could benefit @@ -68,7 +68,7 @@ enum class CachedTransformation: UnsignedByte { /** @brief Which transformations to cache in this feature -@see @ref scenegraph-caching, @ref AbstractFeature::setCachedTransformations(), +@see @ref scenegraph-features-caching, @ref AbstractFeature::setCachedTransformations(), @ref AbstractFeature::clean(), @ref AbstractFeature::cleanInverted() */ typedef Containers::EnumSet CachedTransformations; @@ -90,12 +90,11 @@ Feature is templated on dimension count and underlying transformation type, so it can be used only on object having transformation with the same dimension count and type. -@anchor SceneGraph-AbstractFeature-subclassing-caching ### Caching transformations in features Features can cache absolute transformation of the object instead of computing it from scratch every time to achieve better performance. See -@ref scenegraph-caching for introduction. +@ref scenegraph-features-caching for introduction. In order to have caching, you must enable it first, because by default the caching is disabled. You can enable it using @ref setCachedTransformations() @@ -104,17 +103,16 @@ and then implement corresponding cleaning function(s) -- either @ref clean(), @code class CachingFeature: public SceneGraph::AbstractFeature3D { public: - CachingFeature(SceneGraph::AbstractObject3D& object): SceneGraph::AbstractFeature3D(object) { + explicit CachingFeature(SceneGraph::AbstractObject3D& object): SceneGraph::AbstractFeature3D{object} { setCachedTransformations(CachedTransformation::Absolute); } - protected: + private: void clean(const Matrix4& absoluteTransformationMatrix) override { - absolutePosition = absoluteTransformationMatrix.translation(); + _absolutePosition = absoluteTransformationMatrix.translation(); } - private: - Vector3 absolutePosition; + Vector3 _absolutePosition; }; @endcode @@ -123,33 +121,22 @@ Before using the cached value explicitly request object cleaning by calling ### Accessing object transformation -Features has by default access only to @ref AbstractObject, which is base of -@ref Object not depending on any particular transformation implementation. This -has the advantage that features doesn't have to be implemented for all possible -transformation implementations, thus preventing code duplication. However it -is impossible to transform the object using only pointer to @ref AbstractObject. - -The transformations have interfaces for common functionality, so the feature -can use that interface instead of being specialized for all relevant -transformation implementations. Using small trick we are able to get pointer -to both @ref AbstractObject and needed transformation from one constructor -parameter: +The feature has by default only access to @ref AbstractObject, which doesn't +know about any used transformation. By using small template trick in the +constructor it is possible to gain access to transformation interface in the +constructor: @code class TransformingFeature: public SceneGraph::AbstractFeature3D { public: - template TransformingFeature(SceneGraph::Object& object): - SceneGraph::AbstractFeature3D(object), transformation(object) {} + template explicit TransformingFeature(SceneGraph::Object& object): + SceneGraph::AbstractFeature3D{object}, _transformation{object} {} private: - SceneGraph::AbstractTranslationRotation3D& transformation; + SceneGraph::AbstractTranslationRotation3D& _transformation; }; @endcode -If we take for example @ref Object "Object", it is -derived from @ref AbstractObject "AbstractObject3D" and -@ref BasicMatrixTransformation3D "MatrixTransformation3D", which is derived -from @ref AbstractBasicTranslationRotationScaling3D "AbstractTranslationRotationScaling3D", -which is derived from @ref AbstractBasicTranslationRotation3D "AbstractTranslationRotation3D", -which is automatically extracted from the reference in our constructor. + +See @ref scenegraph-features-transformation for more detailed information. ## Explicit template specializations @@ -222,13 +209,14 @@ template class AbstractFeature /** * @{ @name Transformation caching * - * See @ref scenegraph-caching for more information. + * See @ref scenegraph-features-caching for more information. */ /** * @brief Which transformations are cached * - * @see @ref scenegraph-caching, @ref clean(), @ref cleanInverted() + * @see @ref scenegraph-features-caching, @ref clean(), + * @ref cleanInverted() */ CachedTransformations cachedTransformations() const { return _cachedTransformations; @@ -243,7 +231,7 @@ template class AbstractFeature * transformation. * * Nothing is enabled by default. - * @see @ref scenegraph-caching + * @see @ref scenegraph-features-caching */ void setCachedTransformations(CachedTransformations transformations) { _cachedTransformations = transformations; @@ -257,7 +245,7 @@ template class AbstractFeature * done in @ref clean() and @ref cleanInverted(). * * Default implementation does nothing. - * @see @ref scenegraph-caching + * @see @ref scenegraph-features-caching */ virtual void markDirty(); @@ -269,7 +257,7 @@ template class AbstractFeature * to recalculate data based on absolute object transformation. * * Default implementation does nothing. - * @see @ref scenegraph-caching, @ref cleanInverted() + * @see @ref scenegraph-features-caching, @ref cleanInverted() */ virtual void clean(const MatrixTypeFor& absoluteTransformationMatrix); @@ -282,7 +270,7 @@ template class AbstractFeature * transformation. * * Default implementation does nothing. - * @see @ref scenegraph-caching, @ref clean() + * @see @ref scenegraph-features-caching, @ref clean() */ virtual void cleanInverted(const MatrixTypeFor& invertedAbsoluteTransformationMatrix); diff --git a/src/Magnum/SceneGraph/AbstractObject.h b/src/Magnum/SceneGraph/AbstractObject.h index 637bfaed4..35e858d48 100644 --- a/src/Magnum/SceneGraph/AbstractObject.h +++ b/src/Magnum/SceneGraph/AbstractObject.h @@ -212,7 +212,7 @@ template class AbstractObject /** * @{ @name Transformation caching * - * See @ref scenegraph-caching for more information. + * See @ref scenegraph-features-caching for more information. */ /** @@ -251,7 +251,7 @@ template class AbstractObject * Returns `true` if transformation of the object or any parent has * changed since last call to @ref setClean(), `false` otherwise. All * objects are dirty by default. - * @see @ref scenegraph-caching + * @see @ref scenegraph-features-caching */ bool isDirty() const { return doIsDirty(); } @@ -262,7 +262,8 @@ template class AbstractObject * recursively calls @ref setDirty() on every child object which is not * already dirty. If the object is already marked as dirty, the * function does nothing. - * @see @ref scenegraph-caching, @ref setClean(), @ref isDirty() + * @see @ref scenegraph-features-caching, @ref setClean(), + * @ref isDirty() */ void setDirty() { doSetDirty(); } @@ -277,7 +278,8 @@ template class AbstractObject * See also @ref setClean(const std::vector*>&), * which cleans given set of objects more efficiently than when calling * @ref setClean() on each object individually. - * @see @ref scenegraph-caching, @ref setDirty(), @ref isDirty() + * @see @ref scenegraph-features-caching, @ref setDirty(), + * @ref isDirty() */ void setClean() { doSetClean(); } diff --git a/src/Magnum/SceneGraph/AbstractTransformation.h b/src/Magnum/SceneGraph/AbstractTransformation.h index 3fe264457..54c4b9d2a 100644 --- a/src/Magnum/SceneGraph/AbstractTransformation.h +++ b/src/Magnum/SceneGraph/AbstractTransformation.h @@ -39,7 +39,8 @@ namespace Magnum { namespace SceneGraph { /** @brief Base for transformations -Provides transformation implementation for @ref Object instances. +Provides transformation implementation for @ref Object instances. See +@ref scenegraph-features-transformation for more information. @anchor SceneGraph-AbstractTransformation-explicit-specializations ## Explicit template specializations diff --git a/src/Magnum/SceneGraph/AbstractTranslation.h b/src/Magnum/SceneGraph/AbstractTranslation.h index dbf2c3c95..86e72c42c 100644 --- a/src/Magnum/SceneGraph/AbstractTranslation.h +++ b/src/Magnum/SceneGraph/AbstractTranslation.h @@ -38,13 +38,15 @@ namespace Magnum { namespace SceneGraph { /** @brief Base transformation for two-dimensional scenes supporting translation +See @ref scenegraph-features-transformation for more information. + By default the translation is stored with the same underlying type as resulting transformation matrix, but it's possible to store translation in e.g. integral coordinates while having floating-point transformation matrix. -@see @ref AbstractBasicTranslation2D, @ref AbstractBasicTranslation3D, - @ref AbstractTranslation2D, @ref AbstractTranslation3D, @ref scenegraph, - @ref TranslationTransformation +@see @ref scenegraph, @ref AbstractBasicTranslation2D, + @ref AbstractBasicTranslation3D, @ref AbstractTranslation2D, + @ref AbstractTranslation3D, @ref TranslationTransformation */ #ifdef DOXYGEN_GENERATING_OUTPUT template diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h b/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h index 2ab7806c7..982a01437 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h @@ -36,7 +36,9 @@ namespace Magnum { namespace SceneGraph { /** @brief Base transformation for two-dimensional scenes supporting translation and rotation -@see @ref AbstractTranslationRotation2D, @ref scenegraph, +See @ref scenegraph-features-transformation for more information. + +@see @ref scenegraph, @ref AbstractTranslationRotation2D, @ref AbstractBasicTranslationRotation3D, @ref BasicRigidMatrixTransformation2D, @ref BasicDualComplexTransformation */ diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h b/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h index 8bacc2f5a..a4f39d458 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h @@ -36,7 +36,9 @@ namespace Magnum { namespace SceneGraph { /** @brief Base transformation for three-dimensional scenes supporting translation and rotation -@see @ref AbstractTranslationRotation3D @ref scenegraph, +See @ref scenegraph-features-transformation for more information. + +@see @ref scenegraph, @ref AbstractTranslationRotation3D, @ref AbstractBasicTranslationRotation2D, @ref BasicRigidMatrixTransformation3D, @ref BasicDualQuaternionTransformation diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h index 4315273af..c7415509a 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h @@ -36,7 +36,9 @@ namespace Magnum { namespace SceneGraph { /** @brief Base transformation for two-dimensional scenes supporting translation, rotation and scaling -@see @ref AbstractTranslationRotationScaling2D, @ref scenegraph, +See @ref scenegraph-features-transformation for more information. + +@see @ref scenegraph, @ref AbstractTranslationRotationScaling2D, @ref AbstractBasicTranslationRotationScaling2D, @ref BasicMatrixTransformation2D */ diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h index 73e2f59b7..43cd615dc 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h @@ -36,7 +36,9 @@ namespace Magnum { namespace SceneGraph { /** @brief Base transformation for three-dimensional scenes supporting translation, rotation and scaling -@see @ref AbstractTranslationRotationScaling3D, @ref scenegraph, +See @ref scenegraph-features-transformation for more information. + +@see @ref scenegraph, @ref AbstractTranslationRotationScaling3D, @ref AbstractBasicTranslationRotationScaling2D, @ref BasicMatrixTransformation3D */ diff --git a/src/Magnum/SceneGraph/Animable.h b/src/Magnum/SceneGraph/Animable.h index ebba40887..b0770a261 100644 --- a/src/Magnum/SceneGraph/Animable.h +++ b/src/Magnum/SceneGraph/Animable.h @@ -78,22 +78,25 @@ typedef SceneGraph::Scene Scene3D; class AnimableObject: public Object3D, SceneGraph::Animable3D { public: - AnimableObject(Object* parent = nullptr, SceneGraph::DrawableGroup3D* group = nullptr): Object3D(parent), SceneGraph::Animable3D(*this, group) { + AnimableObject(Object3D* parent = nullptr, SceneGraph::DrawableGroup3D* group = nullptr): Object3D{parent}, SceneGraph::Animable3D{*this, group} { setDuration(10.0f); // ... } + private: void animationStep(Float time, Float delta) override { rotateX(15.0_degf*delta); // rotate at 15 degrees per second } } @endcode -Then add the object to your scene and some animation group. You can also use -@ref AnimableGroup::add() and @ref AnimableGroup::remove() instead of passing -the group in the constructor. The animation is initially in stopped state and -without repeat, see @ref setState(), @ref setRepeated() and -@ref setRepeatCount() for more information. +Similarly to @ref Drawable feature, there is no way to just animate all the +objects in the scene. You need to create animable group and use it to control +given set of animations. You can also use @ref AnimableGroup::add() and +@ref AnimableGroup::remove() instead of passing the group in the constructor. +The animation is initially in stopped state and without repeat, see +@ref setState(), @ref setRepeated() and @ref setRepeatCount() for more +information. @code Scene3D scene; SceneGraph::AnimableGroup3D animables; @@ -120,13 +123,13 @@ void MyApplication::drawEvent() { } @endcode -## Using animable groups to improve performance +## Using multiple animable groups to improve performance @ref AnimableGroup is optimized for case when no animation is running -- it just puts itself to rest and waits until some animation changes its state to @ref AnimationState::Running again. If you put animations which are not -pernamently running to separate group, they will not be always traversed when -calling @ref AnimableGroup::step(), saving precious frame time. +pernamently running into separate group, they will not be traversed every time +the @ref AnimableGroup::step() gets called, saving precious frame time. ## Explicit template specializations diff --git a/src/Magnum/SceneGraph/Camera2D.h b/src/Magnum/SceneGraph/Camera2D.h index 18aa96c7a..2d01c2620 100644 --- a/src/Magnum/SceneGraph/Camera2D.h +++ b/src/Magnum/SceneGraph/Camera2D.h @@ -36,11 +36,11 @@ namespace Magnum { namespace SceneGraph { /** @brief Camera for two-dimensional scenes -See Drawable documentation for introduction. The camera by default displays -OpenGL unit cube `[(-1, -1, -1); (1, 1, 1)]` and doesn't do any aspect ratio -correction. Common setup example: +See @ref Drawable documentation for complete introduction. The camera by +default displays OpenGL unit cube `[(-1, -1, -1); (1, 1, 1)]` and doesn't do +any aspect ratio correction. Common setup example: @code -SceneGraph::Camera2D camera(&cameraObject); +SceneGraph::Camera2D camera{&cameraObject}; camera.setProjection({4.0f/3.0f, 1.0f}) .setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend); @endcode diff --git a/src/Magnum/SceneGraph/Camera3D.h b/src/Magnum/SceneGraph/Camera3D.h index 37bf51fe0..82e65e436 100644 --- a/src/Magnum/SceneGraph/Camera3D.h +++ b/src/Magnum/SceneGraph/Camera3D.h @@ -41,12 +41,12 @@ namespace Magnum { namespace SceneGraph { /** @brief Camera for three-dimensional scenes -See Drawable documentation for introduction. The camera by default displays -OpenGL unit cube `[(-1, -1, -1); (1, 1, 1)]` with orthographic projection and -doesn't do any aspect ratio correction. Common setup example: +See @ref Drawable documentation for complete introduction. The camera by +default displays OpenGL unit cube `[(-1, -1, -1); (1, 1, 1)]` with orthographic +projection and doesn't do any aspect ratio correction. Common setup example: @code -SceneGraph::Camera3D camera(&cameraObject); -camera.setPerspective({}, 0.001f, 100.0f) +SceneGraph::Camera3D camera{&cameraObject}; +camera.setPerspective(35.0_degf, 1.0f, 0.001f, 100.0f) .setAspectRatioPolicy(SceneGraph::AspectRatioPolicy::Extend); @endcode diff --git a/src/Magnum/SceneGraph/Drawable.h b/src/Magnum/SceneGraph/Drawable.h index ba4c24586..6279205a2 100644 --- a/src/Magnum/SceneGraph/Drawable.h +++ b/src/Magnum/SceneGraph/Drawable.h @@ -36,62 +36,94 @@ namespace Magnum { namespace SceneGraph { /** @brief Drawable -Adds drawing function to the object. Each Drawable is part of some -@ref DrawableGroup and the whole group is drawn with particular camera using -@ref AbstractCamera::draw(). +Adds drawing functionality to the object. Each Drawable is part of some +@ref DrawableGroup and the whole group can be drawn with particular camera +using @ref AbstractCamera::draw(). ## Usage First thing is to add @ref Drawable feature to some object and implement -@ref draw(). You can do it conveniently using multiple inheritance (see -@ref scenegraph-features for introduction). Example: +@ref draw() function. You can do it conveniently using multiple inheritance +(see @ref scenegraph-features for introduction). Example drawable object that +draws blue sphere: @code typedef SceneGraph::Object Object3D; typedef SceneGraph::Scene Scene3D; -class DrawableObject: public Object3D, SceneGraph::Drawable3D { +class RedCube: public Object3D, SceneGraph::Drawable3D { public: - DrawableObject(Object* parent = nullptr, SceneGraph::DrawableGroup3D* group = nullptr): Object3D(parent), SceneGraph::Drawable3D(*this, group) { - // ... + RedCube(Object3D* parent, SceneGraph::DrawableGroup3D* group): Object3D{parent}, SceneGraph::Drawable3D{*this, group} { + std::tie(_mesh, _vertices, _indices) = MeshTools::compile(Primitives::UVSPhere::solid(16, 32)); } + private: void draw(const Matrix4& transformationMatrix, AbstractCamera3D& camera) override { - // ... + _shader.setDiffuseColor(Color3::fromHSV(216.0_degf, 0.85f, 1.0f)) + .setLightPosition({5.0f, 5.0f, 7.0f}) + .setTransformationMatrix(transformationMatrix) + .setNormalMatrix(transformationMatrix.rotation()) + .setProjectionMatrix(camera.projectionMatrix()); + _mesh.draw(_shader); } + + Mesh _mesh; + std::unique_ptr _vertices, _indices; + Shaders::Phong _shader; } @endcode -Then you add these objects to your scene and some drawable group and transform -them as you like. You can also use @ref DrawableGroup::add() and -@ref DrawableGroup::remove(). +The @p transformationMatrix parameter in @ref draw() function contains +transformation of the object (to which the drawable is attached) relative to +@p camera. The camera contains projection matrix. Some shaders (like the +@ref Shaders::Phong used in the example) have separate functions for setting +transformation and projection matrix, but some (such as @ref Shaders::Flat) +have single function to set composite transformation and projection matrix. In +that case you need to combine the two matrices manually like in the following +code. Some shaders have additional requirements for various transformation +matrices, see their respective documentation for details. +@code +Shaders::Flat3D shader; +shader.setTransformationProjectionMatrix(camera.projectionMatrix()*transformationMatrix); +@endcode + +There is no way to just draw all the drawables in the scene, you need to create +some drawable group and add the drawable objects to both the scene and the +group. You can also use @ref DrawableGroup::add() and +@ref DrawableGroup::remove() instead of passing the group in the constructor. @code Scene3D scene; SceneGraph::DrawableGroup3D drawables; -(new DrawableObject(&scene, &drawables)) +(new RedCube(&scene, &drawables)) ->translate(Vector3::yAxis(-0.3f)) .rotateX(30.0_degf); -(new AnotherDrawableObject(&scene, &drawables)) - ->translate(Vector3::zAxis(0.5f)); + // ... @endcode The last thing you need is camera attached to some object (thus using its -transformation) and with it you can perform drawing in your draw event +transformation). Using the camera and the drawable group you can perform +drawing in your @ref Platform::Sdl2Application::drawEvent() "drawEvent()" implementation. See @ref Camera2D and @ref Camera3D documentation for more information. @code -Camera3D camera(&cameraObject); +auto cameraObject = new Object3D(&scene); +cameraObject->translate(Vector3::zAxis(5.0f)); +auto camera = new SceneGraph::Camera3D(&cameraObject); +camera->setPerspective(35.0_degf, 1.0f, 0.001f, 100.0f); + +// ... void MyApplication::drawEvent() { - camera.draw(drawables); + camera->draw(drawables); - swapBuffers(); // ... + + swapBuffers(); } @endcode -## Using drawable groups to improve performance +## Using multiple drawable groups to improve performance You can organize your drawables to multiple groups to minimize OpenGL state changes -- for example put all objects using the same shader, the same light @@ -158,9 +190,8 @@ template class Drawable: public AbstractGrouped /** * @brief Draw the object using given camera - * @param transformationMatrix Object transformation relative - * to camera - * @param camera Camera + * @param transformationMatrix Object transformation relative to camera + * @param camera Camera * * Projection matrix can be retrieved from * @ref SceneGraph::AbstractCamera::projectionMatrix() "AbstractCamera::projectionMatrix()". diff --git a/src/Magnum/SceneGraph/DualComplexTransformation.h b/src/Magnum/SceneGraph/DualComplexTransformation.h index ac5bac8fc..1605eb801 100644 --- a/src/Magnum/SceneGraph/DualComplexTransformation.h +++ b/src/Magnum/SceneGraph/DualComplexTransformation.h @@ -40,7 +40,7 @@ namespace Magnum { namespace SceneGraph { This class allows only rigid transformation (i.e. only rotation and translation). Uses @ref Math::DualComplex as underlying transformation type. -@see @ref DualComplexTransformation, @ref scenegraph, +@see @ref scenegraph, @ref DualComplexTransformation, @ref BasicDualQuaternionTransformation */ template class BasicDualComplexTransformation: public AbstractBasicTranslationRotation2D { diff --git a/src/Magnum/SceneGraph/DualQuaternionTransformation.h b/src/Magnum/SceneGraph/DualQuaternionTransformation.h index c8a11462a..e96982b84 100644 --- a/src/Magnum/SceneGraph/DualQuaternionTransformation.h +++ b/src/Magnum/SceneGraph/DualQuaternionTransformation.h @@ -40,7 +40,7 @@ namespace Magnum { namespace SceneGraph { This class allows only rigid transformation (i.e. only rotation and translation). Uses @ref Math::DualQuaternion as underlying transformation type. -@see @ref DualQuaternionTransformation @ref scenegraph, +@see @ref scenegraph, @ref DualQuaternionTransformation, @ref BasicDualComplexTransformation */ template class BasicDualQuaternionTransformation: public AbstractBasicTranslationRotation3D { diff --git a/src/Magnum/SceneGraph/MatrixTransformation2D.h b/src/Magnum/SceneGraph/MatrixTransformation2D.h index f855734aa..32f05b76b 100644 --- a/src/Magnum/SceneGraph/MatrixTransformation2D.h +++ b/src/Magnum/SceneGraph/MatrixTransformation2D.h @@ -39,7 +39,7 @@ namespace Magnum { namespace SceneGraph { @brief Two-dimensional transformation implemented using matrices Uses @ref Math::Matrix3 as underlying transformation type. -@see @ref MatrixTransformation2D, @ref scenegraph, +@see @ref scenegraph, @ref MatrixTransformation2D, @ref BasicRigidMatrixTransformation2D, @ref BasicMatrixTransformation3D */ template class BasicMatrixTransformation2D: public AbstractBasicTranslationRotationScaling2D { diff --git a/src/Magnum/SceneGraph/MatrixTransformation3D.h b/src/Magnum/SceneGraph/MatrixTransformation3D.h index f374ecf15..f5e95b549 100644 --- a/src/Magnum/SceneGraph/MatrixTransformation3D.h +++ b/src/Magnum/SceneGraph/MatrixTransformation3D.h @@ -39,7 +39,8 @@ namespace Magnum { namespace SceneGraph { @brief Three-dimensional transformation implemented using matrices Uses @ref Math::Matrix4 as underlying transformation type. -@see @ref MatrixTransformation3D, @ref scenegraph, @ref BasicRigidMatrixTransformation3D, @ref BasicMatrixTransformation2D +@see @ref scenegraph, @ref MatrixTransformation3D, + @ref BasicRigidMatrixTransformation3D, @ref BasicMatrixTransformation2D */ template class BasicMatrixTransformation3D: public AbstractBasicTranslationRotationScaling3D { public: diff --git a/src/Magnum/SceneGraph/Object.h b/src/Magnum/SceneGraph/Object.h index f9b348d10..bc986b389 100644 --- a/src/Magnum/SceneGraph/Object.h +++ b/src/Magnum/SceneGraph/Object.h @@ -335,7 +335,7 @@ template class Object: public AbstractObject class Object: public AbstractObject>>), * which cleans given set of objects more efficiently than when calling * @ref setClean() on each object individually. - * @see @ref scenegraph-caching, @ref setDirty(), @ref isDirty() + * @see @ref scenegraph-features-caching, @ref setDirty(), + * @ref isDirty() */ /* note: doc verbatim copied from AbstractObject::setClean() */ void setClean(); diff --git a/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h b/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h index 16eace59a..fe1a9230f 100644 --- a/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h +++ b/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h @@ -43,7 +43,7 @@ Unlike @ref BasicMatrixTransformation2D this class allows only rotation, reflection and translation (no scaling or setting arbitrary transformations). This allows to use @ref Math::Matrix3::invertedRigid() for faster computation of inverse transformations. -@see @ref RigidMatrixTransformation2D, @ref scenegraph, +@see @ref scenegraph, @ref RigidMatrixTransformation2D, @ref BasicRigidMatrixTransformation3D */ template class BasicRigidMatrixTransformation2D: public AbstractBasicTranslationRotation2D { diff --git a/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h b/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h index 70630188c..e7f462162 100644 --- a/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h +++ b/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h @@ -43,7 +43,8 @@ Unlike @ref BasicMatrixTransformation3D this class allows only rotation, reflection and translation (no scaling or setting arbitrary transformations). This allows to use @ref Math::Matrix4::invertedRigid() for faster computation of inverse transformations. -@see @ref RigidMatrixTransformation3D, @ref scenegraph, @ref BasicRigidMatrixTransformation2D +@see @ref scenegraph, @ref RigidMatrixTransformation3D, + @ref BasicRigidMatrixTransformation2D */ template class BasicRigidMatrixTransformation3D: public AbstractBasicTranslationRotation3D { public: diff --git a/src/Magnum/SceneGraph/TranslationTransformation.h b/src/Magnum/SceneGraph/TranslationTransformation.h index df10e078d..f0c3e4e4e 100644 --- a/src/Magnum/SceneGraph/TranslationTransformation.h +++ b/src/Magnum/SceneGraph/TranslationTransformation.h @@ -44,13 +44,9 @@ the translation is stored with the same underlying type as resulting transformation matrix, but it's possible to store translation in e.g. integral coordinates while having floating-point transformation matrix. -Note that translation is commutative, so all @ref TransformationType parameters -have no effect and are included only for compatibility with other -transformation implementations. - -@see @ref BasicTranslationTransformation2D, @ref BasicTranslationTransformation3D, - @ref TranslationTransformation2D, @ref TranslationTransformation3D, - @ref scenegraph +@see @ref scenegraph, @ref BasicTranslationTransformation2D, + @ref BasicTranslationTransformation3D, @ref TranslationTransformation2D, + @ref TranslationTransformation3D */ #ifdef DOXYGEN_GENERATING_OUTPUT template