Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Phong skinning #444

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Magnum/MeshTools/Compile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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. */
Expand Down
55 changes: 40 additions & 15 deletions src/Magnum/MeshTools/Test/CompileGLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Flag> Flags;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -888,6 +890,8 @@ struct PackedVertex {
Vector2us textureCoordinates;
Color4ub color;
UnsignedShort objectId;
Vector4 weights;
Vector4us jointIds;
UnsignedShort:16;
};

Expand All @@ -913,43 +917,55 @@ void CompileGLTest::packedAttributes() {
const PackedVertex vertexData[]{
{Math::pack<Vector3s>(Vector3{-0.75f, -0.75f, -0.35f}),
Math::pack<Vector3s>(Vector3{-0.5f, -0.5f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.0f, 0.0f}), 0x00ff00_rgb, 13562},
Math::pack<Vector2us>(Vector2{0.0f, 0.0f}), 0x00ff00_rgb, 13562,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.00f, -0.75f, -0.25f}),
Math::pack<Vector3s>(Vector3{ 0.0f, -0.5f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.5f, 0.0f}), 0x808000_rgb, 13562},
Math::pack<Vector2us>(Vector2{0.5f, 0.0f}), 0x808000_rgb, 13562,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.75f, -0.75f, -0.35f}),
Math::pack<Vector3s>(Vector3{ 0.5f, -0.5f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{1.0f, 0.0f}), 0xff0000_rgb, 13562},
Math::pack<Vector2us>(Vector2{1.0f, 0.0f}), 0xff0000_rgb, 13562,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},

{Math::pack<Vector3s>(Vector3{-0.75f, 0.00f, -0.25f}),
Math::pack<Vector3s>(Vector3{-0.5f, 0.0f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 13562},
Math::pack<Vector2us>(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 13562,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.00f, 0.00f, 0.00f}),
Math::pack<Vector3s>(Vector3{ 0.0f, 0.0f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.5f, 0.5f}), 0x808080_rgb, 13562},
Math::pack<Vector2us>(Vector2{0.5f, 0.5f}), 0x808080_rgb, 13562,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.75f, 0.00f, -0.25f}),
Math::pack<Vector3s>(Vector3{ 0.5f, 0.0f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 13562},
Math::pack<Vector2us>(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 13562,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},

{Math::pack<Vector3s>(Vector3{-0.75f, 0.00f, -0.25f}),
Math::pack<Vector3s>(Vector3{-0.5f, 0.0f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 26234},
Math::pack<Vector2us>(Vector2{0.0f, 0.5f}), 0x00ff80_rgb, 26234,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.00f, 0.00f, 0.00f}),
Math::pack<Vector3s>(Vector3{ 0.0f, 0.0f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.5f, 0.5f}), 0x808080_rgb, 26234},
Math::pack<Vector2us>(Vector2{0.5f, 0.5f}), 0x808080_rgb, 26234,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.75f, 0.00f, -0.25f}),
Math::pack<Vector3s>(Vector3{ 0.5f, 0.0f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 26234},
Math::pack<Vector2us>(Vector2{1.0f, 0.5f}), 0xff0080_rgb, 26234,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},

{Math::pack<Vector3s>(Vector3{-0.75f, 0.75f, -0.35f}),
Math::pack<Vector3s>(Vector3{-0.5f, 0.5f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.0f, 1.0f}), 0x00ffff_rgb, 26234},
Math::pack<Vector2us>(Vector2{0.0f, 1.0f}), 0x00ffff_rgb, 26234,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.0f, 0.75f, -0.25f}),
Math::pack<Vector3s>(Vector3{ 0.0f, 0.5f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{0.5f, 1.0f}), 0x8080ff_rgb, 26234},
Math::pack<Vector2us>(Vector2{0.5f, 1.0f}), 0x8080ff_rgb, 26234,
Vector4{0.4f, 0.3f, 0.2f, 0.1f}, Vector4us{2, 1, 0, 3}},
{Math::pack<Vector3s>(Vector3{ 0.75f, 0.75f, -0.35f}),
Math::pack<Vector3s>(Vector3{ 0.5f, 0.5f, 1.0f}.normalized()),
Math::pack<Vector2us>(Vector2{1.0f, 1.0f}), 0xff00ff_rgb, 26234}
Math::pack<Vector2us>(Vector2{1.0f, 1.0f}), 0xff00ff_rgb, 26234,
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");
Expand Down Expand Up @@ -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);
Expand All @@ -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(
Expand Down
30 changes: 24 additions & 6 deletions src/Magnum/Shaders/Generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ both bitangents and object ID for instancing, \n
<tr>
<td>6</td>
<td colspan="3">
* *Reserved* --- vertex weights
@ref Weights
</td>
</tr>
<tr>
<td>7</td>
<td colspan="3">
* *Reserved* --- bone indices
@ref JointIds
</td>
</tr>
<tr>
Expand All @@ -150,13 +150,13 @@ both bitangents and object ID for instancing, \n
<tr>
<td>10</td>
<td colspan="2">
* *Reserved* --- 2nd vertex weights
@ref SecondaryWeights
</td>
</tr>
<tr>
<td>11</td>
<td colspan="2">
* *Reserved* --- 2nd bone indices
@ref SecondaryJointIds
</td>
</tr>
<tr>
Expand Down Expand Up @@ -358,7 +358,21 @@ template<UnsignedInt dimensions> 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.
*/
typedef GL::Attribute<6, Vector4> Weights;

/**
* @brief Joint IDs
*
* @ref Magnum::Vector4ui "Vector4ui", four joint indices that may affect the vertex.
* Corresponds to @ref Trade::MeshAttribute::JointIds.
*/
typedef GL::Attribute<7, Vector4ui> JointIds;

/**
* @brief (Instanced) transformation matrix
Expand Down Expand Up @@ -455,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, Vector4ui> JointIds;

typedef GL::Attribute<10, Vector4> SecondaryWeights;
typedef GL::Attribute<11, Vector4ui> SecondaryJointIds;

typedef GL::Attribute<15, Vector2> TextureOffset;

Expand Down Expand Up @@ -483,7 +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;
/* 6, 7 reserved for vertex weights / bone IDs */

typedef GL::Attribute<8, Matrix4> TransformationMatrix;
/* 9, 10, 11 occupied by TransformationMatrix */
Expand Down
44 changes: 42 additions & 2 deletions src/Magnum/Shaders/Phong.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -353,6 +373,26 @@ Phong& Phong::setLightColor(UnsignedInt id, const Magnum::Color4& color) {
return *this;
}

Phong& Phong::setJointMatrices(const Containers::ArrayView<const Matrix4> 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<Matrix4> matrices) {
return setJointMatrices({matrices.begin(), matrices.size()});
}

Debug& operator<<(Debug& debug, const Phong::Flag value) {
debug << "Shaders::Phong::Flag" << Debug::nospace;

Expand Down
Loading