#4080 Rigged mesh support #6

For now not touching normalizeVolumeFaces() to not brick dae upload
master
Andrey Kleshchev 2025-05-28 12:02:50 +03:00 committed by Andrey Kleshchev
parent 078cc9b0c1
commit 4c60231c3f
3 changed files with 166 additions and 4 deletions

View File

@ -334,6 +334,162 @@ void LLModel::normalizeVolumeFaces()
}
}
void LLModel::normalizeVolumeFacesAndWeights()
{
if (!mVolumeFaces.empty())
{
LLVector4a min, max;
// For all of the volume faces
// in the model, loop over
// them and see what the extents
// of the volume along each axis.
min = mVolumeFaces[0].mExtents[0];
max = mVolumeFaces[0].mExtents[1];
for (U32 i = 1; i < mVolumeFaces.size(); ++i)
{
LLVolumeFace& face = mVolumeFaces[i];
update_min_max(min, max, face.mExtents[0]);
update_min_max(min, max, face.mExtents[1]);
if (face.mTexCoords)
{
LLVector2& min_tc = face.mTexCoordExtents[0];
LLVector2& max_tc = face.mTexCoordExtents[1];
min_tc = face.mTexCoords[0];
max_tc = face.mTexCoords[0];
for (S32 j = 1; j < face.mNumVertices; ++j)
{
update_min_max(min_tc, max_tc, face.mTexCoords[j]);
}
}
else
{
face.mTexCoordExtents[0].set(0, 0);
face.mTexCoordExtents[1].set(1, 1);
}
}
// Now that we have the extents of the model
// we can compute the offset needed to center
// the model at the origin.
// Compute center of the model
// and make it negative to get translation
// needed to center at origin.
LLVector4a trans;
trans.setAdd(min, max);
trans.mul(-0.5f);
// Compute the total size along all
// axes of the model.
LLVector4a size;
size.setSub(max, min);
// Prevent division by zero.
F32 x = size[0];
F32 y = size[1];
F32 z = size[2];
F32 w = size[3];
if (fabs(x) < F_APPROXIMATELY_ZERO)
{
x = 1.0;
}
if (fabs(y) < F_APPROXIMATELY_ZERO)
{
y = 1.0;
}
if (fabs(z) < F_APPROXIMATELY_ZERO)
{
z = 1.0;
}
size.set(x, y, z, w);
// Compute scale as reciprocal of size
LLVector4a scale;
scale.splat(1.f);
scale.div(size);
LLVector4a inv_scale(1.f);
inv_scale.div(scale);
for (U32 i = 0; i < mVolumeFaces.size(); ++i)
{
LLVolumeFace& face = mVolumeFaces[i];
// We shrink the extents so
// that they fall within
// the unit cube.
// VFExtents change
face.mExtents[0].add(trans);
face.mExtents[0].mul(scale);
face.mExtents[1].add(trans);
face.mExtents[1].mul(scale);
// For all the positions, we scale
// the positions to fit within the unit cube.
LLVector4a* pos = (LLVector4a*)face.mPositions;
LLVector4a* norm = (LLVector4a*)face.mNormals;
LLVector4a* t = (LLVector4a*)face.mTangents;
for (S32 j = 0; j < face.mNumVertices; ++j)
{
pos[j].add(trans);
pos[j].mul(scale);
if (norm && !norm[j].equals3(LLVector4a::getZero()))
{
norm[j].mul(inv_scale);
norm[j].normalize3();
}
if (t)
{
F32 w = t[j].getF32ptr()[3];
t[j].mul(inv_scale);
t[j].normalize3();
t[j].getF32ptr()[3] = w;
}
}
}
weight_map old_weights = mSkinWeights;
mSkinWeights.clear();
mPosition.clear();
for (auto& weights : old_weights)
{
LLVector4a pos(weights.first.mV[VX], weights.first.mV[VY], weights.first.mV[VZ]);
pos.add(trans);
pos.mul(scale);
LLVector3 scaled_pos(pos.getF32ptr());
mPosition.push_back(scaled_pos);
mSkinWeights[scaled_pos] = weights.second;
}
// mNormalizedScale is the scale at which
// we would need to multiply the model
// by to get the original size of the
// model instead of the normalized size.
LLVector4a normalized_scale;
normalized_scale.splat(1.f);
normalized_scale.div(scale);
mNormalizedScale.set(normalized_scale.getF32ptr());
mNormalizedTranslation.set(trans.getF32ptr());
mNormalizedTranslation *= -1.f;
// remember normalized scale so original dimensions can be recovered for mesh processing (i.e. tangent generation)
for (auto& face : mVolumeFaces)
{
face.mNormalizedScale = mNormalizedScale;
}
}
}
void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const
{
scale_out = mNormalizedScale;

View File

@ -202,6 +202,7 @@ public:
void sortVolumeFacesByMaterialName();
void normalizeVolumeFaces();
void normalizeVolumeFacesAndWeights();
void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
void remapVolumeFaces();
void optimizeVolumeFaces();

View File

@ -468,6 +468,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
if (skinIdx >= 0)
{
vert.weights = glm::vec4(prim.mWeights[i]);
auto accessorIdx = prim.mAttributes["JOINTS_0"];
LL::GLTF::Accessor::ComponentType componentType = LL::GLTF::Accessor::ComponentType::UNSIGNED_BYTE;
if (accessorIdx >= 0)
@ -487,8 +489,11 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
{
vert.joints = glm::unpackUint4x16(prim.mJoints[i]);
}
vert.weights = glm::vec4(prim.mWeights[i]);
else
{
vert.joints = glm::zero<glm::u16vec4>();
vert.weights = glm::zero<glm::vec4>();
}
}
vertices.push_back(vert);
}
@ -659,8 +664,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
}
}
// Call normalizeVolumeFaces to compute proper extents
pModel->normalizeVolumeFaces();
// Call normalizeVolumeFacesAndWeights to compute proper extents
pModel->normalizeVolumeFacesAndWeights();
// Fill joint names, bind matrices and prepare to remap weight indices
if (skinIdx >= 0)