-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improving Performance #21
Comments
Looks good to me! Yeah this is definitely a worthy optimization. There is definitely room to improve the API. I've had some thoughts about making the api more "fluent" and adding helper functions like yours, but haven't had the time. |
Nice approach but I can imagine it will have some issues with overlapping or complex meshes. If you would like to share a more complete example of the code, I can use it for testing when I continue my attempts to make CSG faster. |
One way to speed these kinds of operations up, is to break them into smaller problems. Otherwise any CPU/cache/de-recursion based performance improvements will still have an upper limit due to the nature of the algorithm., where currently, every triangle in each mesh has to be tested against every other triangle of the other mesh. To get REAL big speedups I think you would have to pull in some kind of search acceleration structure like mesh-bvh or an octtree. Then you have a chance of knocking down the dot O complexity, at the cost of making the algorithm quite a bit more complicated. But that is no easy task. |
You can see an example of the first approach, here: https://manthrax.github.io/THREE-CSGMesh/v2/index.html Here I took a complex blobby gold shape, and subtract a high poly text from it. But cutting out the area of interest into a second piece.. then subtracting the high poly text from that simpler piece, and merging the results back together is very quick. |
So.. there are definitely ways to improve the speed of the algorithm, but they all involve adding a TON more complexity to the algorithm, which IMO is outside the scope of the library, and should either become a fork/optimized version, or some kind of add-on library. |
@manthrax I see what you are saying, I ran into the recursion error (stack size exceeded) on the union operation even with the arrays since it still needs to add all polygons from bspB to bspA at the end. I'm still experimenting but I was able to improve the performance by checking the intersection of all the bspA polygons against the bounding box of bspB and then exempting them from the node build flow. I also noticed that with some geometries (extruded geometry for example), the node build flow sometimes gets stuck on the same polygons and keeps looping for thousands of times until it errors out with the stack size exceeded error, I've added some logic to check and stop these loops so now I rarely see the stack size exceeded error. |
@giladdarshan That's great. Yeah that sounds like a promising avenue, the intersection/bounds pre-pass. If you come across a simple repro for the stack exceeded thing, in the form of a gltf file? Let me know and I can take a look if its something easy to fix. You can export an object using the THREE GLTFExporter... via something like this:
|
@manthrax the easiest way for me to reproduce this error is with extruded geometries and then try to union it with a small cylinder, below is a simple example of the extruded geometry:
With the current CSG I quickly get the error "RangeError: Maximum call stack size exceeded" on Node.build.
|
@manthrax what are your thoughts on the suggested solution here for the recursion issue in node.build? If I use the function I posted above I end up with some missing polygons in the end geometry, with the below change I can't see holes in the geometry (so far, continuing to test). Changing the loop in node.build from:
To:
|
Your repro is missing the first part where you create the first mesh? Can you perhaps show it in a glitch? |
I really need to make a test suite... if you can give me that small repro, i can start with that :) |
Your 2 line fix looks promising but I want to understand/see the problem before I try to fix it. |
@manthrax, here are the two meshes and the union operation:
If I change
Do you mean converting the recursion to a regular loop? something like this? I believe it will run into the same issue of infinite looping unless we solve the issue of the |
interesting yeah. I do mean something like that. and yeah.. I want to understand why it's happening before I attempt to fix it pull a fix. :D There are limits to this technique which I don't advertise because they don't always matter. Like.. ideally this should only be done with manifold meshes, but you can get away without manifold meshes sometimes. btw: if you feel like making a fork with bleeding edge improvements, I'm totally on board! |
I plan on updating a fork with the improvements, doing some more tests and then. I'm also looking into using Octree for CSG, Three.js already has an Octree class so it helps. |
afaik polygons in the algorithm are always triangles.. they are extracted from threejs buffergeometries which only support triangles. |
@manthrax right, the incoming geometry always results in triangles, but, the splitPolygon function sometimes creates polygons with 4+ vertices when it hits the spanning type case. |
In the
I tried using the same logic in the splitPolygon function when the f/b arrays are bigger than 3 but the result didn't look good, so I assume another / better algorithm is needed for the triangulation. |
@manthrax I've updated the changes I made in my fork, still need to do more testing. I've started reading about Octree-Embedded BSPs so I'm going to try and implement something similar (couldn't find code examples for it). |
@giladdarshan Sorry for the late response. :) That does sound interesting... I have also been mulling over the idea of using this library https://github.com/gkjohnson/three-mesh-bvh as an acceleration structure.. Curious about your impression of https://arxiv.org/abs/2103.02486 as well? |
Hey @manthrax, I looked into gkjohnson's BVH implementation (I use it in my website for other things), they also have a question there regarding CSG (Issue #281). I didn't find code examples for the Octree-Embedded BSPs so I decided to create a new CSG implementation using Octrees from scratch. There is still more room for improvement and testing but so far it's performing faster and generating less triangles than BSP based CSG libraries. It can also be used in combination with gkjohnson's three-mesh-bvh for faster raycasting. I will invite you later to the project, looking forward for your input and feedback :) |
@giladdarshan nice work! Once the project is public do let me know, as well. Getting CSG going using three-mesh-bvh as a traversal structure had been on my list for awhile but I never got the chance to start. There were other non-BSP approaches I was looking at to help improve perf and memory overall. Happy to contribute ideas, too. I'm interested to see more of this! I'll have to dig through my notes to find other references I was looking at at the time. |
Awesome, I've invited both of you and will appreciate any feedback you have. @manthrax I think the changes in my fork are still useful for this library -
|
Wow that's looking fantastic @giladdarshan!! |
Thank you :) Do you happen to have an example that uses the latest Three.js versions? If I try to use "CSGDemo" with the latest Three.js it complains about missing RGBEEncoding / RGBEFormat. |
@giladdarshan I've created a pull request for easier version bumping. |
If i could suggest some a further improvement relatively simple to add: object pooling would be quite relevant here as there are a lot objects created and cloned through the process, it basically just needs a create-method and "flush" method at the end the user would call when the process is done, to push Polygon, Vertex etc. into an cache array, and instead calling Vertex.cache = [];
Vertex.new = function ( pos, normal, uv ) {
const instance = Vertex.cache.pop() || new Vertex;
instance.set( pos, normal, uv );
return instance;
} A This drastically increases general performance regarding GC and memory, a manual For a bit more advanced solution Also having a optional "without A" or "without B" option would be nice if the new polygons from subtraction are not required to be in the final geometry. |
Hello,
I've been learning how THREE-CSGMesh works in an attempt to improve the performance when dealing with a large number of objects.
As an example, making 14 holes in a plate/cube (as shown below), with the current subtract function, it will need to create a total of ~28 BSP trees (a/b nodes in the function).
By adding support for an array of CSG objects, I'm able to cut down the total operation time from ~1.9 seconds to ~0.21 seconds as it only creates ~15 BSP trees for the above example:
What are your thoughts on this? are there any downsides I'm not seeing?
Thanks,
Gilad
The text was updated successfully, but these errors were encountered: