Skip to content

Commit

Permalink
[mesh] refactoring and initial work with meshoptimizer
Browse files Browse the repository at this point in the history
  • Loading branch information
PanosK92 committed Oct 18, 2024
1 parent 2ca3c1d commit 5fb2d1e
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 97 deletions.
9 changes: 2 additions & 7 deletions editor/Widgets/AssetBrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,16 @@ namespace
"Some models might define lights, they can be imported as well."
);

mesh_import_dialog_checkbox(MeshFlags::OptimizeVertexCache,
mesh_import_dialog_checkbox(MeshFlags::OptimizeVertexCacheAndOverdraw,
"Optimize vertex cache (slower import)",
"Improve the GPU's post-transform cache hit rate, reducing the required vertex shader invocations"
"Optimize GPU's post-transform cache hit rate and reorder vertices for better cache performance, decreasing vertex shader calls and bandwidth use."
);

mesh_import_dialog_checkbox(MeshFlags::OptimizeVertexFetch,
"Optimize vertex fetch (slower import)",
"Reorder vertices and changes indices to improve vertex fetch cache performance, reducing the bandwidth needed to fetch vertices"
);

mesh_import_dialog_checkbox(MeshFlags::OptimizeOverdraw,
"Optimize overdraw (slower import)",
"Minimize overdraw by reordering triangles, aiming to reduce pixel shader invocations"
);

// Ok button
if (ImGuiSp::button_centered_on_line("Ok", 0.5f))
{
Expand Down
116 changes: 61 additions & 55 deletions runtime/Rendering/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,40 @@ using namespace Spartan::Math;

namespace Spartan
{
namespace meshoptimizer
{
void optimize_mesh(vector<RHI_Vertex_PosTexNorTan>& vertices, vector<uint32_t>& indices, const uint32_t flags)
{
if (flags & static_cast<uint32_t>(MeshFlags::OptimizeVertexCacheAndOverdraw))
{
// optimize the order of the indices for vertex cache
meshopt_optimizeVertexCache
(
&indices[0], // destination
&indices[0], // indices
indices.size(), // index count
vertices.size() // vertex count
);

// optimize triangle order to reduce overdraw - needs input from meshopt_optimizeVertexCache
meshopt_optimizeOverdraw(&indices[0], // destination
&indices[0], // indices
indices.size(), // index count
reinterpret_cast<const float*>(&vertices[0]), // vertex positions
vertices.size(), // vertex count
sizeof(RHI_Vertex_PosTexNorTan), // vertex positions stride
1.05f // threshold
);
}

if (flags & static_cast<uint32_t>(MeshFlags::OptimizeVertexFetch))
{
// optimize vertex fetch by reordering vertices based on the new index order
meshopt_optimizeVertexFetch(vertices.data(), indices.data(), indices.size(), vertices.data(), vertices.size(), sizeof(RHI_Vertex_PosTexNorTan));
}
}
}

Mesh::Mesh() : IResource(ResourceType::Mesh)
{
m_flags = GetDefaultFlags();
Expand Down Expand Up @@ -83,10 +117,7 @@ namespace Spartan
file->Read(&m_indices);
file->Read(&m_vertices);

//Optimize();
ComputeAabb();
ComputeNormalizedScale();
CreateGpuBuffers();
PostProcess();
}
// load foreign format
else
Expand Down Expand Up @@ -192,64 +223,16 @@ namespace Spartan
return static_cast<uint32_t>(m_indices.size());
}

void Mesh::ComputeAabb()
{
SP_ASSERT_MSG(m_vertices.size() != 0, "There are no vertices");

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

uint32_t Mesh::GetDefaultFlags()
{
return
static_cast<uint32_t>(MeshFlags::ImportRemoveRedundantData) |
static_cast<uint32_t>(MeshFlags::ImportRemoveRedundantData) |
static_cast<uint32_t>(MeshFlags::ImportNormalizeScale);
//static_cast<uint32_t>(MeshFlags::OptimizeVertexCache) |
//static_cast<uint32_t>(MeshFlags::OptimizeOverdraw) |
//static_cast<uint32_t>(MeshFlags::OptimizeVertexFetch);
}

float Mesh::ComputeNormalizedScale()
{
float scale_offset = m_aabb.GetExtents().Length();
float normalized_scale = 1.0f / scale_offset;

return normalized_scale;
//static_cast<uint32_t>(MeshFlags::OptimizeVertexCacheAndOverdraw) |
//static_cast<uint32_t>(MeshFlags::OptimizeVertexFetch);
}

void Mesh::Optimize()
{
SP_ASSERT(!m_indices.empty());
SP_ASSERT(!m_vertices.empty());

const uint32_t index_count = static_cast<uint32_t>(m_indices.size());
const uint32_t vertex_count = static_cast<uint32_t>(m_vertices.size());
const size_t vertex_size = sizeof(RHI_Vertex_PosTexNorTan);
vector<uint32_t> indices = m_indices;
vector<RHI_Vertex_PosTexNorTan> vertices = m_vertices;

// vertex cache optimization
if (m_flags & static_cast<uint32_t>(MeshFlags::OptimizeVertexCache))
{
meshopt_optimizeVertexCache(&indices[0], &indices[0], index_count, vertex_count);
}

// overdraw optimization
if (m_flags & static_cast<uint32_t>(MeshFlags::OptimizeOverdraw))
{
meshopt_optimizeOverdraw(&indices[0], &indices[0], index_count, &vertices[0].pos[0], vertex_count, vertex_size, 1.05f);
}

// vertex fetch optimization
if (m_flags & static_cast<uint32_t>(MeshFlags::OptimizeVertexFetch))
{
meshopt_optimizeVertexFetch(&vertices[0], &indices[0], index_count, &vertices[0], vertex_count, vertex_size);
}

// store the updated data back to member variables
m_indices = move(indices);
m_vertices = move(vertices);
}
void Mesh::CreateGpuBuffers()
{
m_vertex_buffer = make_shared<RHI_Buffer>(RHI_Buffer_Type::Vertex,
Expand All @@ -269,6 +252,29 @@ namespace Spartan
);
}

void Mesh::PostProcess()
{
// work on the vertices an indices
meshoptimizer::optimize_mesh(m_vertices, m_indices, m_flags);

// compute an axis-aligned bounding box
m_aabb = BoundingBox(m_vertices.data(), static_cast<uint32_t>(m_vertices.size()));

// normalize scale
if (m_flags & static_cast<uint32_t>(MeshFlags::ImportNormalizeScale))
{
if (shared_ptr<Entity> root_entity = m_root_entity.lock())
{
float scale_offset = m_aabb.GetExtents().Length();
float normalized_scale = 1.0f / scale_offset;

root_entity->SetScale(normalized_scale);
}
}

CreateGpuBuffers();
}

void Mesh::SetMaterial(shared_ptr<Material>& material, Entity* entity) const
{
SP_ASSERT(material != nullptr);
Expand Down
19 changes: 9 additions & 10 deletions runtime/Rendering/Mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ namespace Spartan
{
enum class MeshFlags : uint32_t
{
ImportRemoveRedundantData = 1 << 0,
ImportLights = 1 << 1,
ImportCombineMeshes = 1 << 2,
ImportNormalizeScale = 1 << 3,
OptimizeVertexCache = 1 << 4,
OptimizeVertexFetch = 1 << 5,
OptimizeOverdraw = 1 << 6,
ImportRemoveRedundantData = 1 << 0,
ImportLights = 1 << 1,
ImportCombineMeshes = 1 << 2,
ImportNormalizeScale = 1 << 3,
OptimizeVertexCacheAndOverdraw = 1 << 4, // Optimize GPU's post-transform cache hit rate and reorder vertices for better cache performance, decreasing vertex shader calls and bandwidth use.
OptimizeVertexFetch = 1 << 5,
};

enum class MeshType
Expand Down Expand Up @@ -105,11 +104,11 @@ namespace Spartan
MeshType GetType() const { return m_type; }
void SetType(const MeshType type) { m_type = type; }

// misc
// flags
uint32_t GetFlags() const { return m_flags; }
static uint32_t GetDefaultFlags();
float ComputeNormalizedScale();
void Optimize();

void PostProcess();
void SetMaterial(std::shared_ptr<Material>& material, Entity* entity) const;
void AddTexture(std::shared_ptr<Material>& material, MaterialTexture texture_type, const std::string& file_path, bool is_gltf);

Expand Down
4 changes: 1 addition & 3 deletions runtime/Rendering/Renderer_Resources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,7 @@ namespace Spartan
mesh->AddIndices(indices);
mesh->AddVertices(vertices);
mesh->SetType(type);
mesh->ComputeAabb();
mesh->ComputeNormalizedScale();
mesh->CreateGpuBuffers();
mesh->PostProcess();

standard_meshes[static_cast<uint8_t>(type)] = mesh;
};
Expand Down
20 changes: 1 addition & 19 deletions runtime/Resource/Import/ModelImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,25 +487,7 @@ namespace Spartan
this_thread::sleep_for(std::chrono::milliseconds(16));
}

// optimize
if ((mesh->GetFlags() & static_cast<uint32_t>(MeshFlags::OptimizeVertexCache)) ||
(mesh->GetFlags() & static_cast<uint32_t>(MeshFlags::OptimizeVertexFetch)) ||
(mesh->GetFlags() & static_cast<uint32_t>(MeshFlags::OptimizeOverdraw)))
{
mesh->Optimize();
}

// aabb
mesh->ComputeAabb();

// normalize scale
if (mesh->GetFlags() & static_cast<uint32_t>(MeshFlags::ImportNormalizeScale))
{
float normalized_scale = mesh->ComputeNormalizedScale();
mesh->GetRootEntity().lock()->SetScale(normalized_scale);
}

mesh->CreateGpuBuffers();
mesh->PostProcess();
}

// make the root entity active since it's now thread-safe
Expand Down
4 changes: 1 addition & 3 deletions runtime/World/Components/Terrain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,9 +686,7 @@ namespace Spartan
mesh->Clear();
mesh->AddIndices(m_tile_indices[tile_index]);
mesh->AddVertices(m_tile_vertices[tile_index]);
mesh->CreateGpuBuffers();
mesh->ComputeNormalizedScale();
mesh->ComputeAabb();
mesh->PostProcess();

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

0 comments on commit 5fb2d1e

Please sign in to comment.