Browse Source

Shaders: allow uploading just a subset of joint matrices.

It's not a GL error, and allows the application to compile just a single
shader for all skinned meshes, not one for each skeleton size. Together
with the dynamic per-vertex joint count this means the app only needs a
single shader for all skinned meshes, which is nice.
pull/499/head
Vladimír Vondruš 3 years ago
parent
commit
96b5bd2d86
  1. 4
      src/Magnum/Shaders/FlatGL.cpp
  2. 31
      src/Magnum/Shaders/FlatGL.h
  3. 8
      src/Magnum/Shaders/MeshVisualizerGL.cpp
  4. 46
      src/Magnum/Shaders/MeshVisualizerGL.h
  5. 4
      src/Magnum/Shaders/PhongGL.cpp
  6. 28
      src/Magnum/Shaders/PhongGL.h
  7. 15
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  8. 23
      src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp
  9. 13
      src/Magnum/Shaders/Test/PhongGLTest.cpp

4
src/Magnum/Shaders/FlatGL.cpp

@ -498,8 +498,8 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setObje
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setJointMatrices(const Containers::ArrayView<const MatrixTypeFor<dimensions, Float>> matrices) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::FlatGL::setJointMatrices(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_jointCount == matrices.size(),
"Shaders::FlatGL::setJointMatrices(): expected" << _jointCount << "items but got" << matrices.size(), *this);
CORRADE_ASSERT(matrices.size() <= _jointCount,
"Shaders::FlatGL::setJointMatrices(): expected at most" << _jointCount << "items but got" << matrices.size(), *this);
if(_jointCount) setUniform(_jointMatricesUniform, matrices);
return *this;
}

31
src/Magnum/Shaders/FlatGL.h

@ -152,10 +152,13 @@ per-vertex primary and secondary joint count in
@ref Configuration::setJointCount() and upload appropriate joint matrices with
@ref setJointMatrices().
To avoid having to compile multiple shader variants for different per-vertex
joint counts, enable @ref Flag::DynamicPerVertexJointCount, set the maximum
per-vertex joint count in @ref Configuration::setJointCount() and then adjust
the actual per-draw joint count with @ref setPerVertexJointCount().
To avoid having to compile multiple shader variants for different joint matrix
counts, set the maximum used joint count in @ref Configuration::setJointCount()
and then upload just a prefix via @ref setJointMatrices(). Similarly, to avoid
multiple variants for different per-vertex joint counts, enable
@ref Flag::DynamicPerVertexJointCount, set the maximum per-vertex joint count
in @ref Configuration::setJointCount() and then adjust the actual per-draw
joint count with @ref setPerVertexJointCount().
@requires_gl30 Extension @gl_extension{EXT,texture_integer}
@requires_gles30 Skinning requires integer support in shaders, which is not
@ -1015,7 +1018,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @m_since_latest
*
* Initial values are identity transformations. Expects that the size
* of the @p matrices array is the same as @ref jointCount().
* of the @p matrices array is not larger than @ref jointCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationUniform2D::transformationMatrix /
@ -1393,15 +1396,15 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL<dimensions>:
/**
* @brief Set joint count
*
* If @ref Flag::UniformBuffers isn't set, @p count describes how many
* joint matrices get supplied to each draw by @ref setJointMatrices()
* / @ref setJointMatrix(). If @ref Flag::UniformBuffers is set,
* @p count describes size of a @ref TransformationUniform2D /
* @ref TransformationUniform3D buffer bound with
* @ref bindJointBuffer(); as uniform buffers are required to have a
* statically defined size. The per-vertex joints then index into the
* array offset by @ref FlatDrawUniform::jointOffset. If @p count is
* @cpp 0 @ce, skinning is not performed.
* If @ref Flag::UniformBuffers isn't set, @p count describes an upper
* bound on how many joint matrices get supplied to each draw by
* @ref setJointMatrices() / @ref setJointMatrix(). If
* @ref Flag::UniformBuffers is set, @p count describes size of a
* @ref TransformationUniform2D / @ref TransformationUniform3D buffer
* bound with @ref bindJointBuffer(); as uniform buffers are required
* to have a statically defined size. The per-vertex joints then index
* into the array offset by @ref FlatDrawUniform::jointOffset. If
* @p count is @cpp 0 @ce, skinning is not performed.
*
* The @p perVertexCount and @p secondaryPerVertexCount then describe
* how many components are taken from @ref JointIds / @ref Weights and

8
src/Magnum/Shaders/MeshVisualizerGL.cpp

@ -803,8 +803,8 @@ MeshVisualizerGL2D& MeshVisualizerGL2D::setSmoothness(const Float smoothness) {
MeshVisualizerGL2D& MeshVisualizerGL2D::setJointMatrices(const Containers::ArrayView<const Matrix3> matrices) {
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL2D::setJointMatrices(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_jointCount == matrices.size(),
"Shaders::MeshVisualizerGL2D::setJointMatrices(): expected" << _jointCount << "items but got" << matrices.size(), *this);
CORRADE_ASSERT(matrices.size() <= _jointCount,
"Shaders::MeshVisualizerGL2D::setJointMatrices(): expected at most" << _jointCount << "items but got" << matrices.size(), *this);
if(_jointCount) setUniform(_jointMatricesUniform, matrices);
return *this;
}
@ -1372,8 +1372,8 @@ MeshVisualizerGL3D& MeshVisualizerGL3D::setSmoothness(const Float smoothness) {
MeshVisualizerGL3D& MeshVisualizerGL3D::setJointMatrices(const Containers::ArrayView<const Matrix4> matrices) {
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL3D::setJointMatrices(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_jointCount == matrices.size(),
"Shaders::MeshVisualizerGL3D::setJointMatrices(): expected" << _jointCount << "items but got" << matrices.size(), *this);
CORRADE_ASSERT(matrices.size() <= _jointCount,
"Shaders::MeshVisualizerGL3D::setJointMatrices(): expected at most" << _jointCount << "items but got" << matrices.size(), *this);
if(_jointCount) setUniform(_jointMatricesUniform, matrices);
return *this;
}

46
src/Magnum/Shaders/MeshVisualizerGL.h

@ -897,7 +897,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* @m_since_latest
*
* Initial values are identity transformations. Expects that the size
* of the @p matrices array is the same as @ref jointCount().
* of the @p matrices array is not larger than @ref jointCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationUniform2D::transformationMatrix and call
@ -1193,13 +1193,13 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D::Configuration {
/**
* @brief Set joint count
*
* If @ref Flag::UniformBuffers isn't set, @p count describes how many
* joint matrices get supplied to each draw by @ref setJointMatrices()
* / @ref setJointMatrix(). If @ref Flag::UniformBuffers is set,
* @p count describes size of a @ref TransformationUniform2D buffer
* bound with @ref bindJointBuffer(); as uniform buffers are required
* to have a statically defined size. The per-vertex joints then index
* into the array offset by
* If @ref Flag::UniformBuffers isn't set, @p count describes an upper
* bound on how many joint matrices get supplied to each draw with
* @ref setJointMatrices() / @ref setJointMatrix(). If
* @ref Flag::UniformBuffers is set, @p count describes size of a
* @ref TransformationUniform2D buffer bound with @ref bindJointBuffer();
* as uniform buffers are required to have a statically defined size.
* The per-vertex joints then index into the array offset by
* @ref MeshVisualizerDrawUniform2D::jointOffset. If @p count is
* @cpp 0 @ce, skinning is not performed.
*
@ -1509,10 +1509,13 @@ per-vertex primary and secondary joint count in
transforming the mesh vertices for feature parity with other shaders,
no skinning-specific visualization feature is implemented.
To avoid having to compile multiple shader variants for different per-vertex
joint counts, enable @ref Flag::DynamicPerVertexJointCount, set the maximum
per-vertex joint count in @ref Configuration::setJointCount() and then adjust
the actual per-draw joint count with @ref setPerVertexJointCount().
To avoid having to compile multiple shader variants for different joint matrix
counts, set the maximum used joint count in @ref Configuration::setJointCount()
and then upload just a prefix via @ref setJointMatrices(). Similarly, to avoid
multiple variants for different per-vertex joint counts, enable
@ref Flag::DynamicPerVertexJointCount, set the maximum per-vertex joint count
in @ref Configuration::setJointCount() and then adjust the actual per-draw
joint count with @ref setPerVertexJointCount().
@requires_gl30 Extension @gl_extension{EXT,texture_integer}
@requires_gles30 Skinning requires integer support in shaders, which is not
@ -2744,7 +2747,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @m_since_latest
*
* Initial values are identity transformations. Expects that the size
* of the @p matrices array is the same as @ref jointCount().
* of the @p matrices array is not larger than @ref jointCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationUniform3D::transformationMatrix and call
@ -3140,14 +3143,15 @@ class MeshVisualizerGL3D::Configuration {
/**
* @brief Set joint count
*
* If @ref Flag::UniformBuffers isn't set, @p count describes how many
* joint matrices get supplied to each draw by @ref setJointMatrices()
* / @ref setJointMatrix(). If @ref Flag::UniformBuffers is set,
* @p count describes size of a @ref TransformationUniform3D buffer
* bound with @ref bindJointBuffer(); as uniform buffers are required
* to have a statically defined size. The per-vertex joints then index
* into the array offset by @ref MeshVisualizerDrawUniform3D::jointOffset.
* If @p count is @cpp 0 @ce, skinning is not performed.
* If @ref Flag::UniformBuffers isn't set, @p count describes an upper
* bound on how many joint matrices get supplied to each draw with
* @ref setJointMatrices() / @ref setJointMatrix(). If
* @ref Flag::UniformBuffers is set, @p count describes size of a
* @ref TransformationUniform3D buffer bound with @ref bindJointBuffer();
* as uniform buffers are required to have a statically defined size.
* The per-vertex joints then index into the array offset by
* @ref MeshVisualizerDrawUniform3D::jointOffset. If @p count is
* @cpp 0 @ce, skinning is not performed.
*
* The @p perVertexCount and @p secondaryPerVertexCount then describe
* how many components are taken from @ref JointIds / @ref Weights and

4
src/Magnum/Shaders/PhongGL.cpp

@ -886,8 +886,8 @@ PhongGL& PhongGL::setLightRange(const UnsignedInt id, const Float range) {
PhongGL& PhongGL::setJointMatrices(const Containers::ArrayView<const Matrix4> matrices) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setJointMatrices(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_jointCount == matrices.size(),
"Shaders::PhongGL::setJointMatrices(): expected" << _jointCount << "items but got" << matrices.size(), *this);
CORRADE_ASSERT(matrices.size() <= _jointCount,
"Shaders::PhongGL::setJointMatrices(): expected at most" << _jointCount << "items but got" << matrices.size(), *this);
if(_jointCount) setUniform(_jointMatricesUniform, matrices);
return *this;
}

28
src/Magnum/Shaders/PhongGL.h

@ -241,10 +241,13 @@ per-vertex primary and secondary joint count in
@ref Configuration::setJointCount() and upload appropriate joint matrices with
@ref setJointMatrices().
To avoid having to compile multiple shader variants for different per-vertex
joint counts, enable @ref Flag::DynamicPerVertexJointCount, set the maximum
per-vertex joint count in @ref Configuration::setJointCount() and then adjust
the actual per-draw joint count with @ref setPerVertexJointCount().
To avoid having to compile multiple shader variants for different joint matrix
counts, set the maximum used joint count in @ref Configuration::setJointCount()
and then upload just a prefix via @ref setJointMatrices(). Similarly, to avoid
multiple variants for different per-vertex joint counts, enable
@ref Flag::DynamicPerVertexJointCount, set the maximum per-vertex joint count
in @ref Configuration::setJointCount() and then adjust the actual per-draw
joint count with @ref setPerVertexJointCount().
@requires_gl30 Extension @gl_extension{EXT,texture_integer}
@requires_gles30 Object ID output requires integer support in shaders, which
@ -2175,14 +2178,15 @@ class MAGNUM_SHADERS_EXPORT PhongGL::Configuration {
/**
* @brief Set joint count
*
* If @ref Flag::UniformBuffers isn't set, @p count describes how many
* joint matrices get supplied to each draw by @ref setJointMatrices()
* / @ref setJointMatrix(). If @ref Flag::UniformBuffers is set,
* @p count describes size of a @ref TransformationUniform3D buffer
* bound with @ref bindJointBuffer(); as uniform buffers are required
* to have a statically defined size. The per-vertex joints then index
* into the array offset by @ref PhongDrawUniform::jointOffset. If
* @p count is @cpp 0 @ce, skinning is not performed.
* If @ref Flag::UniformBuffers isn't set, @p count describes an upper
* bound on how many joint matrices get supplied to each draw with
* @ref setJointMatrices() / @ref setJointMatrix(). If
* @ref Flag::UniformBuffers is set, @p count describes size of a
* @ref TransformationUniform3D buffer bound with @ref bindJointBuffer();
* as uniform buffers are required to have a statically defined size.
* The per-vertex joints then index into the array offset by
* @ref PhongDrawUniform::jointOffset. If @p count is @cpp 0 @ce,
* skinning is not performed.
*
* The @p perVertexCount and @p secondaryPerVertexCount then describe
* how many components are taken from @ref JointIds / @ref Weights and

15
src/Magnum/Shaders/Test/FlatGLTest.cpp

@ -542,7 +542,12 @@ const struct {
{3*4, FlatGL2D::Weights{FlatGL2D::Weights::Components::Three}},
}}, false, true, false,
"skinning.tga"},
{"single set, joint matrices one by one", 5, 3, 0, 0, 0, {}, {InPlaceInit, {
{"single set, upload just a prefix of joint matrices", 15, 3, 0, 0, 0, {}, {InPlaceInit, {
{0, FlatGL2D::JointIds{FlatGL2D::JointIds::Components::Three}},
{3*4, FlatGL2D::Weights{FlatGL2D::Weights::Components::Three}},
}}, false, true, false,
"skinning.tga"},
{"single set, upload joint matrices one by one", 5, 3, 0, 0, 0, {}, {InPlaceInit, {
{0, FlatGL2D::JointIds{FlatGL2D::JointIds::Components::Three}},
{3*4, FlatGL2D::Weights{FlatGL2D::Weights::Components::Three}},
}}, false, true, true,
@ -1587,10 +1592,12 @@ template<UnsignedInt dimensions> void FlatGLTest::setWrongJointCountOrId() {
std::ostringstream out;
Error redirectError{&out};
shader.setJointMatrices({MatrixTypeFor<dimensions, Float>{}});
shader.setJointMatrix(5, MatrixTypeFor<dimensions, Float>{});
/* Calling setJointMatrices() with less items is fine, tested in
renderSkinning*D() */
shader.setJointMatrices({{}, {}, {}, {}, {}, {}})
.setJointMatrix(5, MatrixTypeFor<dimensions, Float>{});
CORRADE_COMPARE(out.str(),
"Shaders::FlatGL::setJointMatrices(): expected 5 items but got 1\n"
"Shaders::FlatGL::setJointMatrices(): expected at most 5 items but got 6\n"
"Shaders::FlatGL::setJointMatrix(): joint ID 5 is out of bounds for 5 joints\n");
}
#endif

23
src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp

@ -935,7 +935,12 @@ const struct {
{3*4, MeshVisualizerGL2D::Weights{MeshVisualizerGL2D::Weights::Components::Three}},
}}, false, true, false,
"skinning.tga"},
{"single set, joint matrices one by one", 5, 3, 0, 0, 0, {}, {}, {InPlaceInit, {
{"single set, upload just a prefix of joint matrices", 15, 3, 0, 0, 0, {}, {}, {InPlaceInit, {
{0, MeshVisualizerGL2D::JointIds{MeshVisualizerGL2D::JointIds::Components::Three}},
{3*4, MeshVisualizerGL2D::Weights{MeshVisualizerGL2D::Weights::Components::Three}},
}}, false, true, false,
"skinning.tga"},
{"single set, upload joint matrices one by one", 5, 3, 0, 0, 0, {}, {}, {InPlaceInit, {
{0, MeshVisualizerGL2D::JointIds{MeshVisualizerGL2D::JointIds::Components::Three}},
{3*4, MeshVisualizerGL2D::Weights{MeshVisualizerGL2D::Weights::Components::Three}},
}}, false, true, true,
@ -2881,10 +2886,12 @@ void MeshVisualizerGLTest::setWrongJointCountOrId2D() {
std::ostringstream out;
Error redirectError{&out};
shader.setJointMatrices({Matrix3{}});
shader.setJointMatrix(5, Matrix3{});
/* Calling setJointMatrices() with less items is fine, tested in
renderSkinningWireframe2D() */
shader.setJointMatrices({{}, {}, {}, {}, {}, {}})
.setJointMatrix(5, Matrix3{});
CORRADE_COMPARE(out.str(),
"Shaders::MeshVisualizerGL2D::setJointMatrices(): expected 5 items but got 1\n"
"Shaders::MeshVisualizerGL2D::setJointMatrices(): expected at most 5 items but got 6\n"
"Shaders::MeshVisualizerGL2D::setJointMatrix(): joint ID 5 is out of bounds for 5 joints\n");
}
@ -2904,10 +2911,12 @@ void MeshVisualizerGLTest::setWrongJointCountOrId3D() {
std::ostringstream out;
Error redirectError{&out};
shader.setJointMatrices({Matrix4{}});
shader.setJointMatrix(5, Matrix4{});
/* Calling setJointMatrices() with less items is fine, tested in
renderSkinningWireframe3D() */
shader.setJointMatrices({{}, {}, {}, {}, {}, {}})
.setJointMatrix(5, Matrix4{});
CORRADE_COMPARE(out.str(),
"Shaders::MeshVisualizerGL3D::setJointMatrices(): expected 5 items but got 1\n"
"Shaders::MeshVisualizerGL3D::setJointMatrices(): expected at most 5 items but got 6\n"
"Shaders::MeshVisualizerGL3D::setJointMatrix(): joint ID 5 is out of bounds for 5 joints\n");
}
#endif

13
src/Magnum/Shaders/Test/PhongGLTest.cpp

@ -857,7 +857,12 @@ const struct {
{3*4, PhongGL::Weights{PhongGL::Weights::Components::Three}},
}}, false, true, false,
"skinning.tga"},
{"single set, joint matrices one by one", 5, 3, 0, 0, 0, {}, {InPlaceInit, {
{"single set, upload just a prefix of joint matrices", 15, 3, 0, 0, 0, {}, {InPlaceInit, {
{0, PhongGL::JointIds{PhongGL::JointIds::Components::Three}},
{3*4, PhongGL::Weights{PhongGL::Weights::Components::Three}},
}}, false, true, false,
"skinning.tga"},
{"single set, upload joint matrices one by one", 5, 3, 0, 0, 0, {}, {InPlaceInit, {
{0, PhongGL::JointIds{PhongGL::JointIds::Components::Three}},
{3*4, PhongGL::Weights{PhongGL::Weights::Components::Three}},
}}, false, true, true,
@ -2008,10 +2013,12 @@ void PhongGLTest::setWrongJointCountOrId() {
std::ostringstream out;
Error redirectError{&out};
shader.setJointMatrices({Matrix4{}})
/* Calling setJointMatrices() with less items is fine, tested in
renderSkinning() */
shader.setJointMatrices({{}, {}, {}, {}, {}, {}})
.setJointMatrix(5, Matrix4{});
CORRADE_COMPARE(out.str(),
"Shaders::PhongGL::setJointMatrices(): expected 5 items but got 1\n"
"Shaders::PhongGL::setJointMatrices(): expected at most 5 items but got 6\n"
"Shaders::PhongGL::setJointMatrix(): joint ID 5 is out of bounds for 5 joints\n");
}
#endif

Loading…
Cancel
Save