More Boolean Solvers #120182

Open
opened 2024-04-02 18:50:27 +02:00 by Howard Trickey · 19 comments
Member

Why More Boolean Solvers?

The Mesh Boolean node in Blender 4.1 and earlier uses only the Exact Boolean geometry solver, unlike the modifier which allowed a choice between the native float boolean solver and the Exact Boolean solver that was put into Blenlib, using the "Mesh Arrangements" paper for the algorithm.

Users have long asked for the float solver to be included as an option in the Mesh Boolean node. And in general, complained about the speed of the Exact Boolean solver. For example, this bug: Extremely Long time delay using geometry nodes with simple mesh boolean node 37706ms #98020.

Some recent papers and open source projects have offered hope of even better and even faster solvers. Having a super-fast solver (even faster than the current float solver) is desirable especially for these use cases:

  • sculpting
  • high-detail hard-ops modeling
  • interactive tools that would like to use boolean ("extrude manifold", "bevel-after-boolean")

Which Solvers to Add?

Native Float Solver

The obvious first one to add is the current native float solver.

Pros

  • Already works, though needed some adaptation to work in geometry node context
  • Decently fast on medium size models
  • Users of the modifier are familiar with how to use it to avoid problems
  • Doesn't put any limitations on the topology of the inputs
  • Doesn't touch the parts of the mesh that aren't part of intersection (so less chance for messing up attributes on those parts of the meshes)

And in fact, the main branch of the 4.2 alpha already has the native float solver added. #119294.

Cons

  • Doesn't work with coplanar faces or intersections that hit exactly on vertices or edges of the other meshes involved
  • The raycast method for determining insideness/outsideness isn't reliable, especially on high-density meshes
  • Not a lot of attention paid to parallelizing it (I think BVH tree building, for fast intersection testing, is parallelized)
  • Needs a round trip through BMesh, which gathers more topology information than is strictly necessary and in any case isn't well optimized for modern computer memory

Manifold Float Solver

We recently became aware of the manifold open source boolean solver. This is a float solver too, but it uses a technique of symbolic perturbation to make it guaranteed to product a manifold output when given a manifold input. Here "manifold" means that the input edges are all used in exactly two faces and the those faces are joined with consistently facing normals. The upshot of this is that it has some restrictions but is much more robust than our current float solver, and is probably faster to boot.

Pros

  • Robust, so less likely to fail in strange ways compared to the native float solver
  • Highly parallelized so will take full advantage of modern machines with many cores
  • The library has means for tracking which original elements the output elements come from, making attribute propagation reasonably straightforward
  • The developer is active and engages with us in a very timely fashion

Cons

  • The manifold requirement on inputs means that users cannot use this with just any Blender Mesh. Though if one starts with Mesh primitives and is a bit careful, it is not hard to maintain the manifold property. And some non-manifold meshes can easily be faked into being manifold for the purpose of doing the boolean. For example, the library has routines for booleaning with a plane that are handled this way.
  • The library requires triangulated input, unlike the native float solver. So this adds a slow-down step, and also adds the need to "untriangulate" the result, which also will slow things down. The current exact solver does this too, however, and has code that can be copied to do the untriangulation.
  • Several new dependencies are needed in Blender, mostly header-only libraries, but Clipper2 is an actual library
  • Using an external library instead of writing the code ourselves has several downsides: (1) we have to rely on upstream to fix bugs (unless we want to get into a patch-it-ourselves game); (2) we can't really adapt the code to our specific use case, which may mean, for instance, extra copying of data into nearly-identical forms, which wastes time and memory. (3) less intimate familiarity with how the library works may mean that bugs are harder to diagnose and fix.

Ember Solver

Another task, Exact Boolean V2 #114476, describes a new native exact solver that I have been working on. It is based on using fixed-length multiprecision integer arithmetic. The authors of the paper that it is based on claim that their implementation is faster than float solvers they have measured against (not including Manifold, which post-dates the paper). It had been my intention to use this to replace the old Exact Solver, and maybe avoid the need for any float solver, but at this point I am a lot less clear that that can happen. It has taken a lot longer than i expected to get it working (and it is still quite a way from really working), so when the Manifold library came to my attention, I switched priorities to get that solver in first.

Pros

  • Gives exact results, so extremely robust.
  • Has a promising approach of subdividing the input by successive space-partitioning planes, into "subproblems". This has three great speed advantages: (1) naturally parallelizable; (2) one can extensively use "short cut" evaluation to find cases where large parts of the input meshes don't need any processing; (3) one can have a local reference point in each subproblem, with calculated insideness/outsideness for each boolean argument -- this makes applying the boolean operation to a subproblem into a local problem that does't have to examine the whole input meshes.
  • We would know the code very well and can optimize it specifically in the Blender context

Cons

  • Preliminary tests of speed have not been all that encouraging. Probably lots of optimization at the base arithmetic level are still needed
  • it turns out to a lot more complicated than anticipated to take the results of the paper's algorithm -- a disconnected set of faces -- and turn them into a connected Mesh. At least, to do it efficiently.
  • The paper's algorithm produces T-junctions all over the place, which Blender users would not like. There might be ways to redo the intersection faces in a nicer way, but that's more algorithm development, and goes against the paper's desire to keep within a certain precision budget (which in turn determines how big the fixed-integer-length arithmetic has to be).
  • The paper's algorithm produces long skinny faces (almost zero-area) sometimes, which would likely have to be removed by more post-processing (a slow-down step). This is also true of the Manifold algorithm, but that library handles the postprocessing itself.
  • There are restrictions on the input topology, similar to those of the current (Mesh Arrangements) Exact Solver.
### Why More Boolean Solvers? The Mesh Boolean node in Blender 4.1 and earlier uses only the Exact Boolean geometry solver, unlike the modifier which allowed a choice between the native float boolean solver and the Exact Boolean solver that was put into Blenlib, using the "Mesh Arrangements" paper for the algorithm. Users have long asked for the float solver to be included as an option in the Mesh Boolean node. And in general, complained about the speed of the Exact Boolean solver. For example, this bug: [Extremely Long time delay using geometry nodes with simple mesh boolean node 37706ms #98020](https://projects.blender.org/blender/blender/issues/98020). Some recent papers and open source projects have offered hope of even better and even faster solvers. Having a super-fast solver (even faster than the current float solver) is desirable especially for these use cases: - sculpting - high-detail hard-ops modeling - interactive tools that would like to use boolean ("extrude manifold", "bevel-after-boolean") ### Which Solvers to Add? #### Native Float Solver The obvious first one to add is the **current native float solver.** _Pros_ - Already works, though needed some adaptation to work in geometry node context - Decently fast on medium size models - Users of the modifier are familiar with how to use it to avoid problems - Doesn't put any limitations on the topology of the inputs - Doesn't touch the parts of the mesh that aren't part of intersection (so less chance for messing up attributes on those parts of the meshes) And in fact, the main branch of the 4.2 alpha already has the native float solver added. [#119294](https://projects.blender.org/blender/blender/pulls/119294). _Cons_ - Doesn't work with coplanar faces or intersections that hit exactly on vertices or edges of the other meshes involved - The raycast method for determining insideness/outsideness isn't reliable, especially on high-density meshes - Not a lot of attention paid to parallelizing it (I think BVH tree building, for fast intersection testing, is parallelized) - Needs a round trip through BMesh, which gathers more topology information than is strictly necessary and in any case isn't well optimized for modern computer memory #### Manifold Float Solver We recently became aware of the [manifold](https://github.com/elalish/manifold) open source boolean solver. This is a float solver too, but it uses a technique of symbolic perturbation to make it guaranteed to product a manifold output when given a manifold input. Here "manifold" means that the input edges are all used in exactly two faces and the those faces are joined with consistently facing normals. The upshot of this is that it has some restrictions but is much more robust than our current float solver, and is probably faster to boot. _Pros_ - Robust, so less likely to fail in strange ways compared to the native float solver - Highly parallelized so will take full advantage of modern machines with many cores - The library has means for tracking which original elements the output elements come from, making attribute propagation reasonably straightforward - The developer is active and engages with us in a very timely fashion _Cons_ - The manifold requirement on inputs means that users cannot use this with just any Blender Mesh. Though if one starts with Mesh primitives and is a bit careful, it is not hard to maintain the manifold property. And some non-manifold meshes can easily be faked into being manifold for the purpose of doing the boolean. For example, the library has routines for booleaning with a plane that are handled this way. - The library requires triangulated input, unlike the native float solver. So this adds a slow-down step, and also adds the need to "untriangulate" the result, which also will slow things down. The current exact solver does this too, however, and has code that can be copied to do the untriangulation. - Several new dependencies are needed in Blender, mostly header-only libraries, but Clipper2 is an actual library - Using an external library instead of writing the code ourselves has several downsides: (1) we have to rely on upstream to fix bugs (unless we want to get into a patch-it-ourselves game); (2) we can't really adapt the code to our specific use case, which may mean, for instance, extra copying of data into nearly-identical forms, which wastes time and memory. (3) less intimate familiarity with how the library works may mean that bugs are harder to diagnose and fix. #### Ember Solver #### Another task, [Exact Boolean V2 #114476](https://projects.blender.org/blender/blender/issues/114476), describes a new native exact solver that I have been working on. It is based on using fixed-length multiprecision integer arithmetic. The authors of the paper that it is based on claim that their implementation is faster than float solvers they have measured against (not including Manifold, which post-dates the paper). It had been my intention to use this to replace the old Exact Solver, and maybe avoid the need for any float solver, but at this point I am a lot less clear that that can happen. It has taken a lot longer than i expected to get it working (and it is still quite a way from really working), so when the Manifold library came to my attention, I switched priorities to get that solver in first. _Pros_ - Gives exact results, so extremely robust. - Has a promising approach of subdividing the input by successive space-partitioning planes, into "subproblems". This has three great speed advantages: (1) naturally parallelizable; (2) one can extensively use "short cut" evaluation to find cases where large parts of the input meshes don't need any processing; (3) one can have a local reference point in each subproblem, with calculated insideness/outsideness for each boolean argument -- this makes applying the boolean operation to a subproblem into a local problem that does't have to examine the whole input meshes. - We would know the code very well and can optimize it specifically in the Blender context _Cons_ - Preliminary tests of speed have not been all that encouraging. Probably lots of optimization at the base arithmetic level are still needed - it turns out to a lot more complicated than anticipated to take the results of the paper's algorithm -- a disconnected set of faces -- and turn them into a connected Mesh. At least, to do it efficiently. - The paper's algorithm produces T-junctions all over the place, which Blender users would not like. There might be ways to redo the intersection faces in a nicer way, but that's more algorithm development, and goes against the paper's desire to keep within a certain precision budget (which in turn determines how big the fixed-integer-length arithmetic has to be). - The paper's algorithm produces long skinny faces (almost zero-area) sometimes, which would likely have to be removed by more post-processing (a slow-down step). This is also true of the Manifold algorithm, but that library handles the postprocessing itself. - There are restrictions on the input topology, similar to those of the current (Mesh Arrangements) Exact Solver.
Howard Trickey added this to the 4.2 LTS milestone 2024-04-02 18:50:27 +02:00
Howard Trickey added the
Interest
Modeling
Interest
Geometry Nodes
Type
Design
labels 2024-04-02 18:50:28 +02:00
Howard Trickey self-assigned this 2024-04-02 18:50:28 +02:00
Contributor

I did some very rough timings on the existing float solver to attempt to identify areas of potential optimization inside the existing BM_mesh_intersect function. For a mesh with 491,522 vertices and 524,288 faces, doing a Trim Lasso operation on the mesh in a developer build took 16.3s inside the BM_mesh_intersect function.

The areas of largest runtime are as follows:

Performing the Tri-Tri Intersections

    for (i = 0; i < tree_overlap_tot; i++) {
      bm_isect_tri_tri(&s,
                       overlap[i].indexA,
                       overlap[i].indexB,
                       looptris[overlap[i].indexA],
                       looptris[overlap[i].indexB],
                       isect_tri_tri_no_shared);
    }

(tree_overlap_tot = 3570558) taking 5.2s (31.9% of runtime)

Iteratively Removing Faces

      for (i = 0; i < tot; i++) {
        if (ftable[i]->mat_nr == -1) {
          BM_face_kill_loose(bm, ftable[i]);
        }
      }

(Removing 139446 / 525801 faces) taking 10.1s (61.9% of runtime)

Of the two areas, parallelizing the former seems less intrusive but still requires minor adjustments to some internal structs to support splitting this work across a number of threads.

I did some very rough timings on the existing float solver to attempt to identify areas of potential optimization inside the existing `BM_mesh_intersect` function. For a mesh with **491,522** vertices and **524,288** faces, doing a *Trim Lasso* operation on the mesh in a developer build took **16.3s** inside the `BM_mesh_intersect` function. The areas of largest runtime are as follows: ### Performing the Tri-Tri Intersections ``` for (i = 0; i < tree_overlap_tot; i++) { bm_isect_tri_tri(&s, overlap[i].indexA, overlap[i].indexB, looptris[overlap[i].indexA], looptris[overlap[i].indexB], isect_tri_tri_no_shared); } ``` (tree_overlap_tot = 3570558) taking 5.2s (31.9% of runtime) ### Iteratively Removing Faces ``` for (i = 0; i < tot; i++) { if (ftable[i]->mat_nr == -1) { BM_face_kill_loose(bm, ftable[i]); } } ``` (Removing 139446 / 525801 faces) taking 10.1s (61.9% of runtime) Of the two areas, parallelizing the former seems less intrusive but still requires minor adjustments to some internal `struct`s to support splitting this work across a number of threads.

@ideasman42 @JacquesLucke hey, any thoughts here?

@ideasman42 @JacquesLucke hey, any thoughts here?

FYI some context from @LazyDodo re adding manifold lib to our dependencies:

[... Adding the] manifold (Apache 2) lib, this will bring in the following additional deps

  • GLM (MIT)
  • thrust (Apache2/BSD, concern: same platform support as cuda, we could be on or own for mac support there)
  • Clipper2 (Boost Software License)
  • QuickHull ("100% Public Domain.", yeah... I'm not sure how this jives with our GPL, someone at compliance needs to sign off on this, is that you these days @ThomasDinges ?)

Given the large number of deps it has, I don't think it living in /extern is the way to go
[...]

FYI [some context](https://blender.chat/channel/core-module?msg=K6Bzw9G5PR5inRoMT) from @LazyDodo re adding `manifold` lib to our dependencies: > [... Adding the] [manifold](https://github.com/elalish/manifold) (Apache 2) lib, this will bring in the following additional deps > > - [GLM](https://github.com/g-truc/glm/) (MIT) > - [thrust](https://github.com/NVIDIA/thrust) (Apache2/BSD, concern: same platform support as cuda, we could be on or own for mac support there) > - [Clipper2](https://github.com/AngusJohnson/Clipper2) (Boost Software License) > - [QuickHull](https://github.com/akuukka/quickhull) ("100% Public Domain.", yeah... I'm not sure how this jives with our GPL, someone at compliance needs to sign off on this, is that you these days @ThomasDinges ?) > > Given the large number of deps it has, I don't think it living in /extern is the way to go [...]
Member

I think it makes sense to pursue using the manifold library. Ideally the performance will be very good and we will be satisfied there. And ideally it could replace the existing exact solver. Adding library and its dependencies makes sense then. If it doesn't work out, they can always be removed again anyway.

For boolean performance in general, I think it would make sense to make the topology cleanup and de-triangulation optional. For many procedural workflows this shouldn't be necessary, and I could foresee it taking a significant portion of the overall runtime.

I think it makes sense to pursue using the manifold library. Ideally the performance will be very good and we will be satisfied there. And ideally it could replace the existing exact solver. Adding library and its dependencies makes sense then. If it doesn't work out, they can always be removed again anyway. For boolean performance in general, I think it would make sense to make the topology cleanup and de-triangulation optional. For many procedural workflows this shouldn't be necessary, and I could foresee it taking a significant portion of the overall runtime.
Member

I think it would be good to talk a bit more about the different use-cases of mesh boolean solvers. Then we can check which solvers work well for certain types of work. This approach also makes it easier to tell users which solvers they should use.

Currently, I can think of these main use-cases, but I might be missing some stuff:

  1. Fixing models: The user starts out with a fairly broken model that might not be a closed volume and wants to make it ready for e.g. 3D printing. An boolean algorithm for this case should be quite forgiving when the input mesh is bad. However, it's also fine if the algorithm isn't super fast, because it generally only has to be done once for a mesh.
  2. Mesh modelling where the output topology matters. This kind of algorithm could potentially make more assumptions about the input meshes, but it sometimes has to trade-off performance for a better output topology that users can continue to work on.
  3. Mesh modelling where the output topology does not matter. I think in many procedural setups, the exact output topology does not matter too much and users don't really expect a clean topology. Here one can also make more assumptions about the input meshes. This should be suitable for high performance CSG modelling. As such it should probably also be able to deal with coplanar faces.

Am I missing something important? Which solver would you use for each of these tasks?

I think it would be good to talk a bit more about the different use-cases of mesh boolean solvers. Then we can check which solvers work well for certain types of work. This approach also makes it easier to tell users which solvers they should use. Currently, I can think of these main use-cases, but I might be missing some stuff: 1. Fixing models: The user starts out with a fairly broken model that might not be a closed volume and wants to make it ready for e.g. 3D printing. An boolean algorithm for this case should be quite forgiving when the input mesh is bad. However, it's also fine if the algorithm isn't super fast, because it generally only has to be done once for a mesh. 2. Mesh modelling where the output topology matters. This kind of algorithm could potentially make more assumptions about the input meshes, but it sometimes has to trade-off performance for a better output topology that users can continue to work on. 3. Mesh modelling where the output topology does not matter. I think in many procedural setups, the exact output topology does not matter too much and users don't really expect a clean topology. Here one can also make more assumptions about the input meshes. This should be suitable for high performance [CSG modelling](https://en.wikipedia.org/wiki/Constructive_solid_geometry). As such it should probably also be able to deal with coplanar faces. Am I missing something important? Which solver would you use for each of these tasks?
Author
Member

I don't think any of our current or proposed Boolean solvers are good for your use case 1 (fixing broken models). But there is an aspect to the question: if you have a broken model, which solver is more likely to give what people think a boolean operation should do on those models. This usually means falling back on ray tracing to discover insideness-outsideness, but there is a bit of an art to doing that. I would say it is a tossup right now whether the current float solver or the current exact solver is better here.

For use case 2, either the current exact solver or the manifold solver would be best IMO. The float solver sometimes works for this case but is unreliable -- sometimes the output will be utterly wrong. But I will note that within case 2 there are still many users who are very unsatisfied with the speed of the current exact solver.

Case 3 seems to be mostly about sculpting, but I case could also apply to cases where the resulting geometry is just rendered as is, using some kind of texturing that doesn't care about topololgy.

There is also the question of: is attribute propagation from input to output important? LIke untriangulating, that also slows things down and may not be needed by some users.

Should I start a user feedback thread on devtalk to ask about their requirements/desiderata for boolean solvers?

I don't think any of our current or proposed Boolean solvers are good for your use case 1 (fixing broken models). But there is an aspect to the question: if you have a broken model, which solver is more likely to give what people _think_ a boolean operation should do on those models. This usually means falling back on ray tracing to discover insideness-outsideness, but there is a bit of an art to doing that. I would say it is a tossup right now whether the current float solver or the current exact solver is better here. For use case 2, either the current exact solver or the manifold solver would be best IMO. The float solver sometimes works for this case but is unreliable -- sometimes the output will be utterly wrong. But I will note that within case 2 there are still many users who are very unsatisfied with the speed of the current exact solver. Case 3 seems to be mostly about sculpting, but I case could also apply to cases where the resulting geometry is just rendered as is, using some kind of texturing that doesn't care about topololgy. There is also the question of: is attribute propagation from input to output important? LIke untriangulating, that also slows things down and may not be needed by some users. Should I start a user feedback thread on devtalk to ask about their requirements/desiderata for boolean solvers?
Member

Thanks.

There is also the question of: is attribute propagation from input to output important?

It definitely is in general, i.e. the code should support it. Currently, one can generally assume that nodes in geometry nodes propagate all attributes and I think the same will be true for boolean operations. However, we also give users tools to avoid propagating attributes: named attributes can be removed before the boolean node and anonymous attributes are detected whether they need to be propagated automatically.

I think a general "don't propagate attributes" checkbox in the boolean node is way to inflexible. What could help is to provide additional information in the timing overlay. We could explicitly show how long the attribute propagation takes so that it is more obvious to the user that it might make sense to optimize this part.

Should I start a user feedback thread on devtalk to ask about their requirements/desiderata for boolean solvers?

Might be useful to get a better understanding of what trade-offs we can make to get better performance. I'd assume that generally performance gets worse in the following cases:

  • The output should have good topology.
  • Bad input meshes should be handled gracefully.
  • Robust handling of coplanar faces.

It would also be useful to know if people often only use one boolean operation or whether they usually use multiple chained operations. For the latter case we should figure out a way to keep the mesh data in a boolean solver friendly data-structure for longer instead of converting back and forth for each operation.


Overall, I think the Manifold library seems to be a good fit for procedural workflows, probably better than the other solvers we have already. Are there functional benefits of using Ember over Manifold? Does Manifold handle coplanar faces as well as Ember? How does Ember decide what's inside when the input is not a closed volume?

Thanks. > There is also the question of: is attribute propagation from input to output important? It definitely is in general, i.e. the code should support it. Currently, one can generally assume that nodes in geometry nodes propagate all attributes and I think the same will be true for boolean operations. However, we also give users tools to avoid propagating attributes: named attributes can be removed before the boolean node and anonymous attributes are detected whether they need to be propagated automatically. I think a general "don't propagate attributes" checkbox in the boolean node is way to inflexible. What could help is to provide additional information in the timing overlay. We could explicitly show how long the attribute propagation takes so that it is more obvious to the user that it might make sense to optimize this part. > Should I start a user feedback thread on devtalk to ask about their requirements/desiderata for boolean solvers? Might be useful to get a better understanding of what trade-offs we can make to get better performance. I'd assume that generally performance gets worse in the following cases: * The output should have good topology. * Bad input meshes should be handled gracefully. * Robust handling of coplanar faces. It would also be useful to know if people often only use one boolean operation or whether they usually use multiple chained operations. For the latter case we should figure out a way to keep the mesh data in a boolean solver friendly data-structure for longer instead of converting back and forth for each operation. ------ Overall, I think the Manifold library seems to be a good fit for procedural workflows, probably better than the other solvers we have already. Are there functional benefits of using Ember over Manifold? Does Manifold handle coplanar faces as well as Ember? How does Ember decide what's inside when the input is not a closed volume?
Contributor

Just wanted to mention that in my professional work I deal with insane amount of boolean operations. I prepare stop-motion puppet replacement parts for 3D printing and sometimes do multiple boolean operators on 50-100+ objects in a day. I also use booleans for sculpting. I would be happy to test in my workflow whatever library needs to be tested

Just wanted to mention that in my professional work I deal with insane amount of boolean operations. I prepare stop-motion puppet replacement parts for 3D printing and sometimes do multiple boolean operators on 50-100+ objects in a day. I also use booleans for sculpting. I would be happy to test in my workflow whatever library needs to be tested
Author
Member

I'll answer Jacques' questions later, but Nika: would you like to explain your particular requirements on boolean here? Do you care about the output topology (do you care if they are all triangles?). Do you care about reliability in cases where one edge of one part exactly intersects an edge or vertex of another part? Do you care about handling coplanar intersections properly? How large are your models typically? Do your booleans typically have only two operands or many operands? Do you chain many booleans together? How fast, ideally, do you need boolean to run?

I'll answer Jacques' questions later, but Nika: would you like to explain your particular requirements on boolean here? Do you care about the output topology (do you care if they are all triangles?). Do you care about reliability in cases where one edge of one part exactly intersects an edge or vertex of another part? Do you care about handling coplanar intersections properly? How large are your models typically? Do your booleans typically have only two operands or many operands? Do you chain many booleans together? How fast, ideally, do you need boolean to run?
Contributor

Do you care about the output topology (do you care if they are all triangles?)

I don't think so. Nowadays 3D printers can print almost any topology. Sometimes we do get some weirdness, but it's all fixable. Sometimes I even run Decimate on models but they still print fine. What is hard requirement for us is that silhouette of the object isn't changed and object is watertight. Judging by the name only Manifold might help here.

Do you care about reliability in cases where one edge of one part exactly intersects an edge or vertex of another part? Do you care about handling coplanar intersections properly?

I'm not sure I fully understand that, but because my models are typically 300,000+ polygons, and there are lot of intersections (also because they're tiny), so in many cases where I run booleans there are lot of vertices and edges that are intersecting or very close to each other. Sometimes I use "Merge by Distance" to reduce the number, and it can take out even 30,000k vertices that are close to each other. It's important for me that boolean can handle that and doesn't need merge beforehand. For example, I had mustache and head as separate objects, and before printing I was using union boolean to combine them, and in at least 2/3 of cases I had to run "Merge by Distance" on head object because otherwise boolean would screw up.

How large are your models typically?

Our models are 30-50 mm, but sometimes we don't follow real-life scale in Blender, because it's harder to work on smaller sizes and we scale them up to meters, and then rescale them in 3D printing software.

Do your booleans typically have only two operands or many operands? Do you chain many booleans together?

I use Bool Tools automatic option, which adds boolean and immediatelly applies it. So even though I use multiple booleans on single objects, they're never chained in a sense that I never have all modifiers at the same time.

So that answers your last question as well, speed is the most important requirement for me besides it just preserving mesh well. I've had workdays where I had to spend 4+ hours just doing booleans, and when each operation takes 10+ seconds on 500,000 poly mesh it's quite daunting.

> Do you care about the output topology (do you care if they are all triangles?) I don't think so. Nowadays 3D printers can print almost any topology. Sometimes we do get some weirdness, but it's all fixable. Sometimes I even run Decimate on models but they still print fine. What is hard requirement for us is that silhouette of the object isn't changed and object is watertight. Judging by the name only Manifold might help here. > Do you care about reliability in cases where one edge of one part exactly intersects an edge or vertex of another part? Do you care about handling coplanar intersections properly? I'm not sure I fully understand that, but because my models are typically 300,000+ polygons, and there are lot of intersections (also because they're tiny), so in many cases where I run booleans there are lot of vertices and edges that are intersecting or very close to each other. Sometimes I use "Merge by Distance" to reduce the number, and it can take out even 30,000k vertices that are close to each other. It's important for me that boolean can handle that and doesn't need merge beforehand. For example, I had mustache and head as separate objects, and before printing I was using union boolean to combine them, and in at least 2/3 of cases I had to run "Merge by Distance" on head object because otherwise boolean would screw up. > How large are your models typically? Our models are 30-50 mm, but sometimes we don't follow real-life scale in Blender, because it's harder to work on smaller sizes and we scale them up to meters, and then rescale them in 3D printing software. > Do your booleans typically have only two operands or many operands? Do you chain many booleans together? I use Bool Tools automatic option, which adds boolean and immediatelly applies it. So even though I use multiple booleans on single objects, they're never chained in a sense that I never have all modifiers at the same time. So that answers your last question as well, speed is the most important requirement for me besides it just preserving mesh well. I've had workdays where I had to spend 4+ hours just doing booleans, and when each operation takes 10+ seconds on 500,000 poly mesh it's quite daunting.
Author
Member

Niki,

Thanks for your response.

By "how large", I meant "how many polygons", but you answered that already.

Can I assume you are currently using the "Float" solver in the modifier? (I don't know if Bool Tool always uses Float, or if there is an option). With models that large, the 'Exact' solver must be too slow by far. But that would be why you have to fiddle with merging so often in order to not have boolean "screw up".

While I understand that you use Bool Tool and thus do one boolean at a time, if there were a way to do multiple booleans at a time, about how many total operands would there be in your typical use?

Niki, Thanks for your response. By "how large", I meant "how many polygons", but you answered that already. Can I assume you are currently using the "Float" solver in the modifier? (I don't know if Bool Tool always uses Float, or if there is an option). With models that large, the 'Exact' solver must be too slow by far. But that would be why you have to fiddle with merging so often in order to not have boolean "screw up". While I understand that you use Bool Tool and thus do one boolean at a time, if there were a way to do multiple booleans at a time, about how many total operands would there be in your typical use?
Contributor

Mostly I use Exact, because even though it's slower, it's most important that it looks the best. Objects we print are gonna be shot in close-ups and shown on large screens, so they have to look best. Sometimes there are cases where Float also can do the job, but problem is if I spend time checking Float, seeing if it works, and if it doesn't then undoing and redoing with Exact, I spend more time than if I do all Exacts.

That reminds me that undo speed is biggest performance hit in my workflow. Because every time Exact solver fails and I have to adjust my mesh and redo Blender freezes on undo and triples waiting time.

While I understand that you use Bool Tool and thus do one boolean at a time, if there were a way to do multiple booleans at a time, about how many total operands would there be in your typical use?

Either 3 or 4 operands on each object.

Mostly I use Exact, because even though it's slower, it's most important that it looks the best. Objects we print are gonna be shot in close-ups and shown on large screens, so they have to look best. Sometimes there are cases where Float also can do the job, but problem is if I spend time checking Float, seeing if it works, and if it doesn't then undoing and redoing with Exact, I spend more time than if I do all Exacts. That reminds me that undo speed is biggest performance hit in my workflow. Because every time Exact solver fails and I have to adjust my mesh and redo Blender freezes on undo and triples waiting time. > While I understand that you use Bool Tool and thus do one boolean at a time, if there were a way to do multiple booleans at a time, about how many total operands would there be in your typical use? Either 3 or 4 operands on each object.
Contributor

From the sculpting side of things, this comment and others in the issue may be helpful in gathering some requirements / desired features, though it also concerns more specific Trim functionality that isn't necessarily relevant to the boolean solver itself.

From the sculpting side of things, [this comment](https://projects.blender.org/blender/blender/issues/84229#issuecomment-896500) and others in the issue may be helpful in gathering some requirements / desired features, though it also concerns more specific Trim functionality that isn't necessarily relevant to the boolean solver itself.
Author
Member

Answering Jacques' earlier questions:

Overall, I think the Manifold library seems to be a good fit for procedural workflows, probably better than the other solvers we have already. Are there functional benefits of using Ember over Manifold? Does Manifold handle coplanar faces as well as Ember? How does Ember decide what's inside when the input is not a closed volume?

Ember is an exact solver that handles special cases such as coplanar faces, edges exactly intersecting edges at something other than their endpoints, etc., as one would expect. Manifold is a "robust float solver", where the "robust" means that it will not create topological nonsense. But it does that by taking cases like coplanar faces and edges exactly intersecting edges and perturbing them in the decision process so that the special cases don't happen. This means that it can create zero area faces and the like. There is a cleanup process that does merges and other operations to try to get rid of such things. We need to experiment to see how successful that is in practice. But note that there are several caveats to saying that Ember is exact: first, it is only exact in the space where all vertex positions are converted to 26-bit integers (after scaling the floats to take full advantage of that range, of course). Second, sometimes "exact" doesn't correspond to what users actually want -- for instance, if you rotate a cube by what feels like 90 degrees, maybe the rotation matrix makes the vertex positions slightly away from their exact values if the rotation were perfect; then if you expected a face in that to be coplanar with another mesh's face, you might be disappointed that it creates an almost-zero-area face instead.

Ember, as described in the paper creates a strange output topology compared to Manifold. Ember's faces have t-junctions all over the place. If I continue working on Ember, I will try to fix that problem, which I think Blender users who care about output toplogy would not find very acceptable.

Ember might be faster than Manifold huge models, because it pays more attention to short-circuiting around large parts of models that are unaffected by intersection. But this is just a hypothesis at this point, not proven.

Manifold determines inside-vs-outside via local computations with the entities involved in the intersections, followed by some kind of sort. (Basically, the local computations determine which elements are "shadowed by", and hence "inside" in some sense, which other elements.) It is hard to see how to adapt this to the cases where our current Float and Exact solvers can deal with non-manifold meshes.

One possibility open to us: I take Manifold's code as a starting point, remove its dependencies on clipper, thrust, and glm, and then adapt it to Blender's specific use case, adding optimizations like the short-circuiting of Ember. The big downside of this would be losing (or at least making much harder) any future improvements to Manifold by its author.

Answering Jacques' earlier questions: > Overall, I think the Manifold library seems to be a good fit for procedural workflows, probably better than the other solvers we have already. Are there functional benefits of using Ember over Manifold? Does Manifold handle coplanar faces as well as Ember? How does Ember decide what's inside when the input is not a closed volume? Ember is an exact solver that handles special cases such as coplanar faces, edges exactly intersecting edges at something other than their endpoints, etc., as one would expect. Manifold is a "robust float solver", where the "robust" means that it will not create topological nonsense. But it does that by taking cases like coplanar faces and edges exactly intersecting edges and perturbing them in the decision process so that the special cases don't happen. This means that it can create zero area faces and the like. There is a cleanup process that does merges and other operations to try to get rid of such things. We need to experiment to see how successful that is in practice. But note that there are several caveats to saying that Ember is exact: first, it is only exact in the space where all vertex positions are converted to 26-bit integers (after scaling the floats to take full advantage of that range, of course). Second, sometimes "exact" doesn't correspond to what users actually want -- for instance, if you rotate a cube by what feels like 90 degrees, maybe the rotation matrix makes the vertex positions slightly away from their exact values if the rotation were perfect; then if you expected a face in that to be coplanar with another mesh's face, you might be disappointed that it creates an almost-zero-area face instead. Ember, as described in the paper creates a strange output topology compared to Manifold. Ember's faces have t-junctions all over the place. If I continue working on Ember, I will try to fix that problem, which I think Blender users who care about output toplogy would not find very acceptable. Ember might be faster than Manifold huge models, because it pays more attention to short-circuiting around large parts of models that are unaffected by intersection. But this is just a hypothesis at this point, not proven. Manifold determines inside-vs-outside via local computations with the entities involved in the intersections, followed by some kind of sort. (Basically, the local computations determine which elements are "shadowed by", and hence "inside" in some sense, which other elements.) It is hard to see how to adapt this to the cases where our current Float and Exact solvers can deal with non-manifold meshes. One possibility open to us: I take Manifold's code as a starting point, remove its dependencies on clipper, thrust, and glm, and then adapt it to Blender's specific use case, adding optimizations like the short-circuiting of Ember. The big downside of this would be losing (or at least making much harder) any future improvements to Manifold by its author.
Member

I'm not sure how much effort it would be, but I'd really like to see a prototype with Manifold where one can chain multiple mesh boolean nodes and everything is evaluated as efficiently as possible, i.e. no unnecessary data structure conversions and attribute propagations (I'm fine with using a hacky approach to implement this). If that feels fast enough, it may be good to work towards properly implementing it. Otherwise, we might have to hope that Ember can feel fast enough in this situation. I can't really put numbers on what "fast enough" means yet unfortunately.. Right now it just too often feels slow when one would expect things to be real-time still.

I'm not sure how much effort it would be, but I'd really like to see a prototype with Manifold where one can chain multiple mesh boolean nodes and everything is evaluated as efficiently as possible, i.e. no unnecessary data structure conversions and attribute propagations (I'm fine with using a hacky approach to implement this). If that feels fast enough, it may be good to work towards properly implementing it. Otherwise, we might have to hope that Ember can feel fast enough in this situation. I can't really put numbers on what "fast enough" means yet unfortunately.. Right now it just too often feels slow when one would expect things to be real-time still.
Author
Member

I can see what I can do. Interestingly, Manifold internally keeps a tree of boolean operations, unevaluated, until one asks for the mesh output.

I did a very rough timing test yesterday (unsatisfactory mixture of Debug and Release code) that leads me to believe that Manifold will likely be about the same, or maybe somewhat faster, than our current Float solver. Which is much better than current Exact, but still not where I'd like it to be (Sean was ready to investigate improving the Float solver for sculpting as it was still sometimes too slow there).

To do the prototype you talk about, I can see several approaches:

  1. Make a cache property of Mesh runtime that holds the internal manifold, or something like it, and not evaluate the manifold until some Geometry input really wants to suck up the realized mesh. The boolean node could then use such an cached value input instead of freshly converting input Mesh into manifold.

  2. Try to examine the geo node tree and make connected components of boolean operations, and then make a boolean expression tree from that and evaluate it all at once.

Thoughts? Other ideas?

I can see what I can do. Interestingly, Manifold internally keeps a tree of boolean operations, unevaluated, until one asks for the mesh output. I did a very rough timing test yesterday (unsatisfactory mixture of Debug and Release code) that leads me to believe that Manifold will likely be about the same, or maybe somewhat faster, than our current Float solver. Which is much better than current Exact, but still not where I'd like it to be (Sean was ready to investigate improving the Float solver for sculpting as it was still sometimes too slow there). To do the prototype you talk about, I can see several approaches: 1. Make a cache property of Mesh runtime that holds the internal manifold, or something like it, and not evaluate the manifold until some Geometry input really wants to suck up the realized mesh. The boolean node could then use such an cached value input instead of freshly converting input Mesh into manifold. 2. Try to examine the geo node tree and make connected components of boolean operations, and then make a boolean expression tree from that and evaluate it all at once. Thoughts? Other ideas?
Author
Member

Here are some timings for a Release build on my Macbook Pro M3 Max (12 performance cores, 4 efficiency cores):

For a sphere-sphere difference where sphere1 has 200k faces (400k triangles) and sphere2 has 500k face (1 M triangles):

exact: 1281 ms
float: 422 ms
manifold: 327 ms. (triangle output for now; the other two have quad output except in the actual intersection areas)

Here are some timings for a Release build on my Macbook Pro M3 Max (12 performance cores, 4 efficiency cores): For a sphere-sphere difference where sphere1 has 200k faces (400k triangles) and sphere2 has 500k face (1 M triangles): exact: 1281 ms float: 422 ms manifold: 327 ms. (triangle output for now; the other two have quad output except in the actual intersection areas)

Regarding how to integrate manifold for prototyping work (and making builds on the buildbot for people to try it out once ready enough), an idea would be to put it and its dependencies into the extern/ of the wip branch for the time being. Then if we decide it's worth it and when it's ready for main, we can properly add the libraries to our pre-compiled repository instead.

Regarding how to integrate manifold for prototyping work (and making builds on the buildbot for people to try it out once ready enough), an idea would be to put it and its dependencies into the `extern/` of the wip branch for the time being. Then if we decide it's worth it and when it's ready for main, we can properly add the libraries to our pre-compiled repository instead.
Author
Member

I kind of like that idea, Bastien, and think I will try it out. For one thing, it makes it easier for me to experiment with some things without having to involve the platform maintainers (though I thank LazyDodo for his help so far, which has made it possible for me to get this far).

I may even be able to figure out how to remove some, if not all, of the dependencies beyond manifold itself (I think, but have to verify), that clipper and hull are only needed for features that we don't need for 3D Boolean.

I kind of like that idea, Bastien, and think I will try it out. For one thing, it makes it easier for me to experiment with some things without having to involve the platform maintainers (though I thank LazyDodo for his help so far, which has made it possible for me to get this far). I may even be able to figure out how to remove some, if not all, of the dependencies beyond manifold itself (I think, but have to verify), that clipper and hull are only needed for features that we don't need for 3D Boolean.
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
6 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#120182
No description provided.