Add mesh index buffer optimization based on meshoptimizer library
Work similar to existing impl but yields better results with even less overdraw.
This commit is contained in:
@@ -10,11 +10,12 @@
|
||||
#include "Engine/Core/Collections/BitArray.h"
|
||||
#include "Engine/Tools/ModelTool/ModelTool.h"
|
||||
#include "Engine/Tools/ModelTool/VertexTriangleAdjacency.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "Engine/Platform/MessageBox.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include <ThirdParty/meshoptimizer/meshoptimizer.h>
|
||||
#define USE_MIKKTSPACE 1
|
||||
#include "ThirdParty/MikkTSpace/mikktspace.h"
|
||||
#include <ThirdParty/MikkTSpace/mikktspace.h>
|
||||
#if USE_ASSIMP
|
||||
#define USE_SPATIAL_SORT 1
|
||||
#define ASSIMP_BUILD_NO_EXPORT
|
||||
@@ -25,6 +26,26 @@
|
||||
#endif
|
||||
#include <stack>
|
||||
|
||||
bool InitedMeshOpt = false;
|
||||
|
||||
void* MeshOptAllocate(size_t size)
|
||||
{
|
||||
return Allocator::Allocate(size);
|
||||
}
|
||||
|
||||
void MeshOptDeallocate(void* ptr)
|
||||
{
|
||||
Allocator::Free(ptr);
|
||||
}
|
||||
|
||||
void InitMeshOpt()
|
||||
{
|
||||
if (InitedMeshOpt)
|
||||
return;
|
||||
InitedMeshOpt = true;
|
||||
meshopt_setAllocator(MeshOptAllocate, MeshOptDeallocate);
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
// Import UVAtlas library
|
||||
@@ -934,6 +955,23 @@ void MeshData::ImproveCacheLocality()
|
||||
LOG(Info, "Generated {3} for mesh in {0}s ({1} vertices, {2} indices)", time, vertexCount, indexCount, TEXT("optimized indices"));
|
||||
}
|
||||
|
||||
void MeshData::Optimize()
|
||||
{
|
||||
if (Indices.IsEmpty() || Positions.IsEmpty())
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
InitMeshOpt();
|
||||
|
||||
// Vertex cache optimization (https://meshoptimizer.org/#vertex-cache-optimization)
|
||||
Array<uint32> tmpIndices;
|
||||
tmpIndices.Resize(Indices.Count());
|
||||
meshopt_optimizeVertexCache(tmpIndices.Get(), Indices.Get(), Indices.Count(), Positions.Count());
|
||||
|
||||
// Overdraw optimization (https://meshoptimizer.org/#overdraw-optimization)
|
||||
const float overdrawThreshold = 1.05f;
|
||||
meshopt_optimizeOverdraw(Indices.Get(), tmpIndices.Get(), Indices.Count(), (const float*)Positions.Get(), Positions.Count(), sizeof(Float3), overdrawThreshold);
|
||||
}
|
||||
|
||||
float MeshData::CalculateTrianglesArea() const
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
@@ -228,9 +228,16 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// Reorders all triangles for improved vertex cache locality. It tries to arrange all triangles to fans and to render triangles which share vertices directly one after the other.
|
||||
/// [Deprecated in v1.13]
|
||||
/// </summary>
|
||||
DEPRECATED("Use Optimize instead as it does more advanced optimizations on index buffer.")
|
||||
void ImproveCacheLocality();
|
||||
|
||||
/// <summary>
|
||||
/// Optimizes mesh vertex and index buffers for runtime rendering. Uses 'meshoptimizer' library.
|
||||
/// </summary>
|
||||
void Optimize();
|
||||
|
||||
/// <summary>
|
||||
/// Sums the area of all triangles in the mesh.
|
||||
/// </summary>
|
||||
|
||||
@@ -437,6 +437,12 @@ bool ProcessMesh(ModelData& result, AssimpImporterData& data, const aiMesh* aMes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.Options.OptimizeMeshes)
|
||||
{
|
||||
mesh.Optimize();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -730,7 +736,7 @@ bool ModelTool::ImportDataAssimp(const String& path, ModelData& data, Options& o
|
||||
if (options.ReverseWindingOrder)
|
||||
flags &= ~aiProcess_FlipWindingOrder;
|
||||
if (options.OptimizeMeshes)
|
||||
flags |= aiProcess_OptimizeMeshes | aiProcess_SplitLargeMeshes | aiProcess_ImproveCacheLocality;
|
||||
flags |= aiProcess_OptimizeMeshes;
|
||||
if (options.MergeMeshes)
|
||||
flags |= aiProcess_RemoveRedundantMaterials;
|
||||
}
|
||||
|
||||
@@ -988,7 +988,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
||||
|
||||
if (data.Options.OptimizeMeshes)
|
||||
{
|
||||
mesh.ImproveCacheLocality();
|
||||
mesh.Optimize();
|
||||
}
|
||||
|
||||
// Apply FBX Mesh geometry transformation
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
#include "Engine/Animations/Graph/AnimGraph.h"
|
||||
#include <ThirdParty/meshoptimizer/meshoptimizer.h>
|
||||
extern void InitMeshOpt();
|
||||
#endif
|
||||
|
||||
ModelSDFHeader::ModelSDFHeader(const ModelBase::SDFData& sdf, const GPUTextureDescription& desc)
|
||||
@@ -940,16 +941,6 @@ void OptimizeCurve(LinearCurve<T>& curve)
|
||||
}
|
||||
}
|
||||
|
||||
void* MeshOptAllocate(size_t size)
|
||||
{
|
||||
return Allocator::Allocate(size);
|
||||
}
|
||||
|
||||
void MeshOptDeallocate(void* ptr)
|
||||
{
|
||||
Allocator::Free(ptr);
|
||||
}
|
||||
|
||||
void TrySetupMaterialParameter(MaterialInstance* instance, Span<const Char*> paramNames, const Variant& value, MaterialParameterType type)
|
||||
{
|
||||
for (const Char* name : paramNames)
|
||||
@@ -1954,8 +1945,8 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
||||
// Automatic LOD generation
|
||||
if (options.GenerateLODs && options.LODCount > 1 && data.LODs.HasItems() && options.TriangleReduction < 1.0f - ZeroTolerance)
|
||||
{
|
||||
InitMeshOpt();
|
||||
auto lodStartTime = DateTime::NowUTC();
|
||||
meshopt_setAllocator(MeshOptAllocate, MeshOptDeallocate);
|
||||
float triangleReduction = Math::Saturate(options.TriangleReduction);
|
||||
int32 lodCount = Math::Max(options.LODCount, data.LODs.Count());
|
||||
int32 baseLOD = Math::Clamp(options.BaseLOD, 0, lodCount - 1);
|
||||
|
||||
Reference in New Issue
Block a user