1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

glTF: Clean up rigid animation

This commit is contained in:
Lars Mueller 2025-04-25 22:49:39 +02:00 committed by Lars Müller
parent 5113fcaedd
commit 01e4395977
2 changed files with 52 additions and 63 deletions

View file

@ -364,18 +364,6 @@ IAnimatedMesh* SelfType::createMesh(io::IReadFile* file)
return nullptr; return nullptr;
} }
static void transformVertices(std::vector<video::S3DVertex> &vertices, const core::matrix4 &transform)
{
for (auto &vertex : vertices) {
// Apply scaling, rotation and rotation (in that order) to the position.
transform.transformVect(vertex.Pos);
// For the normal, we do not want to apply the translation.
vertex.Normal = transform.rotateAndScaleVect(vertex.Normal);
// Renormalize (length might have been affected by scaling).
vertex.Normal.normalize();
}
}
static void checkIndices(const std::vector<u16> &indices, const std::size_t nVerts) static void checkIndices(const std::vector<u16> &indices, const std::size_t nVerts)
{ {
for (u16 index : indices) { for (u16 index : indices) {
@ -425,12 +413,6 @@ void SelfType::MeshExtractor::addPrimitive(
if (n_vertices >= std::numeric_limits<u16>::max()) if (n_vertices >= std::numeric_limits<u16>::max())
throw std::runtime_error("too many vertices"); throw std::runtime_error("too many vertices");
// Apply the global transform along the parent chain.
// "Only the joint transforms are applied to the skinned mesh;
// the transform of the skinned mesh node MUST be ignored."
if (!skinIdx)
transformVertices(*vertices, parent->GlobalMatrix);
auto maybeIndices = getIndices(primitive); auto maybeIndices = getIndices(primitive);
std::vector<u16> indices; std::vector<u16> indices;
if (maybeIndices.has_value()) { if (maybeIndices.has_value()) {
@ -441,10 +423,9 @@ void SelfType::MeshExtractor::addPrimitive(
indices = generateIndices(vertices->size()); indices = generateIndices(vertices->size());
} }
m_irr_model->addMeshBuffer( auto *meshbuf = new SSkinMeshBuffer(std::move(*vertices), std::move(indices));
new SSkinMeshBuffer(std::move(*vertices), std::move(indices))); m_irr_model->addMeshBuffer(meshbuf);
const auto meshbufNr = m_irr_model->getMeshBufferCount() - 1; const auto meshbufNr = m_irr_model->getMeshBufferCount() - 1;
auto *meshbuf = m_irr_model->getMeshBuffer(meshbufNr);
if (primitive.material.has_value()) { if (primitive.material.has_value()) {
const auto &material = m_gltf_model.materials->at(*primitive.material); const auto &material = m_gltf_model.materials->at(*primitive.material);
@ -463,17 +444,17 @@ void SelfType::MeshExtractor::addPrimitive(
} }
} }
if (!skinIdx.has_value()) { if (!skinIdx) {
// No skin => all vertices belong entirely to their parent // Apply the global transform along the parent chain.
for (std::size_t v = 0; v < n_vertices; ++v) { meshbuf->Transformation = parent->GlobalMatrix;
auto *weight = m_irr_model->addWeight(parent); // Set up rigid animation
weight->buffer_id = meshbufNr; parent->AttachedMeshes.push_back(meshbufNr);
weight->vertex_id = v;
weight->strength = 1.0f;
}
return; return;
} }
// Otherwise: "Only the joint transforms are applied to the skinned mesh;
// the transform of the skinned mesh node MUST be ignored."
const auto &skin = m_gltf_model.skins->at(*skinIdx); const auto &skin = m_gltf_model.skins->at(*skinIdx);
const auto &attrs = primitive.attributes; const auto &attrs = primitive.attributes;

View file

@ -91,6 +91,20 @@ SECTION("minimal triangle") {
} }
} }
auto check_cube_vertices = [](auto *meshbuf) {
REQUIRE(meshbuf->getVertexCount() == 24);
auto vertices = static_cast<const irr::video::S3DVertex *>(
meshbuf->getVertices());
CHECK(vertices[0].Pos == v3f{-1.0f, -1.0f, -1.0f});
CHECK(vertices[3].Pos == v3f{-1.0f, 1.0f, -1.0f});
CHECK(vertices[6].Pos == v3f{-1.0f, -1.0f, 1.0f});
CHECK(vertices[9].Pos == v3f{-1.0f, 1.0f, 1.0f});
CHECK(vertices[12].Pos == v3f{1.0f, -1.0f, -1.0f});
CHECK(vertices[15].Pos == v3f{1.0f, 1.0f, -1.0f});
CHECK(vertices[18].Pos == v3f{1.0f, -1.0f, 1.0f});
CHECK(vertices[21].Pos == v3f{1.0f, 1.0f, 1.0f});
};
SECTION("blender cube") { SECTION("blender cube") {
const auto path = GENERATE( const auto path = GENERATE(
model_stem + "blender_cube.gltf", model_stem + "blender_cube.gltf",
@ -98,24 +112,20 @@ SECTION("blender cube") {
const auto mesh = loadMesh(path); const auto mesh = loadMesh(path);
REQUIRE(mesh); REQUIRE(mesh);
REQUIRE(mesh->getMeshBufferCount() == 1); REQUIRE(mesh->getMeshBufferCount() == 1);
auto *meshbuf = dynamic_cast<irr::scene::SSkinMeshBuffer *>(
mesh->getMeshBuffer(0));
REQUIRE(meshbuf);
SECTION("vertex coordinates are correct") { SECTION("vertex coordinates are correct") {
REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); core::matrix4 scale;
auto vertices = static_cast<const irr::video::S3DVertex *>( scale.setScale(v3f(10.0f));
mesh->getMeshBuffer(0)->getVertices()); REQUIRE(meshbuf->Transformation == scale);
CHECK(vertices[0].Pos == v3f{-10.0f, -10.0f, -10.0f}); check_cube_vertices(meshbuf);
CHECK(vertices[3].Pos == v3f{-10.0f, 10.0f, -10.0f});
CHECK(vertices[6].Pos == v3f{-10.0f, -10.0f, 10.0f});
CHECK(vertices[9].Pos == v3f{-10.0f, 10.0f, 10.0f});
CHECK(vertices[12].Pos == v3f{10.0f, -10.0f, -10.0f});
CHECK(vertices[15].Pos == v3f{10.0f, 10.0f, -10.0f});
CHECK(vertices[18].Pos == v3f{10.0f, -10.0f, 10.0f});
CHECK(vertices[21].Pos == v3f{10.0f, 10.0f, 10.0f});
} }
SECTION("vertex indices are correct") { SECTION("vertex indices are correct") {
REQUIRE(mesh->getMeshBuffer(0)->getIndexCount() == 36); REQUIRE(meshbuf->getIndexCount() == 36);
auto indices = static_cast<const irr::u16 *>( auto indices = static_cast<const irr::u16 *>(
mesh->getMeshBuffer(0)->getIndices()); meshbuf->getIndices());
CHECK(indices[0] == 16); CHECK(indices[0] == 16);
CHECK(indices[1] == 5); CHECK(indices[1] == 5);
CHECK(indices[2] == 22); CHECK(indices[2] == 22);
@ -123,9 +133,9 @@ SECTION("blender cube") {
} }
SECTION("vertex normals are correct") { SECTION("vertex normals are correct") {
REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); REQUIRE(meshbuf->getVertexCount() == 24);
auto vertices = static_cast<const irr::video::S3DVertex *>( auto vertices = static_cast<const irr::video::S3DVertex *>(
mesh->getMeshBuffer(0)->getVertices()); meshbuf->getVertices());
CHECK(vertices[0].Normal == v3f{-1.0f, 0.0f, 0.0f}); CHECK(vertices[0].Normal == v3f{-1.0f, 0.0f, 0.0f});
CHECK(vertices[1].Normal == v3f{0.0f, -1.0f, 0.0f}); CHECK(vertices[1].Normal == v3f{0.0f, -1.0f, 0.0f});
CHECK(vertices[2].Normal == v3f{0.0f, 0.0f, -1.0f}); CHECK(vertices[2].Normal == v3f{0.0f, 0.0f, -1.0f});
@ -136,9 +146,9 @@ SECTION("blender cube") {
} }
SECTION("texture coords are correct") { SECTION("texture coords are correct") {
REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); REQUIRE(meshbuf->getVertexCount() == 24);
auto vertices = static_cast<const irr::video::S3DVertex *>( auto vertices = static_cast<const irr::video::S3DVertex *>(
mesh->getMeshBuffer(0)->getVertices()); meshbuf->getVertices());
CHECK(vertices[0].TCoords == v2f{0.375f, 1.0f}); CHECK(vertices[0].TCoords == v2f{0.375f, 1.0f});
CHECK(vertices[1].TCoords == v2f{0.125f, 0.25f}); CHECK(vertices[1].TCoords == v2f{0.125f, 0.25f});
CHECK(vertices[2].TCoords == v2f{0.375f, 0.0f}); CHECK(vertices[2].TCoords == v2f{0.375f, 0.0f});
@ -151,20 +161,15 @@ SECTION("blender cube scaled") {
const auto mesh = loadMesh(model_stem + "blender_cube_scaled.gltf"); const auto mesh = loadMesh(model_stem + "blender_cube_scaled.gltf");
REQUIRE(mesh); REQUIRE(mesh);
REQUIRE(mesh->getMeshBufferCount() == 1); REQUIRE(mesh->getMeshBufferCount() == 1);
auto *meshbuf = dynamic_cast<irr::scene::SSkinMeshBuffer *>(
mesh->getMeshBuffer(0));
REQUIRE(meshbuf);
SECTION("Scaling is correct") { SECTION("Scaling is correct") {
REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); core::matrix4 scale;
auto vertices = static_cast<const irr::video::S3DVertex *>( scale.setScale(v3f{150.0f, 1.0f, 21.5f});
mesh->getMeshBuffer(0)->getVertices()); REQUIRE(meshbuf->Transformation == scale);
check_cube_vertices(meshbuf);
CHECK(vertices[0].Pos == v3f{-150.0f, -1.0f, -21.5f});
CHECK(vertices[3].Pos == v3f{-150.0f, 1.0f, -21.5f});
CHECK(vertices[6].Pos == v3f{-150.0f, -1.0f, 21.5f});
CHECK(vertices[9].Pos == v3f{-150.0f, 1.0f, 21.5f});
CHECK(vertices[12].Pos == v3f{150.0f, -1.0f, -21.5f});
CHECK(vertices[15].Pos == v3f{150.0f, 1.0f, -21.5f});
CHECK(vertices[18].Pos == v3f{150.0f, -1.0f, 21.5f});
CHECK(vertices[21].Pos == v3f{150.0f, 1.0f, 21.5f});
} }
} }
@ -174,14 +179,17 @@ SECTION("blender cube matrix transform") {
REQUIRE(mesh->getMeshBufferCount() == 1); REQUIRE(mesh->getMeshBufferCount() == 1);
SECTION("Transformation is correct") { SECTION("Transformation is correct") {
REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); auto *meshbuf = dynamic_cast<irr::scene::SSkinMeshBuffer *>(
mesh->getMeshBuffer(0));
REQUIRE(meshbuf);
REQUIRE(meshbuf->getVertexCount() == 24);
auto vertices = static_cast<const irr::video::S3DVertex *>( auto vertices = static_cast<const irr::video::S3DVertex *>(
mesh->getMeshBuffer(0)->getVertices()); meshbuf->getVertices());
const auto checkVertex = [&](const std::size_t i, v3f vec) { const auto checkVertex = [&](const std::size_t i, v3f vec) {
// The transform scales by (1, 2, 3) and translates by (4, 5, 6). // The transform scales by (1, 2, 3) and translates by (4, 5, 6).
CHECK(vertices[i].Pos == vec * v3f{1, 2, 3} // The -6 is due to the coordinate system conversion.
// The -6 is due to the coordinate system conversion. CHECK(meshbuf->Transformation.transformVect(vertices[i].Pos)
+ v3f{4, 5, -6}); == vec * v3f{1, 2, 3} + v3f{4, 5, -6});
}; };
checkVertex(0, v3f{-1, -1, -1}); checkVertex(0, v3f{-1, -1, -1});
checkVertex(3, v3f{-1, 1, -1}); checkVertex(3, v3f{-1, 1, -1});