Skip to content

Commit

Permalink
[mesh] fixed all issues with meshoptimizer and enabled optimization a…
Browse files Browse the repository at this point in the history
…nd a small simplification for all imported models
  • Loading branch information
PanosK92 committed Jan 9, 2025
1 parent 3a4a0af commit 2bb9f6e
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 146 deletions.
180 changes: 49 additions & 131 deletions runtime/Rendering/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,121 +40,44 @@ using namespace Spartan::Math;

namespace Spartan
{
namespace
namespace meshoptimizer
{
namespace meshoptimizer
// documentation: https://meshoptimizer.org/

void optimize(vector<RHI_Vertex_PosTexNorTan>& vertices, vector<uint32_t>& indices)
{
// documentation: https://meshoptimizer.org/

void optimize(vector<RHI_Vertex_PosTexNorTan>& vertices, vector<uint32_t>& indices)
{
// 1. first, generate a remap table to optimize vertex reuse
vector<uint32_t> remap(indices.size());
size_t vertex_count = meshopt_generateVertexRemap(
remap.data(),
indices.data(),
indices.size(),
vertices.data(),
vertices.size(),
sizeof(RHI_Vertex_PosTexNorTan)
);

// 2. create temporary buffers for remapped data
vector<RHI_Vertex_PosTexNorTan> vertices_remapped(vertex_count);
vector<uint32_t> indices_remapped(indices.size());

// 3. remap both buffers
meshopt_remapIndexBuffer(
indices_remapped.data(),
indices.data(),
indices.size(),
remap.data()
);

meshopt_remapVertexBuffer(
vertices_remapped.data(),
vertices.data(),
vertices.size(),
sizeof(RHI_Vertex_PosTexNorTan),
remap.data()
);

// 4. optimize vertex cache
meshopt_optimizeVertexCache(
indices_remapped.data(),
indices_remapped.data(),
indices_remapped.size(),
vertex_count
);

// 5. optimize overdraw
meshopt_optimizeOverdraw(
indices_remapped.data(),
indices_remapped.data(),
indices_remapped.size(),
reinterpret_cast<const float*>(&vertices_remapped[0].pos[0]),
vertex_count,
sizeof(RHI_Vertex_PosTexNorTan),
1.05f
);

// 6. optimize vertex fetch
meshopt_optimizeVertexFetch(
vertices_remapped.data(),
indices_remapped.data(),
indices_remapped.size(),
vertices_remapped.data(),
vertex_count,
sizeof(RHI_Vertex_PosTexNorTan)
);

// 7. copy optimized buffers back to the input vectors
vertices = std::move(vertices_remapped);
indices = std::move(indices_remapped);
}

void simplify(vector<RHI_Vertex_PosTexNorTan>& vertices, vector<uint32_t>& indices)
{
const size_t target_index_count = static_cast<size_t>(indices.size() * 0.1f);
const float target_error = 0.01f;

float result_error = 0.0f;
vector<uint32_t> indices_new(indices.size());
size_t index_count = meshopt_simplifySloppy(
&indices_new[0], // destination
&indices[0], // indices
indices.size(), // index count
reinterpret_cast<const float*>(&vertices[0].pos), // vertex positions
vertices.size(), // vertex count
sizeof(RHI_Vertex_PosTexNorTan), // vertex size
target_index_count,
target_error,
&result_error
);
indices = indices_new;
indices.resize(index_count);
}

void log_mesh_info(const char* name, vector<RHI_Vertex_PosTexNorTan>& vertices, vector<uint32_t>& indices)
{
meshopt_VertexCacheStatistics vcs = meshopt_analyzeVertexCache(
indices.data(),
indices.size(),
vertices.size(),
16,
0,
0
);

meshopt_VertexFetchStatistics vfs = meshopt_analyzeVertexFetch(
indices.data(),
indices.size(),
vertices.size(),
sizeof(RHI_Vertex_PosTexNorTan)
);

SP_LOG_INFO("Mesh: %s | Cache miss ratio: %.2f | Transformed vertex ratio: %.2f | Fetch overfetch: %.2f", name, vcs.acmr, vcs.atvr, vfs.overfetch);
}
size_t vertex_count = vertices.size();
size_t index_count = indices.size();

// create a remap table
vector<unsigned int> remap(index_count);
size_t vertex_count_optimized = meshopt_generateVertexRemap(remap.data(),
indices.data(),
index_count,
vertices.data(),
vertex_count,
sizeof(RHI_Vertex_PosTexNorTan));

// note: When we import with Assimp, JoinIdenticalVertices is used, so we don't need to remove duplicates here

// optimization #1: improve the locality of the vertices
meshopt_optimizeVertexCache(indices.data(), indices.data(), index_count, vertex_count);

// optimization #2: reduce pixel overdraw
meshopt_optimizeOverdraw(indices.data(), indices.data(), index_count, &(vertices[0].pos[0]), vertex_count, sizeof(RHI_Vertex_PosTexNorTan), 1.05f);

// optimization #3: optimize access to the vertex buffer
meshopt_optimizeVertexFetch(vertices.data(), indices.data(), index_count, vertices.data(), vertex_count, sizeof(RHI_Vertex_PosTexNorTan));

// optimization #4: create a simplified version of the model
float threshold = 1.0f;
float target_error = 0.0f;
size_t target_index_count = (size_t)(index_count * threshold);
vector<unsigned int> indices_simplified(indices.size());
size_t OptIndexCount = meshopt_simplify(indices_simplified.data(), indices.data(), index_count,
&vertices[0].pos[0], vertex_count, sizeof(RHI_Vertex_PosTexNorTan), target_index_count, target_error);

indices = indices_simplified;
}
}

Expand Down Expand Up @@ -268,27 +191,29 @@ namespace Spartan
}
}

void Mesh::AddVertices(const vector<RHI_Vertex_PosTexNorTan>& vertices, uint32_t* vertex_offset_out /*= nullptr*/)
void Mesh::AddGeometry(vector<RHI_Vertex_PosTexNorTan>& vertices, vector<uint32_t>& indices, uint32_t* vertex_offset_out, uint32_t* index_offset_out)
{
lock_guard lock(m_mutex_vertices);
if (m_flags & static_cast<uint32_t>(MeshFlags::PostProcessOptimize))
{
meshoptimizer::optimize(vertices, indices);
}

lock_guard lock(m_mutex);

// set vertex offset if requested
if (vertex_offset_out)
{
*vertex_offset_out = static_cast<uint32_t>(m_vertices.size());
}

m_vertices.insert(m_vertices.end(), vertices.begin(), vertices.end());
}

void Mesh::AddIndices(const vector<uint32_t>& indices, uint32_t* index_offset_out /*= nullptr*/)
{
lock_guard lock(m_mutex_vertices);


// set index offset if requested
if (index_offset_out)
{
*index_offset_out = static_cast<uint32_t>(m_indices.size());
}


// add
m_vertices.insert(m_vertices.end(), vertices.begin(), vertices.end());
m_indices.insert(m_indices.end(), indices.begin(), indices.end());
}

Expand Down Expand Up @@ -332,13 +257,6 @@ namespace Spartan

void Mesh::PostProcess()
{
if (m_flags & static_cast<uint32_t>(MeshFlags::PostProcessOptimize))
{
//meshoptimizer::log_mesh_info(m_object_name.c_str(), m_vertices, m_indices);
//meshoptimizer::optimize(m_vertices, m_indices);
//meshoptimizer::simplify(m_vertices, m_indices);
}

m_aabb = BoundingBox(m_vertices.data(), static_cast<uint32_t>(m_vertices.size()));

// normalize scale
Expand Down
12 changes: 3 additions & 9 deletions runtime/Rendering/Mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,8 @@ namespace Spartan
);
uint32_t GetMemoryUsage() const;

// add geometry
void AddVertices(const std::vector<RHI_Vertex_PosTexNorTan>& vertices, uint32_t* vertex_offset_out = nullptr);
void AddIndices(const std::vector<uint32_t>& indices, uint32_t* index_offset_out = nullptr);

// get geometry
// geometry
void AddGeometry(std::vector<RHI_Vertex_PosTexNorTan>& vertices, std::vector<uint32_t>& indices, uint32_t* vertex_offset_out = nullptr, uint32_t* index_offset_out = nullptr);
std::vector<RHI_Vertex_PosTexNorTan>& GetVertices() { return m_vertices; }
std::vector<uint32_t>& GetIndices() { return m_indices; }

Expand Down Expand Up @@ -122,11 +119,8 @@ namespace Spartan
// aabb
Math::BoundingBox m_aabb;

// sync primitives
std::mutex m_mutex_indices;
std::mutex m_mutex_vertices;

// misc
std::mutex m_mutex;
std::weak_ptr<Entity> m_root_entity;
MeshType m_type = MeshType::Custom;
};
Expand Down
3 changes: 1 addition & 2 deletions runtime/Rendering/Renderer_Resources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,8 +520,7 @@ namespace Spartan
mesh->SetResourceFilePath(project_directory + "standard_cone" + EXTENSION_MODEL);
}

mesh->AddIndices(indices);
mesh->AddVertices(vertices);
mesh->AddGeometry(vertices, indices);
mesh->SetType(type);
mesh->PostProcess();

Expand Down
3 changes: 1 addition & 2 deletions runtime/Resource/Import/ModelImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,8 +720,7 @@ namespace Spartan
// add vertex and index data to the mesh
uint32_t index_offset = 0;
uint32_t vertex_offset = 0;
mesh->AddIndices(indices, &index_offset);
mesh->AddVertices(vertices, &vertex_offset);
mesh->AddGeometry(vertices, indices, &vertex_offset, &index_offset);

// add a renderable component to this entity
shared_ptr<Renderable> renderable = entity_parent->AddComponent<Renderable>();
Expand Down
3 changes: 1 addition & 2 deletions runtime/World/Components/Terrain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,7 @@ namespace Spartan
// update with geometry
shared_ptr<Mesh>& mesh = m_tile_meshes[tile_index];
mesh->Clear();
mesh->AddIndices(m_tile_indices[tile_index]);
mesh->AddVertices(m_tile_vertices[tile_index]);
mesh->AddGeometry(m_tile_vertices[tile_index], m_tile_indices[tile_index]);
mesh->PostProcess();

// create a child entity, add a renderable, and this mesh tile to it
Expand Down

0 comments on commit 2bb9f6e

Please sign in to comment.