Browse Source

MeshTools: support morph targets in concatenate().

While extremely easy to do with the linear lookup, I bet it'd be
something utterly complex like trying to hash a std::pair with the
original hashmap-based implementation.
pull/623/head
Vladimír Vondruš 3 years ago
parent
commit
d982ba9ec4
  1. 14
      src/Magnum/MeshTools/Concatenate.cpp
  2. 110
      src/Magnum/MeshTools/Test/ConcatenateTest.cpp

14
src/Magnum/MeshTools/Concatenate.cpp

@ -123,14 +123,14 @@ Trade::MeshData concatenate(Containers::Array<char>&& indexData, const UnsignedI
any equivalent in the destination mesh */ any equivalent in the destination mesh */
for(UnsignedInt src = 0; src != mesh.attributeCount(); ++src) { for(UnsignedInt src = 0; src != mesh.attributeCount(); ++src) {
/* Try to find a matching attribute in the destination mesh (same /* Try to find a matching attribute in the destination mesh (same
name, same set). Skip if no such attribute is found. This is a name, same set, same morph target ID). Skip if no such attribute
O(m + n) complexity (linear lookup in both the source and the is found. This is a O(m + n) complexity (linear lookup in both
output mesh), but given the assumption that meshes rarely have the source and the output mesh), but given the assumption that
more than 8-16 attributes it should still be faster than meshes rarely have more than 8-16 attributes it should still be
building a hashmap first and then doing a complex lookup in it faster than building a hashmap first and then doing a complex
(which is how it used to be before, using lookup in it (which is how it used to be before, using
std::unordered_multimap). */ std::unordered_multimap). */
const Containers::Optional<UnsignedInt> dst = out.findAttributeId(mesh.attributeName(src), mesh.attributeId(src)); const Containers::Optional<UnsignedInt> dst = out.findAttributeId(mesh.attributeName(src), mesh.attributeId(src), mesh.attributeMorphTargetId(src));
if(!dst) if(!dst)
continue; continue;

110
src/Magnum/MeshTools/Test/ConcatenateTest.cpp

@ -98,6 +98,7 @@ struct VertexDataA {
Vector2 texcoords2; Vector2 texcoords2;
Int:32; Int:32;
Vector3 position; Vector3 position;
Vector2 positionMorphTarget;
Short data[3]; Short data[3];
}; };
@ -110,13 +111,24 @@ void ConcatenateTest::concatenate() {
/* First is non-indexed, this layout (including the gap) will be /* First is non-indexed, this layout (including the gap) will be
preserved */ preserved */
const VertexDataA vertexDataA[]{ const VertexDataA vertexDataA[]{
{{0.1f, 0.2f}, {0.5f, 0.6f}, {1.0f, 2.0f, 3.0f}, {15, 3, -1}}, {{0.1f, 0.2f},
{{0.3f, 0.4f}, {0.7f, 0.8f}, {4.0f, 5.0f, 6.0f}, {14, 2, -4}} {0.5f, 0.6f},
{1.0f, 2.0f, 3.0f},
{3.0f, 1.0f},
{15, 3, -1}},
{{0.3f, 0.4f},
{0.7f, 0.8f},
{4.0f, 5.0f, 6.0f},
{6.0f, 4.0f},
{14, 2, -4}}
}; };
Containers::StridedArrayView1D<const VertexDataA> verticesA = vertexDataA; Containers::StridedArrayView1D<const VertexDataA> verticesA = vertexDataA;
Trade::MeshData a{MeshPrimitive::Points, {}, vertexDataA, { Trade::MeshData a{MeshPrimitive::Points, {}, vertexDataA, {
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
verticesA.slice(&VertexDataA::texcoords1)}, verticesA.slice(&VertexDataA::texcoords1)},
/* Morph target to verify it's correctly propagated */
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
verticesA.slice(&VertexDataA::positionMorphTarget), 37},
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
verticesA.slice(&VertexDataA::texcoords2)}, verticesA.slice(&VertexDataA::texcoords2)},
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Trade::MeshAttributeData{Trade::MeshAttribute::Position,
@ -127,17 +139,36 @@ void ConcatenateTest::concatenate() {
}}; }};
/* Second is indexed, has only one texture coordinate of the two, an extra /* Second is indexed, has only one texture coordinate of the two, an extra
color (which gets ignored) and misses the position (which will be color (which gets ignored) misses the position (which will be
zero-filled) */ zero-filled) but contains two morph target positions, of which only
one will get used, the one with a matching ID */
const struct VertexDataB { const struct VertexDataB {
Color4 color; Color4 color;
Short data[3]; Short data[3];
Vector2 texcoords1; Vector2 texcoords1;
Vector2 positionMorphTarget1;
Vector2 positionMorphTarget2;
} vertexDataB[]{ } vertexDataB[]{
{0x112233_rgbf, {28, -15, 0}, {0.15f, 0.25f}}, {0x112233_rgbf,
{0x445566_rgbf, {29, -16, 1}, {0.35f, 0.45f}}, {28, -15, 0},
{0x778899_rgbf, {30, -17, 2}, {0.55f, 0.65f}}, {0.15f, 0.25f},
{0xaabbcc_rgbf, {40, -18, 3}, {0.75f, 0.85f}} {},
{9.0f, 7.0f}},
{0x445566_rgbf,
{29, -16, 1},
{0.35f, 0.45f},
{},
{0.0f, 2.0f}},
{0x778899_rgbf,
{30, -17, 2},
{0.55f, 0.65f},
{},
{5.0f, 8.0f}},
{0xaabbcc_rgbf,
{40, -18, 3},
{0.75f, 0.85f},
{},
{2.0f, 0.0f}}
}; };
Containers::StridedArrayView1D<const VertexDataB> verticesB = vertexDataB; Containers::StridedArrayView1D<const VertexDataB> verticesB = vertexDataB;
const UnsignedShort indicesB[]{0, 2, 1, 0, 3, 2}; const UnsignedShort indicesB[]{0, 2, 1, 0, 3, 2};
@ -149,7 +180,12 @@ void ConcatenateTest::concatenate() {
Trade::MeshAttributeData{Trade::meshAttributeCustom(42), Trade::MeshAttributeData{Trade::meshAttributeCustom(42),
VertexFormat::Short, verticesB.slice(&VertexDataB::data), 3}, VertexFormat::Short, verticesB.slice(&VertexDataB::data), 3},
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
verticesB.slice(&VertexDataB::texcoords1)} verticesB.slice(&VertexDataB::texcoords1)},
/* Morph targets to verify they're correctly propagated */
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
verticesB.slice(&VertexDataB::positionMorphTarget1), 22},
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
verticesB.slice(&VertexDataB::positionMorphTarget2), 37}
}}; }};
/* Third is again non-indexed, has one texcoord attribute more (which will /* Third is again non-indexed, has one texcoord attribute more (which will
@ -163,9 +199,21 @@ void ConcatenateTest::concatenate() {
Vector2 texcoords1; Vector2 texcoords1;
Short data[1]; Short data[1];
} vertexDataC[]{ } vertexDataC[]{
{{0.425f, 0.475f}, {1.5f, 2.5f, 3.5f}, {0.725f, 0.775f}, {0.125f, 0.175f}, {320}}, {{0.425f, 0.475f},
{{0.525f, 0.575f}, {4.5f, 5.5f, 6.5f}, {0.825f, 0.875f}, {0.225f, 0.275f}, {3200}}, {1.5f, 2.5f, 3.5f},
{{0.625f, 0.675f}, {7.5f, 8.5f, 9.5f}, {0.925f, 0.975f}, {0.325f, 0.375f}, {32000}}, {0.725f, 0.775f},
{0.125f, 0.175f},
{320}},
{{0.525f, 0.575f},
{4.5f, 5.5f, 6.5f},
{0.825f, 0.875f},
{0.225f, 0.275f},
{3200}},
{{0.625f, 0.675f},
{7.5f, 8.5f, 9.5f},
{0.925f, 0.975f},
{0.325f, 0.375f},
{32000}},
}; };
Containers::StridedArrayView1D<const VertexDataC> verticesC = vertexDataC; Containers::StridedArrayView1D<const VertexDataC> verticesC = vertexDataC;
Trade::MeshData c{MeshPrimitive::Points, {}, vertexDataC, { Trade::MeshData c{MeshPrimitive::Points, {}, vertexDataC, {
@ -188,7 +236,7 @@ void ConcatenateTest::concatenate() {
MeshTools::concatenate({a, b, c}); MeshTools::concatenate({a, b, c});
CORRADE_COMPARE(dst.primitive(), MeshPrimitive::Points); CORRADE_COMPARE(dst.primitive(), MeshPrimitive::Points);
CORRADE_COMPARE(dst.attributeCount(), 4); CORRADE_COMPARE(dst.attributeCount(), 5);
CORRADE_COMPARE_AS(dst.attribute<Vector3>(Trade::MeshAttribute::Position), CORRADE_COMPARE_AS(dst.attribute<Vector3>(Trade::MeshAttribute::Position),
Containers::arrayView<Vector3>({ Containers::arrayView<Vector3>({
{1.0f, 2.0f, 3.0f}, {1.0f, 2.0f, 3.0f},
@ -198,6 +246,16 @@ void ConcatenateTest::concatenate() {
{4.5f, 5.5f, 6.5f}, {4.5f, 5.5f, 6.5f},
{7.5f, 8.5f, 9.5f} {7.5f, 8.5f, 9.5f}
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::Position, 0, 37),
Containers::arrayView<Vector2>({
{3.0f, 1.0f},
{6.0f, 4.0f},
{9.0f, 7.0f},
{0.0f, 2.0f},
{5.0f, 8.0f},
{2.0f, 0.0f},
{}, {}, {}, /* Missing in the third mesh */
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates), CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates),
Containers::arrayView<Vector2>({ Containers::arrayView<Vector2>({
{0.1f, 0.2f}, {0.1f, 0.2f},
@ -219,10 +277,10 @@ void ConcatenateTest::concatenate() {
{0.525f, 0.575f}, {0.525f, 0.575f},
{0.625f, 0.675f} {0.625f, 0.675f}
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
CORRADE_COMPARE(dst.attributeName(3), Trade::meshAttributeCustom(42)); CORRADE_COMPARE(dst.attributeName(4), Trade::meshAttributeCustom(42));
CORRADE_COMPARE(dst.attributeFormat(3), VertexFormat::Short); CORRADE_COMPARE(dst.attributeFormat(4), VertexFormat::Short);
CORRADE_COMPARE(dst.attributeArraySize(3), 3); CORRADE_COMPARE(dst.attributeArraySize(4), 3);
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Vector3s>(dst.attribute<Short[]>(3))), CORRADE_COMPARE_AS((Containers::arrayCast<1, const Vector3s>(dst.attribute<Short[]>(4))),
Containers::arrayView<Vector3s>({ Containers::arrayView<Vector3s>({
{15, 3, -1}, {14, 2, -4}, {15, 3, -1}, {14, 2, -4},
{28, -15, 0}, {29, -16, 1}, {30, -17, 2}, {40, -18, 3}, {28, -15, 0}, {29, -16, 1}, {30, -17, 2}, {40, -18, 3},
@ -240,19 +298,23 @@ void ConcatenateTest::concatenate() {
CORRADE_VERIFY(isInterleaved(dst)); CORRADE_VERIFY(isInterleaved(dst));
if(data.shouldPreserveLayout) { if(data.shouldPreserveLayout) {
/* The original interleaved layout should be preserved */ /* The original interleaved layout should be preserved, including the
order (attribute 1 is between 3 and 4) */
CORRADE_COMPARE(dst.attributeStride(0), sizeof(VertexDataA)); CORRADE_COMPARE(dst.attributeStride(0), sizeof(VertexDataA));
CORRADE_COMPARE(dst.attributeOffset(0), 0); CORRADE_COMPARE(dst.attributeOffset(0), 0);
CORRADE_COMPARE(dst.attributeOffset(1), sizeof(Vector2)); CORRADE_COMPARE(dst.attributeOffset(2), sizeof(Vector2));
CORRADE_COMPARE(dst.attributeOffset(2), 2*sizeof(Vector2) + 4); CORRADE_COMPARE(dst.attributeOffset(3), 2*sizeof(Vector2) + 4);
CORRADE_COMPARE(dst.attributeOffset(3), 2*sizeof(Vector2) + 4 + sizeof(Vector3)); CORRADE_COMPARE(dst.attributeOffset(1), 2*sizeof(Vector2) + 4 + sizeof(Vector3));
CORRADE_COMPARE(dst.attributeOffset(4), 3*sizeof(Vector2) + 4 + sizeof(Vector3));
} else { } else {
/* Everything gets tightly packed */ /* Everything gets tightly packed in offsets following attribute
CORRADE_COMPARE(dst.attributeStride(0), 2*sizeof(Vector2) + sizeof(Vector3) + 3*sizeof(Short)); order */
CORRADE_COMPARE(dst.attributeStride(0), 3*sizeof(Vector2) + sizeof(Vector3) + 3*sizeof(Short));
CORRADE_COMPARE(dst.attributeOffset(0), 0); CORRADE_COMPARE(dst.attributeOffset(0), 0);
CORRADE_COMPARE(dst.attributeOffset(1), sizeof(Vector2)); CORRADE_COMPARE(dst.attributeOffset(1), sizeof(Vector2));
CORRADE_COMPARE(dst.attributeOffset(2), 2*sizeof(Vector2)); CORRADE_COMPARE(dst.attributeOffset(2), 2*sizeof(Vector2));
CORRADE_COMPARE(dst.attributeOffset(3), 2*sizeof(Vector2) + sizeof(Vector3)); CORRADE_COMPARE(dst.attributeOffset(3), 3*sizeof(Vector2));
CORRADE_COMPARE(dst.attributeOffset(4), 3*sizeof(Vector2) + sizeof(Vector3));
} }
} }

Loading…
Cancel
Save