If there are too many wrinkle masks, discard the lowest weight ones (#988)
Since the shader supports a fixed maximum number of active wrinkle masks, if the number of active wrinkle masks is larger than that, it will crash where wrinkleMaskObjectSrg->SetImageArray is called with an array_view which is larger than the target image array. We need a sensible method of truncating the number of masks. One such method is to discard the lowest weight masks.
This commit is contained in:
@@ -526,6 +526,20 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
template<class X>
|
||||
void swizzle_unique(AZStd::vector<X>& values, const AZStd::vector<size_t>& indices)
|
||||
{
|
||||
AZStd::vector<X> out;
|
||||
out.reserve(indices.size());
|
||||
|
||||
for (size_t i : indices)
|
||||
{
|
||||
out.push_back(AZStd::move(values[i]));
|
||||
}
|
||||
|
||||
values = AZStd::move(out);
|
||||
}
|
||||
|
||||
void AtomActorInstance::OnUpdateSkinningMatrices()
|
||||
{
|
||||
if (m_skinnedMeshRenderProxy.IsValid())
|
||||
@@ -584,6 +598,30 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Assert(m_wrinkleMasks.size() == m_wrinkleMaskWeights.size(), "Must have equal # of masks and weights");
|
||||
|
||||
// If there's too many masks, truncate
|
||||
if (m_wrinkleMasks.size() > s_maxActiveWrinkleMasks)
|
||||
{
|
||||
// Build a remapping of indices (because we want to sort two vectors)
|
||||
AZStd::vector<size_t> remapped;
|
||||
remapped.resize_no_construct(m_wrinkleMasks.size());
|
||||
std::iota(remapped.begin(), remapped.end(), 0);
|
||||
|
||||
// Sort index remapping by weight (highest first)
|
||||
std::sort(remapped.begin(), remapped.end(), [&](size_t ia, size_t ib) {
|
||||
return m_wrinkleMaskWeights[ia] > m_wrinkleMaskWeights[ib];
|
||||
});
|
||||
|
||||
// Truncate indices list
|
||||
remapped.resize(s_maxActiveWrinkleMasks);
|
||||
|
||||
// Remap wrinkle masks list and weights list
|
||||
swizzle_unique(m_wrinkleMasks, remapped);
|
||||
swizzle_unique(m_wrinkleMaskWeights, remapped);
|
||||
}
|
||||
|
||||
m_skinnedMeshRenderProxy->SetMorphTargetWeights(lodIndex, m_morphTargetWeights);
|
||||
|
||||
// Until EMotionFX and Atom lods are synchronized [ATOM-13564] we don't know which EMotionFX lod to pull the weights from
|
||||
|
||||
Reference in New Issue
Block a user