Skip to content

Commit

Permalink
Merge pull request #751 from zeux/gltf-simp
Browse files Browse the repository at this point in the history
gltfpack: Improve simplification integration
  • Loading branch information
zeux authored Aug 27, 2024
2 parents 6835a38 + 0bf21e8 commit 77aa56c
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 18 deletions.
12 changes: 9 additions & 3 deletions gltf/gltfpack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ static void process(cgltf_data* data, const char* input_path, const char* output
{
Mesh kinds = {};
Mesh loops = {};
debugSimplify(mesh, kinds, loops, settings.simplify_debug, settings.simplify_attributes);
debugSimplify(mesh, kinds, loops, settings.simplify_debug, settings.simplify_error, settings.simplify_attributes);
debug_meshes.push_back(kinds);
debug_meshes.push_back(loops);
}
Expand Down Expand Up @@ -1177,7 +1177,8 @@ Settings defaults()
settings.rot_bits = 12;
settings.scl_bits = 16;
settings.anim_freq = 30;
settings.simplify_threshold = 1.f;
settings.simplify_ratio = 1.f;
settings.simplify_error = 1e-2f;
settings.texture_scale = 1.f;
for (int kind = 0; kind < TextureKind__Count; ++kind)
settings.texture_quality[kind] = 8;
Expand Down Expand Up @@ -1323,7 +1324,11 @@ int main(int argc, char** argv)
}
else if (strcmp(arg, "-si") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.simplify_threshold = clamp(float(atof(argv[++i])), 0.f, 1.f);
settings.simplify_ratio = clamp(float(atof(argv[++i])), 0.f, 1.f);
}
else if (strcmp(arg, "-se") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.simplify_error = clamp(float(atof(argv[++i])), 0.f, 1.f);
}
else if (strcmp(arg, "-sa") == 0)
{
Expand Down Expand Up @@ -1521,6 +1526,7 @@ int main(int argc, char** argv)
fprintf(stderr, "\t... where C is a comma-separated list (no spaces) with valid values color,normal,attrib\n");
fprintf(stderr, "\nSimplification:\n");
fprintf(stderr, "\t-si R: simplify meshes targeting triangle/point count ratio R (default: 1; R should be between 0 and 1)\n");
fprintf(stderr, "\t-se E: limit simplification error to E (default: 0.01 = 1%% deviation; E should be between 0 and 1)\n");
fprintf(stderr, "\t-sa: aggressively simplify to the target ratio disregarding quality\n");
fprintf(stderr, "\t-sv: take vertex attributes into account when simplifying meshes\n");
fprintf(stderr, "\t-slb: lock border vertices during simplification to avoid gaps on connected meshes\n");
Expand Down
5 changes: 3 additions & 2 deletions gltf/gltfpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ struct Settings
bool mesh_merge;
bool mesh_instancing;

float simplify_threshold;
float simplify_ratio;
float simplify_error;
bool simplify_aggressive;
bool simplify_lock_borders;
bool simplify_attributes;
Expand Down Expand Up @@ -306,7 +307,7 @@ cgltf_data* parseGlb(const void* buffer, size_t size, std::vector<Mesh>& meshes,
void processAnimation(Animation& animation, const Settings& settings);
void processMesh(Mesh& mesh, const Settings& settings);

void debugSimplify(const Mesh& mesh, Mesh& kinds, Mesh& loops, float ratio, bool attributes);
void debugSimplify(const Mesh& mesh, Mesh& kinds, Mesh& loops, float ratio, float error, bool attributes);
void debugMeshlets(const Mesh& mesh, Mesh& meshlets, int max_vertices, bool scan);

bool compareMeshTargets(const Mesh& lhs, const Mesh& rhs);
Expand Down
69 changes: 56 additions & 13 deletions gltf/mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,45 @@ static Stream* getStream(Mesh& mesh, cgltf_attribute_type type, int index = 0)
return NULL;
}

static void simplifyMesh(Mesh& mesh, float threshold, bool attributes, bool aggressive, bool lock_borders, bool debug = false)
static void simplifyAttributes(std::vector<float>& attrs, float* attrw, size_t stride, Mesh& mesh)
{
assert(stride >= 6); // normal + color

size_t vertex_count = mesh.streams[0].data.size();

attrs.resize(vertex_count * stride);
float* data = attrs.data();

if (const Stream* attr = getStream(mesh, cgltf_attribute_type_normal))
{
const Attr* a = attr->data.data();

for (size_t i = 0; i < vertex_count; ++i)
{
data[i * stride + 0] = a[i].f[0];
data[i * stride + 1] = a[i].f[1];
data[i * stride + 2] = a[i].f[2];
}

attrw[0] = attrw[1] = attrw[2] = 0.5f;
}

if (const Stream* attr = getStream(mesh, cgltf_attribute_type_color))
{
const Attr* a = attr->data.data();

for (size_t i = 0; i < vertex_count; ++i)
{
data[i * stride + 3] = a[i].f[0] * a[i].f[3];
data[i * stride + 4] = a[i].f[1] * a[i].f[3];
data[i * stride + 5] = a[i].f[2] * a[i].f[3];
}

attrw[3] = attrw[4] = attrw[5] = 1.0f;
}
}

static void simplifyMesh(Mesh& mesh, float threshold, float error, bool attributes, bool aggressive, bool lock_borders, bool debug = false)
{
enum
{
Expand All @@ -546,24 +584,29 @@ static void simplifyMesh(Mesh& mesh, float threshold, bool attributes, bool aggr
size_t vertex_count = mesh.streams[0].data.size();

size_t target_index_count = size_t(double(mesh.indices.size() / 3) * threshold) * 3;
float target_error = 1e-2f;
float target_error = error;
float target_error_aggressive = 1e-1f;
unsigned int options = 0;
if (lock_borders)
options |= meshopt_SimplifyLockBorder;
if (debug)
options |= meshopt_SimplifyInternalDebug;

const Stream* attr = getStream(mesh, cgltf_attribute_type_color);
attr = attr ? attr : getStream(mesh, cgltf_attribute_type_normal);
std::vector<unsigned int> indices(mesh.indices.size());

const float attrw[3] = {0.5f, 0.5f, 0.5f};
if (attributes)
{
float attrw[6] = {};
std::vector<float> attrs;
simplifyAttributes(attrs, attrw, sizeof(attrw) / sizeof(attrw[0]), mesh);

std::vector<unsigned int> indices(mesh.indices.size());
if (attributes && attr)
indices.resize(meshopt_simplifyWithAttributes(&indices[0], &mesh.indices[0], mesh.indices.size(), positions->data[0].f, vertex_count, sizeof(Attr), attr->data[0].f, sizeof(Attr), attrw, 3, NULL, target_index_count, target_error, options));
indices.resize(meshopt_simplifyWithAttributes(&indices[0], &mesh.indices[0], mesh.indices.size(), positions->data[0].f, vertex_count, sizeof(Attr), attrs.data(), sizeof(attrw), attrw, sizeof(attrw) / sizeof(attrw[0]), NULL, target_index_count, target_error, options));
}
else
{
indices.resize(meshopt_simplify(&indices[0], &mesh.indices[0], mesh.indices.size(), positions->data[0].f, vertex_count, sizeof(Attr), target_index_count, target_error, options));
}

mesh.indices.swap(indices);

// Note: if the simplifier got stuck, we can try to reindex without normals/tangents and retry
Expand Down Expand Up @@ -771,7 +814,7 @@ void processMesh(Mesh& mesh, const Settings& settings)
{
case cgltf_primitive_type_points:
assert(mesh.indices.empty());
simplifyPointMesh(mesh, settings.simplify_threshold);
simplifyPointMesh(mesh, settings.simplify_ratio);
sortPointMesh(mesh);
break;

Expand All @@ -782,8 +825,8 @@ void processMesh(Mesh& mesh, const Settings& settings)
filterBones(mesh);
reindexMesh(mesh);
filterTriangles(mesh);
if (settings.simplify_threshold < 1)
simplifyMesh(mesh, settings.simplify_threshold, settings.simplify_attributes, settings.simplify_aggressive, settings.simplify_lock_borders);
if (settings.simplify_ratio < 1)
simplifyMesh(mesh, settings.simplify_ratio, settings.simplify_error, settings.simplify_attributes, settings.simplify_aggressive, settings.simplify_lock_borders);
optimizeMesh(mesh, settings.compressmore);
break;

Expand All @@ -793,7 +836,7 @@ void processMesh(Mesh& mesh, const Settings& settings)
}

#ifndef NDEBUG
void debugSimplify(const Mesh& source, Mesh& kinds, Mesh& loops, float ratio, bool attributes)
void debugSimplify(const Mesh& source, Mesh& kinds, Mesh& loops, float ratio, float error, bool attributes)
{
Mesh mesh = source;
assert(mesh.type == cgltf_primitive_type_triangles);
Expand All @@ -806,7 +849,7 @@ void debugSimplify(const Mesh& source, Mesh& kinds, Mesh& loops, float ratio, bo

size_t vertex_count = mesh.streams[0].data.size();

simplifyMesh(mesh, ratio, attributes, /* aggressive= */ false, /* lock_borders= */ false, /* debug= */ true);
simplifyMesh(mesh, ratio, error, attributes, /* aggressive= */ false, /* lock_borders= */ false, /* debug= */ true);

// color palette for display
static const Attr kPalette[] = {
Expand Down

0 comments on commit 77aa56c

Please sign in to comment.