Optimize model by merging similar meshes

pull/1356/head
Hleb Valoshka 2022-01-27 22:28:49 +02:00
parent ca80f4448a
commit 746b9e3ef3
3 changed files with 76 additions and 6 deletions

View File

@ -40,6 +40,13 @@ VertexDescription appendingAttributes(const VertexDescription& desc, It begin, I
return VertexDescription(std::move(allAttributes));
}
bool
isOpaqueMaterial(const Material &material)
{
return (!(material.opacity > 0.01f && material.opacity < 1.0f)) &&
material.blend != BlendMode::AdditiveBlend;
}
} // end unnamed namespace
@ -322,13 +329,7 @@ Mesh::addGroup(PrimitiveGroupType prim,
{
PrimitiveGroup g;
if (prim == PrimitiveGroupType::LineStrip || prim == PrimitiveGroupType::LineList)
{
g = createLinePrimitiveGroup(prim == PrimitiveGroupType::LineStrip, indices);
}
else
{
g.primOverride = prim;
}
g.indices = std::move(indices);
g.prim = prim;
@ -721,4 +722,51 @@ Mesh::getPrimitiveCount() const
return count;
}
void
Mesh::merge(const Mesh &other)
{
auto &ti = groups.front().indices;
const auto &oi = other.groups.front().indices;
ti.reserve(ti.size() + oi.size());
for (auto i : oi)
ti.push_back(i + nVertices);
vertices.reserve(vertices.size() + other.vertices.size());
vertices.insert(vertices.end(), other.vertices.begin(), other.vertices.end());
nVertices += other.nVertices;
}
bool
Mesh::canMerge(const Mesh &other, const std::vector<Material> &materials) const
{
if (getGroupCount() != 1 || other.getGroupCount() != 1)
return false;
const auto &tg = groups.front();
const auto &og = other.groups.front();
if (tg.vertexCountOverride != 0 || og.vertexCountOverride != 0 || tg.prim != PrimitiveGroupType::TriList)
return false;
if (std::tie(tg.materialIndex, tg.prim, vertexDesc.strideBytes) !=
std::tie(og.materialIndex, og.prim, other.vertexDesc.strideBytes))
return false;
if (!isOpaqueMaterial(materials[tg.materialIndex]) || !isOpaqueMaterial(materials[og.materialIndex]))
return false;
for (auto i = VertexAttributeSemantic::Position;
i < VertexAttributeSemantic::SemanticMax;
i = static_cast<VertexAttributeSemantic>(1 + static_cast<uint16_t>(i)))
{
auto &ta = vertexDesc.getAttribute(i);
auto &oa = other.vertexDesc.getAttribute(i);
if (ta.format != oa.format || ta.offsetWords != oa.offsetWords)
return false;
}
return true;
}
} // end namespace cmod

View File

@ -237,6 +237,9 @@ class Mesh
unsigned int getVertexStrideWords() const { return vertexDesc.strideBytes / sizeof(cmod::VWord); }
unsigned int getPrimitiveCount() const;
void merge(const Mesh&);
bool canMerge(const Mesh&, const std::vector<Material> &materials) const;
private:
PrimitiveGroup createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices);
void mergePrimitiveGroups();

View File

@ -15,8 +15,11 @@
#include <Eigen/Geometry>
#include <celutil/logger.h>
#include "model.h"
using celestia::util::GetLogger;
namespace cmod
{
@ -335,6 +338,22 @@ Model::sortMeshes(const MeshComparator& comparator)
// Sort the meshes so that completely opaque ones are first
std::sort(meshes.begin(), meshes.end(), std::ref(comparator));
std::vector<Mesh> newMeshes;
newMeshes.push_back(meshes[0].clone());
for (size_t i = 1; i < meshes.size(); i++)
{
auto &p = newMeshes.back();
if (!p.canMerge(meshes[i], materials))
{
newMeshes.push_back(meshes[i].clone());
continue;
}
p.merge(meshes[i]);
}
GetLogger()->info("Merged similar meshes: {} -> {}.\n", meshes.size(), newMeshes.size());
meshes = std::move(newMeshes);
}
} // end namespace cmod