More Boolean Solvers #120182
Labels
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
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#120182
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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:
Which Solvers to Add?
Native Float Solver
The obvious first one to add is the current native float solver.
Pros
And in fact, the main branch of the 4.2 alpha already has the native float solver added. #119294.
Cons
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
Cons
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
Cons
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 theBM_mesh_intersect
function.The areas of largest runtime are as follows:
Performing the Tri-Tri Intersections
(tree_overlap_tot = 3570558) taking 5.2s (31.9% of runtime)
Iteratively Removing Faces
(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?
FYI some context from @LazyDodo re adding
manifold
lib to our dependencies: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 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:
Am I missing something important? Which solver would you use for each of these tasks?
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?
Thanks.
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.
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:
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?
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
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 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.
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.
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.
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.
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?
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.
Either 3 or 4 operands on each object.
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.
Answering Jacques' earlier questions:
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.
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 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:
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.
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?
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.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.