From 13c4a690a3d2bb8679b946b36ae68adf7f6a67b6 Mon Sep 17 00:00:00 2001 From: Squareys Date: Sun, 3 May 2020 10:22:42 +0200 Subject: [PATCH 1/9] Trade: Minor doc fix Signed-off-by: Squareys --- src/Magnum/Trade/MeshData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index 858f922252..6e155a2165 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -106,7 +106,7 @@ enum class MeshAttribute: UnsignedShort { /** * Normal. Type is usually @ref VertexFormat::Vector3, but can be also - * @ref VertexFormat::Vector3h. @ref VertexFormat::Vector3bNormalized or + * @ref VertexFormat::Vector3h, @ref VertexFormat::Vector3bNormalized or * @ref VertexFormat::Vector3sNormalized. Corresponds to * @ref Shaders::Generic::Normal. * @see @ref MeshData::normalsAsArray() From fc940721e68f7b8a39f63afd008954b253b3f133 Mon Sep 17 00:00:00 2001 From: Squareys Date: Sun, 3 May 2020 10:23:05 +0200 Subject: [PATCH 2/9] Shaders: Add Weights and JointIndices attribute types Signed-off-by: Squareys --- src/Magnum/Shaders/Generic.h | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Magnum/Shaders/Generic.h b/src/Magnum/Shaders/Generic.h index 43858c0cdf..4544dcfdae 100644 --- a/src/Magnum/Shaders/Generic.h +++ b/src/Magnum/Shaders/Generic.h @@ -126,13 +126,13 @@ both bitangents and object ID for instancing, \n 6 -* *Reserved* --- vertex weights +@ref Weights 7 -* *Reserved* --- bone indices +@ref JointIndices @@ -150,13 +150,13 @@ both bitangents and object ID for instancing, \n 10 -* *Reserved* --- 2nd vertex weights +@ref Weights 11 -* *Reserved* --- 2nd bone indices +@ref JointIndices @@ -358,7 +358,26 @@ template struct Generic { */ typedef GL::Attribute<5, Vector3> Normal; - /* 6, 7 reserved for vertex weights / bone IDs */ + /** + * @brief Skin weights + * + * @ref Magnum::Vector4 "Vector4", four weights of influence per @ref JointIndices. + * Corresponds to @ref Trade::MeshAttribute::Weights. + */ + // TODO: E.g. gltf supports importing multiple sets of 4 weights (WEIGHTS_0 [0;3], WEIGHTS_1 [4;7]) + // I suppose these would require special shaders and it's fine to only support 4 for the GenericShaders + typedef GL::Attribute<6, Vector4> Weights; + + /** + * @brief Joint indices + * + * @ref Magnum::Vector4 "Vector4", four weights of influence per @ref JointIndices. + * Corresponds to @ref Trade::MeshAttribute::Weights. + */ + // TODO: E.g. gltf supports importing multiple sets of 4 indices (JOINTS_0 [0;3], JOINTS_1 [4;7]) + // I suppose these would require special shaders and it's fine to only support 4 for the GenericShaders + // TODO: This is called "Joints" in gltf. + typedef GL::Attribute<7, Vector4> JointIndices; /** * @brief (Instanced) transformation matrix From 17931de06e0b6a768dd58a7dcdc5c6da85cf231f Mon Sep 17 00:00:00 2001 From: Squareys Date: Sun, 3 May 2020 10:24:18 +0200 Subject: [PATCH 3/9] [WIP] Trade: Implement support for Weights & JointIndices in MeshData. Signed-off-by: Squareys --- src/Magnum/Trade/MeshData.cpp | 12 ++++++ src/Magnum/Trade/MeshData.h | 75 +++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp index a4a949bc2f..658438945e 100644 --- a/src/Magnum/Trade/MeshData.cpp +++ b/src/Magnum/Trade/MeshData.cpp @@ -777,6 +777,18 @@ Containers::Array MeshData::objectIdsAsArray(const UnsignedInt id) return out; } +Containers::Array MeshData::weightsAsArray(const UnsignedInt id) const { + Containers::Array out{_vertexCount}; + weightsInto(out, id); + return out; +} + +Containers::Array MeshData::jointIndicesAsArray(const UnsignedInt id) const { + Containers::Array out{_vertexCount}; + jointIndicesInto(out, id); + return out; +} + Containers::Array MeshData::releaseIndexData() { _indexCount = 0; Containers::Array out = std::move(_indexData); diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index 6e155a2165..6321339525 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -147,6 +147,24 @@ enum class MeshAttribute: UnsignedShort { */ ObjectId, + /** + * Weights. Type is usually @ref VertexFormat::Vector4, but can be also + * @ref VertexFormat::Vector4h, @ref VertexFormat::Vector4bNormalized or + * @ref VertexFormat::Vector4sNormalized. Corresponds to + * @ref Shaders::Generic::Weights. + * @see @ref MeshData::weightsAsArray() + */ + Weights, + + /** + * JointIndices. Type is usually @ref VertexFormat::Vector4ui, but can be also + * @ref VertexFormat::Vector4i, @ref VertexFormat::Vector4s, @ref VertexFormat::Vector4us, + * @ref VertexFormat::Vector4ub or @ref VertexFormat::Vector4b. Corresponds to + * @ref Shaders::Generic::JointIndices. + * @see @ref MeshData::jointIndicesAsArray() + */ + JointIndices, + /** * This and all higher values are for importer-specific attributes. Can be * of any type. See documentation of a particular importer for details. @@ -613,10 +631,11 @@ the @ref Primitives library. The simplest usage is through the convenience functions @ref positions2DAsArray(), @ref positions3DAsArray(), @ref tangentsAsArray(), @ref bitangentsAsArray(), @ref normalsAsArray(), @ref tangentsAsArray(), @ref textureCoordinates2DAsArray(), -@ref colorsAsArray() and @ref objectIdsAsArray(). Each of these takes an index -(as there can be multiple sets of texture coordinates, for example) and you're -expected to check for attribute presence first with either @ref hasAttribute() -or @ref attributeCount(MeshAttribute) const: +@ref colorsAsArray(), @ref objectIdsAsArray(), @ref weightsAsArray() and +@ref jointIndicesAsArray(). Each of these takes an index (as there can be multiple +sets of texture coordinates, for example) and you're expected to check for +attribute presence first with either @ref hasAttribute() or +@ref attributeCount(MeshAttribute) const: @snippet MagnumTrade.cpp MeshData-usage @@ -1717,6 +1736,54 @@ class MAGNUM_TRADE_EXPORT MeshData { */ void objectIdsInto(Containers::StridedArrayView1D destination, UnsignedInt id = 0) const; + /** + * @brief Weights as 4D float vectors + * + * Convenience alternative to @ref attribute(MeshAttribute, UnsignedInt) const + * with @ref MeshAttribute::Weights as the first argument. Converts + * the weights array from an arbitrary underlying type and returns it + * in a newly-allocated array. Expects that the vertex format is *not* + * implementation-specific, in that case you can only access the + * attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const. + * @see @ref weightsInto(), @ref attributeFormat(), + * @ref isVertexFormatImplementationSpecific() + */ + Containers::Array weightsAsArray(UnsignedInt id = 0) const; + + /** + * @brief Weights as 4D float vectors into a pre-allocated view + * + * Like @ref weightsAsArray(), but puts the result into + * @p destination instead of allocating a new array. Expects that + * @p destination is sized to contain exactly all data. + * @see @ref vertexCount() + */ + void weightsInto(Containers::StridedArrayView1D destination, UnsignedInt id = 0) const; + + /** + * @brief Weights as 4D unsigned short vectors + * + * Convenience alternative to @ref attribute(MeshAttribute, UnsignedInt) const + * with @ref MeshAttribute::JointIndices as the first argument. Converts + * the joint indices array from an arbitrary underlying type and returns it + * in a newly-allocated array. Expects that the vertex format is *not* + * implementation-specific, in that case you can only access the + * attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const. + * @see @ref jointIndicesInto(), @ref attributeFormat(), + * @ref isVertexFormatImplementationSpecific() + */ + Containers::Array jointIndicesAsArray(UnsignedInt id = 0) const; + + /** + * @brief Weights as 4D unsigned short vectors into a pre-allocated view + * + * Like @ref jointIndicesAsArray(), but puts the result into + * @p destination instead of allocating a new array. Expects that + * @p destination is sized to contain exactly all data. + * @see @ref vertexCount() + */ + void jointIndicesInto(Containers::StridedArrayView1D destination, UnsignedInt id = 0) const; + /** * @brief Release index data storage * From 90462159236c89f08f8b48fd9e913e0aafaaa961 Mon Sep 17 00:00:00 2001 From: Squareys Date: Thu, 7 May 2020 15:42:21 +0200 Subject: [PATCH 4/9] fixup! MeshAttribute Signed-off-by: Squareys --- src/Magnum/Trade/MeshData.cpp | 60 +++++++++++++++++++++++++++++++++-- src/Magnum/Trade/MeshData.h | 36 +++++++++++---------- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp index 658438945e..94ac37036d 100644 --- a/src/Magnum/Trade/MeshData.cpp +++ b/src/Magnum/Trade/MeshData.cpp @@ -777,15 +777,67 @@ Containers::Array MeshData::objectIdsAsArray(const UnsignedInt id) return out; } +void MeshData::weightsInto(const Containers::StridedArrayView1D destination, const UnsignedInt id) const { + const UnsignedInt attributeId = attributeFor(MeshAttribute::Weights, id); + CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::weightsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Weights) << "weights attributes", ); + CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::weightsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); + const MeshAttributeData& attribute = _attributes[attributeId]; + CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), + "Trade::MeshData::weightsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast(vertexFormatUnwrap(attribute._format)), ); + const Containers::StridedArrayView1D attributeData = attributeDataViewInternal(attribute); + const Containers::StridedArrayView2D destination4f = Containers::arrayCast<2, Float>(destination); + + if(attribute._format == VertexFormat::Vector4) + Utility::copy(Containers::arrayCast(attributeData), destination); + else if(attribute._format == VertexFormat::Vector4h) + Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4ub) + Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4b) + Math::castInto(Containers::arrayCast<2, const Byte>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4us) + Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4s) + Math::castInto(Containers::arrayCast<2, const Short>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4ubNormalized) + Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4bNormalized) + Math::unpackInto(Containers::arrayCast<2, const Byte>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4usNormalized) + Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); + else if(attribute._format == VertexFormat::Vector4sNormalized) + Math::unpackInto(Containers::arrayCast<2, const Short>(attributeData, 4), destination4f); + else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ +} + + Containers::Array MeshData::weightsAsArray(const UnsignedInt id) const { Containers::Array out{_vertexCount}; weightsInto(out, id); return out; } -Containers::Array MeshData::jointIndicesAsArray(const UnsignedInt id) const { - Containers::Array out{_vertexCount}; - jointIndicesInto(out, id); +void MeshData::jointIdsInto(const Containers::StridedArrayView1D destination, const UnsignedInt id) const { + const UnsignedInt attributeId = attributeFor(MeshAttribute::JointIds, id); + CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::jointIdsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "joint IDs attributes", ); + CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::jointIdsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); + const MeshAttributeData& attribute = _attributes[attributeId]; + CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), + "Trade::MeshData::jointIdsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast(vertexFormatUnwrap(attribute._format)), ); + const Containers::StridedArrayView1D attributeData = attributeDataViewInternal(attribute); + + if(attribute._format == VertexFormat::Vector4ui) + Utility::copy(Containers::arrayCast(attributeData), destination); + else if(attribute._format == VertexFormat::Vector4ub) + Utility::copy(Containers::arrayCast(attributeData), destination); + else if(attribute._format == VertexFormat::Vector4us) + Utility::copy(Containers::arrayCast(attributeData), destination); + else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ +} + +Containers::Array MeshData::jointIdsAsArray(const UnsignedInt id) const { + Containers::Array out{_vertexCount}; + jointIdsInto(out, id); return out; } @@ -823,6 +875,8 @@ Debug& operator<<(Debug& debug, const MeshAttribute value) { _c(TextureCoordinates) _c(Color) _c(ObjectId) + _c(Weights) + _c(JointIds) #undef _c /* LCOV_EXCL_STOP */ diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index 6321339525..221713b220 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -149,21 +149,23 @@ enum class MeshAttribute: UnsignedShort { /** * Weights. Type is usually @ref VertexFormat::Vector4, but can be also - * @ref VertexFormat::Vector4h, @ref VertexFormat::Vector4bNormalized or - * @ref VertexFormat::Vector4sNormalized. Corresponds to - * @ref Shaders::Generic::Weights. + * @ref VertexFormat::Vector4h, @ref VertexFormat::Vector4ub, + * @ref VertexFormat::Vector4b, @ref VertexFormat::Vector4us, + * @ref VertexFormat::Vector4s, @ref VertexFormat::Vector4ubNormalized, + * @ref VertexFormat::Vector4bNormalized, @ref VertexFormat::Vector4usNormalized + * or @ref VertexFormat::Vector4sNormalized. + * Corresponds to * @ref Shaders::Generic::Weights. * @see @ref MeshData::weightsAsArray() */ Weights, /** - * JointIndices. Type is usually @ref VertexFormat::Vector4ui, but can be also - * @ref VertexFormat::Vector4i, @ref VertexFormat::Vector4s, @ref VertexFormat::Vector4us, - * @ref VertexFormat::Vector4ub or @ref VertexFormat::Vector4b. Corresponds to - * @ref Shaders::Generic::JointIndices. - * @see @ref MeshData::jointIndicesAsArray() + * Joint IDs. Type is usually @ref VertexFormat::Vector4ui, but can be also + * @ref VertexFormat::Vector4us or @ref VertexFormat::Vector4ub. + * @ref Shaders::Generic::JointIds. + * @see @ref MeshData::jointIdsAsArray() */ - JointIndices, + JointIds, /** * This and all higher values are for importer-specific attributes. Can be @@ -632,7 +634,7 @@ The simplest usage is through the convenience functions @ref positions2DAsArray( @ref positions3DAsArray(), @ref tangentsAsArray(), @ref bitangentsAsArray(), @ref normalsAsArray(), @ref tangentsAsArray(), @ref textureCoordinates2DAsArray(), @ref colorsAsArray(), @ref objectIdsAsArray(), @ref weightsAsArray() and -@ref jointIndicesAsArray(). Each of these takes an index (as there can be multiple +@ref jointIdsAsArray(). Each of these takes an index (as there can be multiple sets of texture coordinates, for example) and you're expected to check for attribute presence first with either @ref hasAttribute() or @ref attributeCount(MeshAttribute) const: @@ -1761,28 +1763,28 @@ class MAGNUM_TRADE_EXPORT MeshData { void weightsInto(Containers::StridedArrayView1D destination, UnsignedInt id = 0) const; /** - * @brief Weights as 4D unsigned short vectors + * @brief Joint IDs as 4D unsigned int vectors * * Convenience alternative to @ref attribute(MeshAttribute, UnsignedInt) const - * with @ref MeshAttribute::JointIndices as the first argument. Converts + * with @ref MeshAttribute::JointIds as the first argument. Converts * the joint indices array from an arbitrary underlying type and returns it * in a newly-allocated array. Expects that the vertex format is *not* * implementation-specific, in that case you can only access the * attribute via the typeless @ref attribute(MeshAttribute, UnsignedInt) const. - * @see @ref jointIndicesInto(), @ref attributeFormat(), + * @see @ref jointIdsInto(), @ref attributeFormat(), * @ref isVertexFormatImplementationSpecific() */ - Containers::Array jointIndicesAsArray(UnsignedInt id = 0) const; + Containers::Array jointIdsAsArray(UnsignedInt id = 0) const; /** - * @brief Weights as 4D unsigned short vectors into a pre-allocated view + * @brief Joint IDs as 4D unsigned int vectors into a pre-allocated view * - * Like @ref jointIndicesAsArray(), but puts the result into + * Like @ref jointIdsAsArray(), but puts the result into * @p destination instead of allocating a new array. Expects that * @p destination is sized to contain exactly all data. * @see @ref vertexCount() */ - void jointIndicesInto(Containers::StridedArrayView1D destination, UnsignedInt id = 0) const; + void jointIdsInto(Containers::StridedArrayView1D destination, UnsignedInt id = 0) const; /** * @brief Release index data storage From 04ef2f5b35a75370ac652568fdeb784f2c0af007 Mon Sep 17 00:00:00 2001 From: Squareys Date: Thu, 7 May 2020 15:42:28 +0200 Subject: [PATCH 5/9] fixup! Generic Signed-off-by: Squareys --- src/Magnum/Shaders/Generic.h | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Magnum/Shaders/Generic.h b/src/Magnum/Shaders/Generic.h index 4544dcfdae..c1840777c6 100644 --- a/src/Magnum/Shaders/Generic.h +++ b/src/Magnum/Shaders/Generic.h @@ -364,20 +364,15 @@ template struct Generic { * @ref Magnum::Vector4 "Vector4", four weights of influence per @ref JointIndices. * Corresponds to @ref Trade::MeshAttribute::Weights. */ - // TODO: E.g. gltf supports importing multiple sets of 4 weights (WEIGHTS_0 [0;3], WEIGHTS_1 [4;7]) - // I suppose these would require special shaders and it's fine to only support 4 for the GenericShaders typedef GL::Attribute<6, Vector4> Weights; /** - * @brief Joint indices + * @brief Joint IDs * - * @ref Magnum::Vector4 "Vector4", four weights of influence per @ref JointIndices. - * Corresponds to @ref Trade::MeshAttribute::Weights. + * @ref Magnum::Vector4ui "Vector4ui", four joint indices that may affect the vertex. + * Corresponds to @ref Trade::MeshAttribute::JointIds. */ - // TODO: E.g. gltf supports importing multiple sets of 4 indices (JOINTS_0 [0;3], JOINTS_1 [4;7]) - // I suppose these would require special shaders and it's fine to only support 4 for the GenericShaders - // TODO: This is called "Joints" in gltf. - typedef GL::Attribute<7, Vector4> JointIndices; + typedef GL::Attribute<7, Vector4ui> JointIds; /** * @brief (Instanced) transformation matrix @@ -502,7 +497,8 @@ template<> struct Generic<3>: BaseGeneric { typedef GL::Attribute<3, Vector4> Tangent4; typedef GL::Attribute<4, Vector3> Bitangent; /* also ObjectId */ typedef GL::Attribute<5, Vector3> Normal; - /* 6, 7 reserved for vertex weights / bone IDs */ + typedef GL::Attribute<6, Vector4> Weights; + typedef GL::Attribute<7, Vector4> JointIds; typedef GL::Attribute<8, Matrix4> TransformationMatrix; /* 9, 10, 11 occupied by TransformationMatrix */ From 0ffa866bda22453f7691085a3323384f93bac0d9 Mon Sep 17 00:00:00 2001 From: Squareys Date: Thu, 7 May 2020 18:07:51 +0200 Subject: [PATCH 6/9] WIP Signed-off-by: Squareys --- src/Magnum/Shaders/Generic.h | 13 +-- src/Magnum/Trade/MeshData.cpp | 18 +---- src/Magnum/Trade/MeshData.h | 20 +++-- src/Magnum/Trade/Test/MeshDataTest.cpp | 106 +++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 27 deletions(-) diff --git a/src/Magnum/Shaders/Generic.h b/src/Magnum/Shaders/Generic.h index c1840777c6..fb8db297cc 100644 --- a/src/Magnum/Shaders/Generic.h +++ b/src/Magnum/Shaders/Generic.h @@ -132,7 +132,7 @@ both bitangents and object ID for instancing, \n 7 -@ref JointIndices +@ref JointIds @@ -150,13 +150,13 @@ both bitangents and object ID for instancing, \n 10 -@ref Weights +@ref SecondaryWeights 11 -@ref JointIndices +@ref SecondaryJointIds @@ -469,6 +469,11 @@ struct BaseGeneric { #ifndef MAGNUM_TARGET_GLES2 typedef GL::Attribute<4, UnsignedInt> ObjectId; #endif + typedef GL::Attribute<6, Vector4> Weights; + typedef GL::Attribute<7, Vector4> JointIds; + + typedef GL::Attribute<10, Vector4> SecondaryWeights; + typedef GL::Attribute<11, Vector4> SecondaryJointIds; typedef GL::Attribute<15, Vector2> TextureOffset; @@ -497,8 +502,6 @@ template<> struct Generic<3>: BaseGeneric { typedef GL::Attribute<3, Vector4> Tangent4; typedef GL::Attribute<4, Vector3> Bitangent; /* also ObjectId */ typedef GL::Attribute<5, Vector3> Normal; - typedef GL::Attribute<6, Vector4> Weights; - typedef GL::Attribute<7, Vector4> JointIds; typedef GL::Attribute<8, Matrix4> TransformationMatrix; /* 9, 10, 11 occupied by TransformationMatrix */ diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp index 94ac37036d..354949d4e9 100644 --- a/src/Magnum/Trade/MeshData.cpp +++ b/src/Magnum/Trade/MeshData.cpp @@ -791,26 +791,13 @@ void MeshData::weightsInto(const Containers::StridedArrayView1D destina Utility::copy(Containers::arrayCast(attributeData), destination); else if(attribute._format == VertexFormat::Vector4h) Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4ub) - Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4b) - Math::castInto(Containers::arrayCast<2, const Byte>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4us) - Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4s) - Math::castInto(Containers::arrayCast<2, const Short>(attributeData, 4), destination4f); else if(attribute._format == VertexFormat::Vector4ubNormalized) Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4bNormalized) - Math::unpackInto(Containers::arrayCast<2, const Byte>(attributeData, 4), destination4f); else if(attribute._format == VertexFormat::Vector4usNormalized) Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4sNormalized) - Math::unpackInto(Containers::arrayCast<2, const Short>(attributeData, 4), destination4f); else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } - Containers::Array MeshData::weightsAsArray(const UnsignedInt id) const { Containers::Array out{_vertexCount}; weightsInto(out, id); @@ -825,13 +812,14 @@ void MeshData::jointIdsInto(const Containers::StridedArrayView1D dest CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), "Trade::MeshData::jointIdsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast(vertexFormatUnwrap(attribute._format)), ); const Containers::StridedArrayView1D attributeData = attributeDataViewInternal(attribute); + const Containers::StridedArrayView2D destination4ui = Containers::arrayCast<2, UnsignedInt>(destination); if(attribute._format == VertexFormat::Vector4ui) Utility::copy(Containers::arrayCast(attributeData), destination); else if(attribute._format == VertexFormat::Vector4ub) - Utility::copy(Containers::arrayCast(attributeData), destination); + Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4ui); else if(attribute._format == VertexFormat::Vector4us) - Utility::copy(Containers::arrayCast(attributeData), destination); + Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4ui); else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index 221713b220..4cc12291a2 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -149,12 +149,9 @@ enum class MeshAttribute: UnsignedShort { /** * Weights. Type is usually @ref VertexFormat::Vector4, but can be also - * @ref VertexFormat::Vector4h, @ref VertexFormat::Vector4ub, - * @ref VertexFormat::Vector4b, @ref VertexFormat::Vector4us, - * @ref VertexFormat::Vector4s, @ref VertexFormat::Vector4ubNormalized, - * @ref VertexFormat::Vector4bNormalized, @ref VertexFormat::Vector4usNormalized - * or @ref VertexFormat::Vector4sNormalized. - * Corresponds to * @ref Shaders::Generic::Weights. + * @ref VertexFormat::Vector4h, @ref VertexFormat::Vector4ubNormalized + * or @ref VertexFormat::Vector4usNormalized. + * Corresponds to @ref Shaders::Generic::Weights. * @see @ref MeshData::weightsAsArray() */ Weights, @@ -162,7 +159,7 @@ enum class MeshAttribute: UnsignedShort { /** * Joint IDs. Type is usually @ref VertexFormat::Vector4ui, but can be also * @ref VertexFormat::Vector4us or @ref VertexFormat::Vector4ub. - * @ref Shaders::Generic::JointIds. + * Corresponds to @ref Shaders::Generic::JointIds. * @see @ref MeshData::jointIdsAsArray() */ JointIds, @@ -2132,6 +2129,15 @@ namespace Implementation { (format == VertexFormat::UnsignedInt || format == VertexFormat::UnsignedShort || format == VertexFormat::UnsignedByte)) || + (name == MeshAttribute::Weights && + (format == VertexFormat::Vector4 || + format == VertexFormat::Vector4h || + format == VertexFormat::Vector4ubNormalized || + format == VertexFormat::Vector4usNormalized)) || + (name == MeshAttribute::JointIds && + (format == VertexFormat::Vector4ui || + format == VertexFormat::Vector4ub || + format == VertexFormat::Vector4us)) || /* Custom attributes can be anything */ isMeshAttributeCustom(name); } diff --git a/src/Magnum/Trade/Test/MeshDataTest.cpp b/src/Magnum/Trade/Test/MeshDataTest.cpp index 301d305f4f..20ef216fb1 100644 --- a/src/Magnum/Trade/Test/MeshDataTest.cpp +++ b/src/Magnum/Trade/Test/MeshDataTest.cpp @@ -146,6 +146,14 @@ struct MeshDataTest: TestSuite::Tester { template void objectIdsAsArray(); void objectIdsIntoArrayInvalidSize(); + template void weightsAsArray(); + template void weightsAsArrayPackedUnsignedNormalized(); + template void weightsAsArrayPackedSignedNormalized(); + void weightsIntoArrayInvalidSize(); + + template void jointIdsAsArray(); + void jointIdsIntoArrayInvalidSize(); + void implementationSpecificVertexFormat(); void implementationSpecificVertexFormatWrongAccess(); void implementationSpecificVertexFormatNotContained(); @@ -364,6 +372,17 @@ MeshDataTest::MeshDataTest() { &MeshDataTest::objectIdsAsArray, &MeshDataTest::objectIdsIntoArrayInvalidSize, + &MeshDataTest::weightsAsArray, + &MeshDataTest::weightsAsArray, + &MeshDataTest::weightsAsArrayPackedUnsignedNormalized, + &MeshDataTest::weightsAsArrayPackedUnsignedNormalized, + &MeshDataTest::weightsIntoArrayInvalidSize, + + &MeshDataTest::jointIdsAsArray, + &MeshDataTest::jointIdsAsArray, + &MeshDataTest::jointIdsAsArray, + &MeshDataTest::jointIdsIntoArrayInvalidSize, + &MeshDataTest::implementationSpecificVertexFormat, &MeshDataTest::implementationSpecificVertexFormatWrongAccess, &MeshDataTest::implementationSpecificVertexFormatNotContained, @@ -1856,8 +1875,11 @@ _c(Vector3b) _c(Vector3us) _c(Vector3s) _c(Vector4) +_c(Vector4ui) _c(Vector4h) +_c(Vector4ub) _c(Vector4b) +_c(Vector4us) _c(Vector4s) _c(Color3) _c(Color3h) @@ -2500,6 +2522,90 @@ void MeshDataTest::objectIdsIntoArrayInvalidSize() { "Trade::MeshData::objectIdsInto(): expected a view with 3 elements but got 2\n"); } +template void MeshDataTest::weightsAsArray() { + setTestCaseTemplateName(NameTraits::name()); + typedef typename T::Type U; + + Containers::Array vertexData{3*sizeof(T)}; + auto weightsView = Containers::arrayCast(vertexData); + /* Needs to be sufficiently representable to have the test work also for + half floats */ + weightsView[0] = T::pad(Math::Vector4{U(2.0f), U(1.0f), U(0.75f), U(3.0f)}); + weightsView[1] = T::pad(Math::Vector4{U(0.0f), U(-1.0f), U(1.25f), U(1.0f)}); + weightsView[2] = T::pad(Math::Vector4{U(-2.0f), U(3.0f), U(2.5f), U(2.5f)}); + + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Weights, weightsView}}}; + CORRADE_COMPARE_AS(data.weightsAsArray(), Containers::arrayView({ + {2.0f, 1.0f, 0.75f, 3.0f}, {0.0f, -1.0f, 1.25f, 1.0f}, {-2.0f, 3.0f, 2.5f, 2.5f}, + }), TestSuite::Compare::Container); +} + +template void MeshDataTest::weightsAsArrayPackedUnsignedNormalized() { + setTestCaseTemplateName(NameTraits::name()); + + Containers::Array vertexData{2*sizeof(T)}; + auto weightsView = Containers::arrayCast(vertexData); + weightsView[0] = T::pad(Math::Vector4{Math::pack(1.0f), 0, Math::pack(1.0f), Math::pack(0.8)}); + weightsView[1] = T::pad(Math::Vector4{0, Math::pack(1.0f), 0, Math::pack(0.4f)}); + + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Weights, + /* Assuming the normalized enum is always after the non-normalized */ + VertexFormat(UnsignedInt(Implementation::vertexFormatFor()) + 1), + weightsView}}}; + CORRADE_COMPARE_AS(data.weightsAsArray(), Containers::arrayView({ + Vector4::pad(Math::Vector::pad(Vector4{1.0f, 0.0f, 1.0f, 0.8})), + Vector4::pad(Math::Vector::pad(Vector4{0.0f, 1.0f, 0.0f, 0.4f})) + }), TestSuite::Compare::Container); +} + +void MeshDataTest::weightsIntoArrayInvalidSize() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Containers::Array vertexData{3*sizeof(Vector4)}; + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Weights, Containers::arrayCast(vertexData)}}}; + + std::ostringstream out; + Error redirectError{&out}; + Vector4 destination[2]; + data.weightsInto(destination); + CORRADE_COMPARE(out.str(), + "Trade::MeshData::weightsInto(): expected a view with 3 elements but got 2\n"); +} + +template void MeshDataTest::jointIdsAsArray() { + setTestCaseTemplateName(NameTraits::name()); + typedef typename T::Type U; + + Containers::Array vertexData{3*sizeof(T)}; + auto joinIdsView = Containers::arrayCast(vertexData); + joinIdsView[0] = {U(0), U(1), U(2), U(3)}; + joinIdsView[1] = {U(4), U(5), U(6), U(7)}; + joinIdsView[2] = {U(8), U(9), U(10), U(11)}; + + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::JointIds, joinIdsView}}}; + CORRADE_COMPARE_AS(data.jointIdsAsArray(), Containers::arrayView({ + {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}, + }), TestSuite::Compare::Container); +} + +void MeshDataTest::jointIdsIntoArrayInvalidSize() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Containers::Array vertexData{3*sizeof(Vector4ui)}; + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::JointIds, Containers::arrayCast(vertexData)}}}; + + std::ostringstream out; + Error redirectError{&out}; + Vector4ui destination[2]; + data.jointIdsInto(destination); + CORRADE_COMPARE(out.str(), + "Trade::MeshData::jointIdsInto(): expected a view with 3 elements but got 2\n"); +} + /* MSVC 2015 doesn't like anonymous bitfields in inline structs, so putting the declaration outside */ struct VertexWithImplementationSpecificData { From 68834eb9a8d063e1e2a2758bc1f8b69969da2e50 Mon Sep 17 00:00:00 2001 From: Squareys Date: Mon, 11 May 2020 14:05:28 +0200 Subject: [PATCH 7/9] Phong Signed-off-by: Squareys --- src/Magnum/Shaders/Generic.h | 4 +- src/Magnum/Shaders/Phong.cpp | 44 ++++++++++++++++- src/Magnum/Shaders/Phong.h | 85 +++++++++++++++++++++++++++++++-- src/Magnum/Shaders/Phong.vert | 45 +++++++++++++++++ src/Magnum/Shaders/generic.glsl | 5 ++ 5 files changed, 175 insertions(+), 8 deletions(-) diff --git a/src/Magnum/Shaders/Generic.h b/src/Magnum/Shaders/Generic.h index fb8db297cc..30d18e7387 100644 --- a/src/Magnum/Shaders/Generic.h +++ b/src/Magnum/Shaders/Generic.h @@ -470,10 +470,10 @@ struct BaseGeneric { typedef GL::Attribute<4, UnsignedInt> ObjectId; #endif typedef GL::Attribute<6, Vector4> Weights; - typedef GL::Attribute<7, Vector4> JointIds; + typedef GL::Attribute<7, Vector4ui> JointIds; typedef GL::Attribute<10, Vector4> SecondaryWeights; - typedef GL::Attribute<11, Vector4> SecondaryJointIds; + typedef GL::Attribute<11, Vector4ui> SecondaryJointIds; typedef GL::Attribute<15, Vector2> TextureOffset; diff --git a/src/Magnum/Shaders/Phong.cpp b/src/Magnum/Shaders/Phong.cpp index 72238fb2c9..f11cb2a9ed 100644 --- a/src/Magnum/Shaders/Phong.cpp +++ b/src/Magnum/Shaders/Phong.cpp @@ -54,9 +54,13 @@ namespace { }; } -Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _lightCount{lightCount}, _lightColorsUniform{_lightPositionsUniform + Int(lightCount)} { +Phong::Phong(const Flags flags, const UnsignedInt lightCount, const UnsignedInt jointCount, const UnsignedInt jointsPerVertex): _flags{flags}, _lightCount{lightCount}, _jointCount{jointCount}, _jointsPerVertex{jointsPerVertex}, _lightColorsUniform{_lightPositionsUniform + Int(lightCount)}, _jointMatricesUniform{_lightPositionsUniform + 2*Int(lightCount)} { CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture)), "Shaders::Phong: texture transformation enabled but the shader is not textured", ); + CORRADE_ASSERT(!(flags & Flag::Skinning) || (jointCount != 0), + "Shaders::Phong: skinning enabled, but jointCount is zero", ); + CORRADE_ASSERT(!(flags & Flag::Skinning) || (jointsPerVertex > 0 && jointsPerVertex <= 8), + "Shaders::Phong: skinning enabled, but jointsPerVertex is not in [1;8]", ); #ifdef MAGNUM_BUILD_STATIC /* Import resources on static build, if not already */ @@ -120,7 +124,12 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l #endif .addSource(Utility::formatString( "#define LIGHT_COUNT {}\n" - "#define LIGHT_COLORS_LOCATION {}\n", lightCount, _lightPositionsUniform + lightCount)); + "#define LIGHT_COLORS_LOCATION {}\n", lightCount, _lightColorsUniform)) + .addSource(flags & Flag::Skinning ? "#define SKINNING\n" : "") + .addSource(Utility::formatString( + "#define JOINT_COUNT {}\n" + "#define JOINTS_PER_VERTEX {}\n" + "#define JOINT_MATRICES_LOCATION {}\n", jointCount, jointsPerVertex, _jointMatricesUniform)); #ifndef MAGNUM_TARGET_GLES if(lightCount) frag.addSource(std::move(lightInitializer)); #endif @@ -159,6 +168,15 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l if(flags >= Flag::InstancedTextureOffset) bindAttributeLocation(TextureOffset::Location, "instancedTextureOffset"); #endif + if(flags & Flag::Skinning) { + bindAttributeLocation(Weights::Location, "weights"); + bindAttributeLocation(JointIds::Location, "jointIds"); + + if(jointCount > 4) { + bindAttributeLocation(SecondaryWeights::Location, "secondaryWeights"); + bindAttributeLocation(SecondaryJointIds::Location, "secondaryJointIds"); + } + } } #endif @@ -185,6 +203,8 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l #ifndef MAGNUM_TARGET_GLES2 if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId"); #endif + if(flags & Flag::Skinning) + _jointMatricesUniform = uniformLocation("jointMatrices"); } #ifndef MAGNUM_TARGET_GLES @@ -353,6 +373,26 @@ Phong& Phong::setLightColor(UnsignedInt id, const Magnum::Color4& color) { return *this; } +Phong& Phong::setJointMatrices(const Containers::ArrayView matrices) { + CORRADE_ASSERT(_jointCount == matrices.size(), + "Shaders::Phong::setJointMatrices(): expected" << _jointCount << "items but got" << matrices.size(), *this); + if(_jointCount) setUniform(_jointMatricesUniform, matrices); + return *this; +} + +Phong& Phong::setJointMatrix(UnsignedInt id, const Matrix4& matrix) { + CORRADE_ASSERT(id < _jointCount, + "Shaders::Phong::setJointMatrix(): joint ID" << id << "is out of bounds for" << _jointCount << "joints", *this); + setUniform(_jointMatricesUniform + id, matrix); + return *this; +} + +/* It's light, but can't be in the header because MSVC needs to know the size + of Matrix4 for the initializer list use */ +Phong& Phong::setJointMatrices(std::initializer_list matrices) { + return setJointMatrices({matrices.begin(), matrices.size()}); +} + Debug& operator<<(Debug& debug, const Phong::Flag value) { debug << "Shaders::Phong::Flag" << Debug::nospace; diff --git a/src/Magnum/Shaders/Phong.h b/src/Magnum/Shaders/Phong.h index fc75fddb0b..ecac4da0ec 100644 --- a/src/Magnum/Shaders/Phong.h +++ b/src/Magnum/Shaders/Phong.h @@ -207,6 +207,42 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { */ typedef Generic3D::Color4 Color4; + /** + * @brief Joint ids + * @m_since_latest + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Vector4ui. + * Used only if @ref Flag::Skinning is set. + */ + typedef Generic3D::JointIds JointIds; + + /** + * @brief Weights + * @m_since_latest + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Vector4. + * Used only if @ref Flag::Skinning is set. + */ + typedef Generic3D::Weights Weights; + + /** + * @brief Secondary joint ids + * @m_since_latest + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Vector4ui. + * Used only if @ref Flag::Skinning is set and @cpp jointCount > 4 @ce. + */ + typedef Generic3D::SecondaryJointIds SecondaryJointIds; + + /** + * @brief Secondary weights + * @m_since_latest + * + * @ref shaders-generic "Generic attribute", @ref Magnum::Vector4. + * Used only if @ref Flag::Skinning is set and @cpp jointCount > 4 @ce. + */ + typedef Generic3D::Weights SecondaryWeights; + #ifndef MAGNUM_TARGET_GLES2 /** * @brief (Instanced) object ID @@ -416,7 +452,14 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { * in WebGL 1.0. * @m_since_latest */ - InstancedTextureOffset = (1 << 10)|TextureTransformation + InstancedTextureOffset = (1 << 10)|TextureTransformation, + + /** + * Skinning. + * @TODO docs + * @m_since_latest + */ + Skinning = 1 << 11 }; /** @@ -428,10 +471,13 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { /** * @brief Constructor - * @param flags Flags - * @param lightCount Count of light sources + * @param flags Flags + * @param lightCount Count of light sources + * @param jointCount Count of joints for skinning (see @ref Flag::Skinning) + * @param jointsPerVertex Max count of joints that may influence a vertex + * default @cpp 4 @ce (see @ref Flag::Skinning) */ - explicit Phong(Flags flags = {}, UnsignedInt lightCount = 1); + explicit Phong(Flags flags = {}, UnsignedInt lightCount = 1, UnsignedInt jointCount = 0, UnsignedInt jointsPerVertex = 4); /** * @brief Construct without creating the underlying OpenGL object @@ -465,6 +511,12 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { /** @brief Light count */ UnsignedInt lightCount() const { return _lightCount; } + /** @brief Joint count */ + UnsignedInt jointCount() const { return _jointCount; } + + /** @brief Joints per vertex */ + UnsignedInt jointsPerVertex() const { return _jointsPerVertex; } + /** * @brief Set ambient color * @return Reference to self (for method chaining) @@ -719,6 +771,28 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { return setLightColors({&color, 1}); } + /** + * @brief Set joint matrices + * @return Reference to self (for method chaining) + * + * Initial values are identity transformations. Expects that the size + * of the @p matrices array is the same as @ref jointCount(). + * @see @ref setJointMatrix(UnsignedInt, const Matrix4&) + */ + Phong& setJointMatrices(const Containers::ArrayView matrices); + + /** @overload */ + Phong& setJointMatrices(std::initializer_list matrices); + + /** + * @brief Set joint matrix for given joint + * @return Reference to self (for method chaining) + * + * Unlike @ref setJointMatrices() updates just a single joint matrix. + * Expects that @p id is less than @ref joinCount(). + */ + Phong& setJointMatrix(UnsignedInt id, const Matrix4& matrix); + private: /* Prevent accidentally calling irrelevant functions */ #ifndef MAGNUM_TARGET_GLES @@ -730,6 +804,8 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { Flags _flags; UnsignedInt _lightCount; + UnsignedInt _jointCount; + UnsignedInt _jointsPerVertex; Int _transformationMatrixUniform{0}, _projectionMatrixUniform{1}, _normalMatrixUniform{2}, @@ -744,6 +820,7 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram { #endif Int _lightPositionsUniform{10}, _lightColorsUniform; /* 10 + lightCount, set in the constructor */ + Int _jointMatricesUniform; /* 10 + 2*lightCount, set in the constructor */ }; /** @debugoperatorclassenum{Phong,Phong::Flag} */ diff --git a/src/Magnum/Shaders/Phong.vert b/src/Magnum/Shaders/Phong.vert index e13c75176d..51dd4a18e3 100644 --- a/src/Magnum/Shaders/Phong.vert +++ b/src/Magnum/Shaders/Phong.vert @@ -80,6 +80,13 @@ layout(location = 10) uniform highp vec3 lightPositions[LIGHT_COUNT]; /* defaults to zero */ #endif +#ifdef SKINNING +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = JOINT_MATRICES_LOCATION) +#endif +uniform mat4 jointMatrices[JOINT_COUNT]; +#endif + #ifdef EXPLICIT_ATTRIB_LOCATION layout(location = POSITION_ATTRIBUTE_LOCATION) #endif @@ -117,6 +124,30 @@ in lowp vec4 vertexColor; out lowp vec4 interpolatedVertexColor; #endif +#ifdef SKINNING +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = WEIGHTS_ATTRIBUTE_LOCATION) +#endif +in mediump vec4 weights; + +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = JOINTIDS_ATTRIBUTE_LOCATION) +#endif +in mediump uvec4 jointIds; + +#if JOINTS_PER_VERTEX > 4 +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = SECONDARY_WEIGHTS_ATTRIBUTE_LOCATION) +#endif +in mediump vec4 secondaryWeights; + +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = SECONDARY_JOINTIDS_ATTRIBUTE_LOCATION) +#endif +in mediump vec4 secondaryJointIds; +#endif +#endif + #ifdef INSTANCED_OBJECT_ID #ifdef EXPLICIT_ATTRIB_LOCATION layout(location = OBJECT_ID_ATTRIBUTE_LOCATION) @@ -155,11 +186,25 @@ out highp vec3 cameraDirection; #endif void main() { + #ifdef SKINNING + mat4 skinMatrix; + int i = 0; + for(; i != JOINTS_PER_VERTEX && i != 4; ++i) + skinMatrix += weights[i]*jointMatrices[int(jointIds[i])]; + #if JOINTS_PER_VERTEX > 4 + for(i = 0; i != JOINTS_PER_VERTEX - 4 && i != 4; ++i) + skinMatrix += secondaryWeights[i]*jointMatrices[int(secondaryJointIds[i])]; + #endif + #endif + /* Transformed vertex position */ highp vec4 transformedPosition4 = transformationMatrix* #ifdef INSTANCED_TRANSFORMATION instancedTransformationMatrix* #endif + #ifdef SKINNING + skinMatrix* + #endif position; highp vec3 transformedPosition = transformedPosition4.xyz/transformedPosition4.w; diff --git a/src/Magnum/Shaders/generic.glsl b/src/Magnum/Shaders/generic.glsl index 180bc4d228..0460d30885 100644 --- a/src/Magnum/Shaders/generic.glsl +++ b/src/Magnum/Shaders/generic.glsl @@ -37,6 +37,11 @@ #define NORMAL_MATRIX_ATTRIBUTE_LOCATION 12 #define TEXTURE_OFFSET_ATTRIBUTE_LOCATION 15 +#define WEIGHTS_ATTRIBUTE_LOCATION 6 +#define JOINTIDS_ATTRIBUTE_LOCATION 7 +#define SECONDARY_WEIGHTS_ATTRIBUTE_LOCATION 10 +#define SECONDARY_JOINTIDS_ATTRIBUTE_LOCATION 11 + /* Outputs */ #define COLOR_OUTPUT_ATTRIBUTE_LOCATION 0 #define OBJECT_ID_OUTPUT_ATTRIBUTE_LOCATION 1 From 385ecc94b208eb28da33b8e4d3aeaffb5ac262d8 Mon Sep 17 00:00:00 2001 From: Squareys Date: Mon, 11 May 2020 14:16:00 +0200 Subject: [PATCH 8/9] compile() Signed-off-by: Squareys --- src/Magnum/MeshTools/Compile.cpp | 24 +++++++++ src/Magnum/MeshTools/Test/CompileGLTest.cpp | 55 +++++++++++++++------ 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/src/Magnum/MeshTools/Compile.cpp b/src/Magnum/MeshTools/Compile.cpp index 458a91c2c3..1c97c0f102 100644 --- a/src/Magnum/MeshTools/Compile.cpp +++ b/src/Magnum/MeshTools/Compile.cpp @@ -79,6 +79,8 @@ GL::Mesh compileInternal(const Trade::MeshData& meshData, GL::Buffer&& indices, continue; } + UnsignedInt jointIdsAttributesCount = 0; + UnsignedInt weightsAttributesCount = 0; switch(meshData.attributeName(i)) { case Trade::MeshAttribute::Position: /* Pick 3D position always, the format will properly reduce it @@ -113,6 +115,28 @@ GL::Mesh compileInternal(const Trade::MeshData& meshData, GL::Buffer&& indices, attribute.emplace(Shaders::Generic3D::ObjectId{}, format); break; #endif + case Trade::MeshAttribute::Weights: + if(weightsAttributesCount == 0) { + attribute.emplace(Shaders::Generic3D::Weights{}, format); + } else if(weightsAttributesCount == 1) { + attribute.emplace(Shaders::Generic3D::SecondaryWeights{}, format); + } else { + Warning{} << "MeshTools::compile(): ignoring" << meshData.attributeName(i) + << weightsAttributesCount << ", more than two are unsupported"; + } + ++weightsAttributesCount; + break; + case Trade::MeshAttribute::JointIds: + if(jointIdsAttributesCount == 0) { + attribute.emplace(Shaders::Generic3D::JointIds{}, format); + } else if(jointIdsAttributesCount == 1) { + attribute.emplace(Shaders::Generic3D::SecondaryJointIds{}, format); + } else { + Warning{} << "MeshTools::compile(): ignoring" << meshData.attributeName(i) + << jointIdsAttributesCount << ", more than two are unsupported"; + } + ++jointIdsAttributesCount; + break; /* To avoid the compiler warning that we didn't handle an enum value. For these a runtime warning is printed below. */ diff --git a/src/Magnum/MeshTools/Test/CompileGLTest.cpp b/src/Magnum/MeshTools/Test/CompileGLTest.cpp index 114535d394..fb917822a8 100644 --- a/src/Magnum/MeshTools/Test/CompileGLTest.cpp +++ b/src/Magnum/MeshTools/Test/CompileGLTest.cpp @@ -76,7 +76,8 @@ enum class Flag { GeneratedSmoothNormals = 1 << 6, TextureCoordinates2D = 1 << 7, Colors = 1 << 8, - ObjectId = 1 << 9 + ObjectId = 1 << 9, + Skinning = 1 << 10 }; typedef Containers::EnumSet Flags; @@ -152,7 +153,8 @@ constexpr struct { {"positions + colors", Flag::Colors}, {"positions + texture coordinates", Flag::TextureCoordinates2D}, {"positions + texture coordinates + colors", Flag::TextureCoordinates2D|Flag::Colors}, - {"positions, object id, nonindexed", Flag::ObjectId|Flag::NonIndexed} + {"positions, object id, nonindexed", Flag::ObjectId|Flag::NonIndexed}, + {"positions + skinning", Flag::Skinning}, }; constexpr struct { @@ -888,6 +890,8 @@ struct PackedVertex { Vector2us textureCoordinates; Color4ub color; UnsignedShort objectId; + Vector4 weights; + Vector4us jointIds; UnsignedShort:16; }; @@ -913,43 +917,55 @@ void CompileGLTest::packedAttributes() { const PackedVertex vertexData[]{ {Math::pack(Vector3{-0.75f, -0.75f, -0.35f}), Math::pack(Vector3{-0.5f, -0.5f, 1.0f}.normalized()), - Math::pack(Vector2{0.0f, 0.0f}), 0x00ff00_rgb, 13562}, + Math::pack(Vector2{0.0f, 0.0f}), 0x00ff00_rgb, 13562, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.00f, -0.75f, -0.25f}), Math::pack(Vector3{ 0.0f, -0.5f, 1.0f}.normalized()), - Math::pack(Vector2{0.5f, 0.0f}), 0x808000_rgb, 13562}, + Math::pack(Vector2{0.5f, 0.0f}), 0x808000_rgb, 13562, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.75f, -0.75f, -0.35f}), Math::pack(Vector3{ 0.5f, -0.5f, 1.0f}.normalized()), - Math::pack(Vector2{1.0f, 0.0f}), 0xff0000_rgb, 13562}, + Math::pack(Vector2{1.0f, 0.0f}), 0xff0000_rgb, 13562, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{-0.75f, 0.00f, -0.25f}), Math::pack(Vector3{-0.5f, 0.0f, 1.0f}.normalized()), - Math::pack(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 13562}, + Math::pack(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 13562, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.00f, 0.00f, 0.00f}), Math::pack(Vector3{ 0.0f, 0.0f, 1.0f}.normalized()), - Math::pack(Vector2{0.5f, 0.5f}), 0x808080_rgb, 13562}, + Math::pack(Vector2{0.5f, 0.5f}), 0x808080_rgb, 13562, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.75f, 0.00f, -0.25f}), Math::pack(Vector3{ 0.5f, 0.0f, 1.0f}.normalized()), - Math::pack(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 13562}, + Math::pack(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 13562, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{-0.75f, 0.00f, -0.25f}), Math::pack(Vector3{-0.5f, 0.0f, 1.0f}.normalized()), - Math::pack(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 26234}, + Math::pack(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 26234, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.00f, 0.00f, 0.00f}), Math::pack(Vector3{ 0.0f, 0.0f, 1.0f}.normalized()), - Math::pack(Vector2{0.5f, 0.5f}), 0x808080_rgb, 26234}, + Math::pack(Vector2{0.5f, 0.5f}), 0x808080_rgb, 26234, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.75f, 0.00f, -0.25f}), Math::pack(Vector3{ 0.5f, 0.0f, 1.0f}.normalized()), - Math::pack(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 26234}, + Math::pack(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 26234, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{-0.75f, 0.75f, -0.35f}), Math::pack(Vector3{-0.5f, 0.5f, 1.0f}.normalized()), - Math::pack(Vector2{0.0f, 1.0f}), 0x00ffff_rgb, 26234}, + Math::pack(Vector2{0.0f, 1.0f}), 0x00ffff_rgb, 26234, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.0f, 0.75f, -0.25f}), Math::pack(Vector3{ 0.0f, 0.5f, 1.0f}.normalized()), - Math::pack(Vector2{0.5f, 1.0f}), 0x8080ff_rgb, 26234}, + Math::pack(Vector2{0.5f, 1.0f}), 0x8080ff_rgb, 26234, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, {Math::pack(Vector3{ 0.75f, 0.75f, -0.35f}), Math::pack(Vector3{ 0.5f, 0.5f, 1.0f}.normalized()), - Math::pack(Vector2{1.0f, 1.0f}), 0xff00ff_rgb, 26234} + Math::pack(Vector2{1.0f, 1.0f}), 0xff00ff_rgb, 26234, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, }; static_assert(sizeof(PackedVertex) % 4 == 0, "the vertex is not 4-byte aligned and that's bad"); @@ -987,8 +1003,16 @@ void CompileGLTest::packedAttributes() { Trade::MeshAttributeData{ Trade::MeshAttribute::ObjectId, Containers::stridedArrayView(vertexData, &vertexData[0].objectId, - Containers::arraySize(vertexData), sizeof(PackedVertex))} + Containers::arraySize(vertexData), sizeof(PackedVertex))}, #endif + Trade::MeshAttributeData{ + Trade::MeshAttribute::Weights, + Containers::stridedArrayView(vertexData, &vertexData[0].weights, + Containers::arraySize(vertexData), sizeof(PackedVertex))}, + Trade::MeshAttributeData{ + Trade::MeshAttribute::JointIds, + Containers::stridedArrayView(vertexData, &vertexData[0].jointIds, + Containers::arraySize(vertexData), sizeof(PackedVertex))} }}; GL::Mesh mesh = compile(meshData); @@ -1012,6 +1036,7 @@ void CompileGLTest::packedAttributes() { .setTransformationMatrix(transformation) .setNormalMatrix(transformation.normalMatrix()) .setProjectionMatrix(projection) + .setJointMatrices({Matrix4{}, Matrix4{}, Matrix4{}, Matrix4{}}) .draw(mesh); MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_WITH( From 29990a7d64ec4afa59e5e8d39539f132ea248ce5 Mon Sep 17 00:00:00 2001 From: Squareys Date: Thu, 11 Jun 2020 15:10:49 +0200 Subject: [PATCH 9/9] WIP Signed-off-by: Squareys --- src/Magnum/MeshTools/Test/CompileGLTest.cpp | 24 ++++++++++----------- src/Magnum/Shaders/Phong.vert | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Magnum/MeshTools/Test/CompileGLTest.cpp b/src/Magnum/MeshTools/Test/CompileGLTest.cpp index fb917822a8..0e1d7aff53 100644 --- a/src/Magnum/MeshTools/Test/CompileGLTest.cpp +++ b/src/Magnum/MeshTools/Test/CompileGLTest.cpp @@ -918,54 +918,54 @@ void CompileGLTest::packedAttributes() { {Math::pack(Vector3{-0.75f, -0.75f, -0.35f}), Math::pack(Vector3{-0.5f, -0.5f, 1.0f}.normalized()), Math::pack(Vector2{0.0f, 0.0f}), 0x00ff00_rgb, 13562, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.00f, -0.75f, -0.25f}), Math::pack(Vector3{ 0.0f, -0.5f, 1.0f}.normalized()), Math::pack(Vector2{0.5f, 0.0f}), 0x808000_rgb, 13562, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.75f, -0.75f, -0.35f}), Math::pack(Vector3{ 0.5f, -0.5f, 1.0f}.normalized()), Math::pack(Vector2{1.0f, 0.0f}), 0xff0000_rgb, 13562, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{-0.75f, 0.00f, -0.25f}), Math::pack(Vector3{-0.5f, 0.0f, 1.0f}.normalized()), Math::pack(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 13562, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.00f, 0.00f, 0.00f}), Math::pack(Vector3{ 0.0f, 0.0f, 1.0f}.normalized()), Math::pack(Vector2{0.5f, 0.5f}), 0x808080_rgb, 13562, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.75f, 0.00f, -0.25f}), Math::pack(Vector3{ 0.5f, 0.0f, 1.0f}.normalized()), Math::pack(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 13562, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{-0.75f, 0.00f, -0.25f}), Math::pack(Vector3{-0.5f, 0.0f, 1.0f}.normalized()), Math::pack(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 26234, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.00f, 0.00f, 0.00f}), Math::pack(Vector3{ 0.0f, 0.0f, 1.0f}.normalized()), Math::pack(Vector2{0.5f, 0.5f}), 0x808080_rgb, 26234, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.75f, 0.00f, -0.25f}), Math::pack(Vector3{ 0.5f, 0.0f, 1.0f}.normalized()), Math::pack(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 26234, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{-0.75f, 0.75f, -0.35f}), Math::pack(Vector3{-0.5f, 0.5f, 1.0f}.normalized()), Math::pack(Vector2{0.0f, 1.0f}), 0x00ffff_rgb, 26234, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.0f, 0.75f, -0.25f}), Math::pack(Vector3{ 0.0f, 0.5f, 1.0f}.normalized()), Math::pack(Vector2{0.5f, 1.0f}), 0x8080ff_rgb, 26234, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, {Math::pack(Vector3{ 0.75f, 0.75f, -0.35f}), Math::pack(Vector3{ 0.5f, 0.5f, 1.0f}.normalized()), Math::pack(Vector2{1.0f, 1.0f}), 0xff00ff_rgb, 26234, - Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{0, 1, 2, 3}}, + Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}}, }; static_assert(sizeof(PackedVertex) % 4 == 0, "the vertex is not 4-byte aligned and that's bad"); diff --git a/src/Magnum/Shaders/Phong.vert b/src/Magnum/Shaders/Phong.vert index 51dd4a18e3..bf884f2488 100644 --- a/src/Magnum/Shaders/Phong.vert +++ b/src/Magnum/Shaders/Phong.vert @@ -190,10 +190,10 @@ void main() { mat4 skinMatrix; int i = 0; for(; i != JOINTS_PER_VERTEX && i != 4; ++i) - skinMatrix += weights[i]*jointMatrices[int(jointIds[i])]; + skinMatrix += weights[i]*jointMatrices[jointIds[i]]; #if JOINTS_PER_VERTEX > 4 for(i = 0; i != JOINTS_PER_VERTEX - 4 && i != 4; ++i) - skinMatrix += secondaryWeights[i]*jointMatrices[int(secondaryJointIds[i])]; + skinMatrix += secondaryWeights[i]*jointMatrices[secondaryJointIds[i]]; #endif #endif