BrunoLevy / geogram

a programming library with geometric algorithms
Other
1.87k stars 126 forks source link

mesh_make_atlas performance degrades with larger meshes on iOS build #191

Open Volutionn opened 5 days ago

Volutionn commented 5 days ago

Hi, I'm encountering a performance issue with mesh_make_atlas when using Geogram on iOS. The function works fine for small meshes, but I'm experiencing a severe slowdown with larger meshes. The issue seems to occur when the vertex count exceeds ~16,000 (tested on a simple plane by progressively subdividing it).

Do you have any ideas about what might be causing this performance degradation with larger meshes? Are there any optimizations or settings I should consider to handle larger meshes efficiently?

Additionally, I'm getting this warning: Warning: Could not initialize SuperLU extension when trying to use ABF++, which causes it to fall back to LSCM. Do you know if I should be able to make SuperLU work on iOS?

Thank you!

BrunoLevy commented 3 days ago

Hello,

I do not have much experience with iOS. On which platform are you running iOS ? Is it a phone ? Did you compare the performance with the same code running on a computer ?

Can you share a small program + data so that I can check ?

About SuperLU, you have several ways to make it work:

Volutionn commented 3 days ago

Thank you for your help!

I assumed it was an issue with my custom build for iOS, but I just tried the macOS build (M1) and encountered issues there as well.

Here are the 2 .obj I used for my test: Planes_OBJ.zip

Test 1

For the first test, I used the ./bin/opennl_LSCM example application.

Plane_15K.obj

Loaded 14762 vertices and 29040 facets
Solving ...
Solver time: 1.26
Used iterations: 2667

Plane_16K.obj

Loaded 16248 vertices and 31994 facets
Solving ...
Solver time: 0
Used iterations: 0

Observations:

Both .obj files were successfully generated and appeared correct. However, the logs are inconsistent, which might help pinpoint the underlying issue.

Test 2

For the second test, I used the following custom code to parameterize the same meshes using the mesh_make_atlas function.

#include <geogram/mesh/mesh.h>
#include <geogram/mesh/mesh_io.h>
#include <geogram/parameterization/mesh_atlas_maker.h>
#include <geogram/basic/logger.h>

int main(int argc, char** argv) {
    if (argc != 3) {
        GEO::Logger::err("Test") << "Usage: " << argv[0] << " input_mesh output_mesh" << std::endl;
        return 1;
    }

    GEO::initialize();

    GEO::Mesh mesh;
    if (!GEO::mesh_load(argv[1], mesh)) {
        GEO::Logger::err("Test") << "Failed to load mesh: " << argv[1] << std::endl;
        return 1;
    }

    GEO::mesh_make_atlas(mesh);

    if (!GEO::mesh_save(mesh, argv[2])) {
        GEO::Logger::err("Test") << "Failed to save mesh: " << argv[2] << std::endl;
        return 1;
    }

    GEO::Logger::out("Test") << "Atlas generation completed successfully." << std::endl;
    return 0;
}

Results:

Considering that the issue is also on macOS it's probably not relevant anymore, but I'm running it on an iPhone. The time differences range from under a second at 15K vertices to a few minutes when the number exceeds roughly 16K. From my observations, with 15K vertices the unwrap is correct, but at 16K it seems to never converge and ends up creating an island per face.


Thank you for the info regarding SuperLU ! I'll look into it further and give it another shot to make it work

BrunoLevy commented 1 day ago

Hello, geogram needs some setup and initialization to operate properly, as follows:

#include <geogram/mesh/mesh.h>
#include <geogram/mesh/mesh_io.h>
#include <geogram/parameterization/mesh_atlas_maker.h>
#include <geogram/basic/logger.h>
#include <geogram/basic/command_line.h>
#include <geogram/basic/command_line_args.h>

int main(int argc, char** argv) {
    GEO::initialize();  // this line should be first
    GEO::CmdLine::import_arg_group("standard"); // declare some command line arg
    GEO::CmdLine::import_arg_group("algo");  // with their default values, used by the solver

    std::vector<std::string> files; // the two filenames on the command line

    // set all command arguments, and get the two filenames 
    // (you can change the behavior of some algorithms in geogram
    // using command line argument, use "myprogram -h" to see what can be done.
    if(!GEO::CmdLine::parse(argc, argv, files, "inputfile outputfile")) {  
    exit(-1);
    }

    GEO::Mesh mesh;
    if (!GEO::mesh_load(files[0], mesh)) {
        GEO::Logger::err("Test") << "Failed to load mesh: "
                 << files[0] << std::endl;
        return 1;
    }

    GEO::mesh_make_atlas(mesh);

    if (!GEO::mesh_save(mesh, files[1])) {
        GEO::Logger::err("Test") << "Failed to save mesh: " << files[1]
                 << std::endl;
        return 1;
    }

    GEO::Logger::out("Test")
    << "Atlas generation completed successfully." << std::endl;
    return 0;
}
Volutionn commented 1 day ago

Hello @BrunoLevy and thank you for your time!

I overly simplified my test code and indeed missed some of those initialization steps, but in my iOS implementation, I already had these lines. This explains why my demo code resulted in an assertion error (only when using the 16K plane for some reason), while my iOS implementation was running.

However, I can't figure out why there's this significant change in behavior at 16K vertices. Is this expected behavior?

On my Mac, going from ~15K to ~16K vertices caused the processing time to increase from 0.296s to 0.816s. It also resulted in 4 charts instead of 1, even though it’s just a basic plane with more subdivisions.

What I find also intriguing is the behavior in the example application opennl_LSCM. It goes from 2,667 iterations to presumably no iterations at all (based on the output log), despite the input being a heavier mesh.

Please let me know how I can contribute in any other way that might help debug or understand this behavior. I’d be happy to provide any additional details or share more about my setup if needed!