Skip to content

Commit

Permalink
Trade: implement support for Weights & JointIds in MeshData.
Browse files Browse the repository at this point in the history
This is the first builtin array attribute, with one of the objectives
being an ability to support an arbitrary count of per-vertex weights in
a single contiguous attribute without the complexity of having to go
through several four-component attributes.

On the shader side it still needs to get cut into at most four
components per attribute, but there's no reason for such limitation to
get propagated here as well.

Co-authored-by: Vladimír Vondruš <mosra@centrum.cz>
  • Loading branch information
Squareys and mosra committed Dec 12, 2022
1 parent 7f94a6f commit f447e99
Show file tree
Hide file tree
Showing 4 changed files with 605 additions and 61 deletions.
16 changes: 16 additions & 0 deletions doc/snippets/MagnumTrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,22 @@ static_cast<void>(triangleIds);
static_cast<void>(triangleCounts);
}

{
/* [MeshData-jointIdsAsArray] */
Trade::MeshData data = DOXYGEN_ELLIPSIS(Trade::MeshData{{}, 0});

Containers::Array<UnsignedInt> array = data.jointIdsAsArray();
Containers::StridedArrayView2D<UnsignedInt> array2D{array,
{data.vertexCount(), data.attributeArraySize(Trade::MeshAttribute::JointIds)}};

for(Containers::StridedArrayView1D<UnsignedInt> i: array2D) {
for(UnsignedInt j: i) {
DOXYGEN_IGNORE(static_cast<void>(j);)// do something with joint ID j in vertex i
}
}
/* [MeshData-jointIdsAsArray] */
}

#ifdef MAGNUM_BUILD_DEPRECATED
{
CORRADE_IGNORE_DEPRECATED_PUSH
Expand Down
85 changes: 85 additions & 0 deletions src/Magnum/Trade/MeshData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& inde
}
}
}

/* Verify that count and array sizes of skin joint IDs and weights match */
const UnsignedInt jointIdAttributeCount = attributeCount(MeshAttribute::JointIds);
const UnsignedInt weightAttributeCount = attributeCount(MeshAttribute::Weights);
CORRADE_ASSERT(weightAttributeCount == jointIdAttributeCount,
"Trade::MeshData: expected" << jointIdAttributeCount << "weight attributes to match joint IDs but got" << weightAttributeCount, );
for(UnsignedInt i = 0; i != jointIdAttributeCount; ++i) {
const UnsignedInt jointIdsArraySize = attributeArraySize(MeshAttribute::JointIds, i);
const UnsignedInt weightsArraySize = attributeArraySize(MeshAttribute::Weights, i);
CORRADE_ASSERT(weightsArraySize == jointIdsArraySize,
"Trade::MeshData: expected" << jointIdsArraySize << "array items for weight attribute" << i << "to match joint IDs but got" << weightsArraySize, );
}
#endif
}

Expand Down Expand Up @@ -835,6 +847,77 @@ Containers::Array<Color4> MeshData::colorsAsArray(const UnsignedInt id) const {
return out;
}

void MeshData::jointIdsInto(const Containers::StridedArrayView2D<UnsignedInt>& destination, const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::JointIds, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::jointIdsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "joint ID attributes", );
const MeshAttributeData& attribute = _attributes[attributeId];
#ifndef CORRADE_NO_ASSERT
const Containers::Size2D expectedSize{_vertexCount, attribute._arraySize};
#endif
CORRADE_ASSERT(destination.size() == expectedSize,
"Trade::MeshData::jointIdsInto(): expected a view with" << expectedSize << "elements but got" << destination.size(), );
CORRADE_ASSERT(destination.isContiguous<1>(),
"Trade::MeshData::jointIdsInto(): second view dimension is not contiguous", );
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::jointIdsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);

if(attribute._format == VertexFormat::UnsignedInt)
Utility::copy(Containers::arrayCast<2, const UnsignedInt>(attributeData, attribute._arraySize), destination);
else if(attribute._format == VertexFormat::UnsignedByte)
Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, attribute._arraySize), destination);
else if(attribute._format == VertexFormat::UnsignedShort)
Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, attribute._arraySize), destination);
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}

Containers::Array<UnsignedInt> MeshData::jointIdsAsArray(const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::JointIds, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::jointIdsAsArray(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "joint ID attributes", {});
const MeshAttributeData& attribute = _attributes[attributeId];
Containers::Array<UnsignedInt> out{_vertexCount*attribute._arraySize};
jointIdsInto(Containers::StridedArrayView2D<UnsignedInt>{out, {_vertexCount, attribute._arraySize}}, id);
return out;
}

void MeshData::weightsInto(const Containers::StridedArrayView2D<Float>& destination, const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Weights, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{},
"Trade::MeshData::weightsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::Weights) << "weight attributes", );
const MeshAttributeData& attribute = _attributes[attributeId];
#ifndef CORRADE_NO_ASSERT
const Containers::Size2D expectedSize{_vertexCount, attribute._arraySize};
#endif
CORRADE_ASSERT(destination.size() == expectedSize,
"Trade::MeshData::weightsInto(): expected a view with" << expectedSize << "elements but got" << destination.size(), );
CORRADE_ASSERT(destination.isContiguous<1>(),
"Trade::MeshData::weightsInto(): second view dimension is not contiguous", );
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format),
"Trade::MeshData::weightsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast<void*>(vertexFormatUnwrap(attribute._format)), );
const Containers::StridedArrayView1D<const void> attributeData = attributeDataViewInternal(attribute);

if(attribute._format == VertexFormat::Float)
Utility::copy(Containers::arrayCast<2, const Float>(attributeData, attribute._arraySize), destination);
else if(attribute._format == VertexFormat::Half)
Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, attribute._arraySize), destination);
else if(attribute._format == VertexFormat::UnsignedByteNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, attribute._arraySize), destination);
else if(attribute._format == VertexFormat::UnsignedShortNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, attribute._arraySize), destination);
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}

Containers::Array<Float> MeshData::weightsAsArray(const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::Weights, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::weightsAsArray(): index" << id << "out of range for" << attributeCount(MeshAttribute::JointIds) << "weight attributes", {});
const MeshAttributeData& attribute = _attributes[attributeId];
Containers::Array<Float> out{_vertexCount*attribute._arraySize};
weightsInto(Containers::StridedArrayView2D<Float>{out, {_vertexCount, attribute._arraySize}}, id);
return out;
}

void MeshData::objectIdsInto(const Containers::StridedArrayView1D<UnsignedInt>& destination, const UnsignedInt id) const {
const UnsignedInt attributeId = findAttributeIdInternal(MeshAttribute::ObjectId, id);
CORRADE_ASSERT(attributeId != ~UnsignedInt{}, "Trade::MeshData::objectIdsInto(): index" << id << "out of range for" << attributeCount(MeshAttribute::ObjectId) << "object ID attributes", );
Expand Down Expand Up @@ -896,6 +979,8 @@ Debug& operator<<(Debug& debug, const MeshAttribute value) {
_c(Normal)
_c(TextureCoordinates)
_c(Color)
_c(JointIds)
_c(Weights)
_c(ObjectId)
#undef _c
/* LCOV_EXCL_STOP */
Expand Down
Loading

0 comments on commit f447e99

Please sign in to comment.