Three.js: Constructive Solid Geometry (CSG) Support

Created on 29 Mar 2019  ·  56Comments  ·  Source: mrdoob/three.js

CSG is a very important feature… other 3D frameworks have support for CSG built-in ( Babylon.js ), the only CSG I can find is the 7 years outdated plugin ( https://github.com/chandlerprall/ThreeCSG )

I propose that this plug-in gets updated for bufferGeometry and added to the three.js code base as an official plug-in for CSG support.

I am willing to contribute funds to see this happen.

Enhancement

Most helpful comment

I did another conversion of the madebyevan CSG library that ya'll may find useful.. it works with current three (103) and fixed some issues I had with the older module out there. It allows buffergeometries but only by converting them to geometries internally.

https://github.com/manthrax/THREE-CSGMesh

Hope this helps someone and feel free to give feedback/suggestions.

All 56 comments

I can give it a try this weekend... let me see how it goes.

Um, I've added a OrbitControls and inspecting the result it doesn't seem very correct. Are you sure this library is sufficiently tested?
Please make some tests on it before I try to 'Bufferize' it 😉
image

Adding it to the core code base might be a bit complicated, the current version (v1 branch) is in TypeScript. Works fine with r100 (and even r103) thou: examples

I don't think bundling it into the src/ folder is the right direction, but updating it to support BufferGeometry sounds promising. Whether the library is well-tested, I have no idea. :)

Adding it to the core code base might be a bit complicated, the current version (v1 branch) is in TypeScript. Works fine with r100 (and even r103) thou: examples

So it is actively developed. I didn't see that tag. And... it seems the v1 tag supports BufferGeometry! @ThreeDfish

I vote to not include CSG features into this repo. Better ThreeCSG is supported if necessary.

So it is actively developed. I didn't see that tag. And... it seems the v1 tag supports BufferGeometry! @ThreeDfish

I don't think so, this is the only mention of BufferGeometry in the v1 version:

function convertGeometryToTriangles(geometry) {
        if (isBufferGeometry(geometry)) {
            throw new Error('threecsg: Only Three.Geometry is supported.');
        }

Has anyone tried contacting the owner of the ThreeCSG to see what their plans are or if they're open to taking PRs to support BufferGeometry? I'm a little interested in this, too.

It seems nobody asked there about BufferGeometry...

Why not shifting the conversation to https://github.com/chandlerprall/ThreeCSG? I bet @chandlerprall would be happy to see such an interest in his project 😊

FWIW there is a newer v1 branch in ThreeCSG which is a complete re-write and cleanup. Need to optimize the plane selector algorithm and then it's ready to npm publish. I would be thrilled if anyone wants to contribute additional features (see also https://github.com/chandlerprall/ThreeCSG/issues/51)

For your information:

Besides https://github.com/chandlerprall/ThreeCSG, the following CSG libraries were mentioned in the recent Discourse forum thread:

I have no opinion on whether any of these three should serve as a basis for three.js's CSG support.

I did another conversion of the madebyevan CSG library that ya'll may find useful.. it works with current three (103) and fixed some issues I had with the older module out there. It allows buffergeometries but only by converting them to geometries internally.

https://github.com/manthrax/THREE-CSGMesh

Hope this helps someone and feel free to give feedback/suggestions.

@manthrax Your project would be a good addition to the following thread in the three.js forum so people who are looking for a plugin will actually find it👍

https://discourse.threejs.org/t/looking-for-updated-plug-in-for-csg/6785

Awesome! I'm not sure how feasible it is but I think any of these solutions would benefit from some examples that demonstrate the performance and real-time editing capabilities like a lot of engine editors have, now.

My personal preference is to keep CSG out of the library and develop it independently.

I agree with this, but it might be useful to have an official set of "related repos". I've created an organisation that we can use for this if we decide to go ahead. github.com/threejs is taken by @enricomarino, but github.com/three-js was there. I'll transfer ownership to whoever, just figured it was good to jump on the name!

So, this organisation is available of anybody want to create projects related to three.js that don't quite fit here.

https://github.com/three-js

I created the organisation https://github.com/threejs to host projects related to three.js.

Actually, at that time, I thought to split the "three.js" mono repo into multiple repos,
such as "threejs/core", "treejs/examples", "threejs/editor", "threejs/docs",
since the "mrdoob/three.js" has become very large and heavy to download...
but this is another story...

If you'd like to use it, the organisation is at your disposal!

I've added a demo and a screenshot to the library:

https://github.com/manthrax/THREE-CSGMesh

Let me know if anyone needs help with it!

@yomboprime @ThreeDfish
I've added a screenshot and a demo to the CSG library I ported. Let me know if you find it useful.
https://github.com/manthrax/THREE-CSGMesh

@yomboprime @ThreeDfish
I've added a screenshot and a demo to the CSG library I ported. Let me know if you find it useful.
https://github.com/manthrax/THREE-CSGMesh

@ThreeDfish If you are still interested I can make a CSG.toBufferGeometry function in this library. The CSG would still accept Geometry as input, but the output could be Geometry (for further boolean operations) or BufferGeometry (final output for rendering).
What do you think @manthrax ?

@enricomarino can you give me access to github.com/threejs ? I'd like to set up a repo with test models for the LWOLoader. BTW you're a hard person to find contact details for 😛

@yomboprime I'm not sure what you're asking..

The version I ported accepts both BufferGeometry or Geometry meshes.. it outputs Geometry, which can be converted to BufferGeometry with

mesh.geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry)

So i don't know if there really is a need for an extra helper function since the conversion is pretty straightforward.

The Geometry->BufferGeometry conversion is unfortunately pretty lossy – it will de-index indexed geometry and increase the vertex count, in addition to adding (white) vertex colors. Final output as BufferGeometry would probably be ideal.

The CSG operation doesn't care about indexing. It operates on and outputs 3 unique verts per triangle no matter what.

It also doesn't handle vertex colors.

Optimizing the resulting mesh is something that can/should be done with other tools/helper functions, imho.

Otherwise it's just duplicating dumb functionality that should actually be in a separate library.

I agree that there is definitely a space in terms of a utility for optimizing geometry in THREE.js. The problem applies to more than just BufferGeometry. But applying optimizations to large buffers, via js, at runtime, are chuggy operations.. and any techniques you apply to reduce the complexity, i.e. octtree/kdtree whatever.. get complicated pretty fast and require their own set of paramaterizations etc..

I feel like there is a tradeoff between code "complexity/flexibility/utility" vs "ultra optimized for the gpu" that in a non javascript setting, you would optimize for the latter, but in a js/web scenario, you would aim for the former, and only if you decide you need to pursue the latter, you would use something like wabasm to crunch the data.

Not to mention these CSG operations are already pretty slow.. The demo in my git is barely interactive with only 10 operations per frame on a box and a 8 subdiv sphere...

That said.. i just looked at the babylon csg demo.. and I'm pretty sure it's a port of the exact same library,
And it's not being done in realtime in that demo either.
https://www.babylonjs.com/demos/csg/

Here is the version I've converted doing a simpler example in realtime:

http://vectorslave.com/csg/CSGDemo.html

I agree that CSG operations are not especially a realtime-friendly, and that the library does not need to pretend they are. However, note that Geometry will eventually be removed from the three.js library, and moved into examples/js/* and examples/jsm/*. At that point, users will almost certainly have an easier time using BufferGeometry as their result. If the CSG code has an internal dependency on Geometry, that seems fine of course.

I would say it this way...

If you want to chain operations, inputting Geometry and outputting Geometry makes sense, since CSG operates on that data structure only.

But be aware that Geometry will soon no longer be renderable, so the output will have to be converted to BufferGeometry in the final step.

@manthrax The QuickHull implementation uses an own set of classes so topological operations are easier done. For example a half-edge implementation is way better than working with Geometry in this context. Since Geometry is focused on rendering, other types of classes might work better even for CSG.

Appreciate the feedback @donmccurdy @WestLangley @Mugen87 .
I'll look into making it work natively with BufferGeometry in preparation for the Geometry deprecation.
I also want to add color and material/group support as well.

@enricomarino Actually, I was planning on sending you a message to see what were you planning to do with the org as I was considering moving it out of my username and splitting things a bit. Not sure yet how should it look like, but would you like to add me to the org for now?

@mrdoob sure!

Hi all.. I made a shinier demo of the CSG library, and fixed a bug in normal generation, if anyone is interested:

http://vectorslave.com/csg/CSGShinyDemo.html

and the gh:
https://github.com/manthrax/THREE-CSGMesh

I am looking into adding a BufferGeometry optimizing version, and something that preserves material separation between the inputs, so it could be directly used for something like a SCAD software.

Just thought I'd drop these links here for inspiration and in case anyone wants to dive really deep into them. I came across this CSG tool in Unity that has some really impressive performance and content creation capabilities:

https://assetstore.unity.com/packages/tools/modeling/realtime-csg-69542

And it looks like the creator has written a few articles on the implementation (there are six parts in total):

http://sandervanrossen.blogspot.com/2010/05/realtime-csg-optimizations.html
http://sandervanrossen.blogspot.com/2010/05/realtime-csg-part-5.html

I ported a csg library and it works very well at the moment.
I can update this project if needed.

https://github.com/FishOrBear/csg.ts

Any update on this?

the library from @manthrax works perfectly!

@manthrax

I am looking into adding a BufferGeometry optimizing version

Is it using THREE.Geometry at the moment?

so i could not let it rest and looked into https://github.com/jscad/csg.js which is the core CSG library of https://openjscad.org/
i browserified it and wrote my own THREE BufferGeometry adapter and it is actually A LOT faster than the library that @manthrax based his code on. (and it supports vertex coloring)

for the same dice which uses spheres with 32 faces to cut out the eyes,
THREE-CSGMesh took 112 seconds,
jscad/csg took 2.5 seconds!!!

that's 45 times faster...

i'm thinking about creating a library out of it, let me know what you think about it...

@SebiTimeWaster

Is it available in a repo anywhere? Looks like csg.js is MIT license, too.

@mrdoob

I am looking into adding a BufferGeometry optimizing version

Is it using THREE.Geometry at the moment?

Iooking at the codebase briefly it looks like yes it does still use THREE.Geometry but just on the input and output to convert it to and from an internal structure for CSG operations.

not yet, if there is interest i would create one...

not yet, if there is interest i would create one...

Heh I think this thread is evidence of interest! But at least I'm interested in checking it out if you've got a faster version. I don't have an immediate need for it anymore but I may in the future. It would be nice to have go to library for CSG in three even if it's just a quick example for how to get started with csg.js in three.js.

not yet, if there is interest i would create one...

Yes, an official example/solution for csg would be great!

I'm on it...

I'm mostly done with a BufferGeometry port of @evanw's csg.js.
Needs a bit of tidying, which I'll find time for this week, then I'll share it here.

@mrdoob do you want a CSG library in this repo? If so I'll make a PR. Otherwise, I'll make a new repo for it.

@SebiTimeWaster I didn't see your comment before now, oops. The more the merrier I guess 😁

@looeee is it a full port or just a wrapper? It looked like csg.js had to convert data to a lot of internal structures for CSG operations anyways, right? It seemed like you should just be able to convert to and from BufferGeometry on the way in and out.

@looeee do you mean a new repo within here ?
would be interesting but I hazard a guess mrdoob ain't ready yet.

I'm not sure this repository is the right place to maintain a full CSG library... perhaps add an example, using a minified build of the CSG library in examples/js(m)/libs/?

So, here is my take on the whole thing (it is based on https://github.com/jscad/csg.js):
https://github.com/SebiTimeWaster/three-csg
with an example (stress test):
https://sebitimewaster.github.io/three-csg/examples/example2.html

@looeee how about you implement the same stress test, then we can compare and optimize our code against each other...

@looeee is it a full port or just a wrapper?

I have one branch that is pretty much just a wrapper for csg.js with a few minor changes:

  • modularized the code
  • aligned function names to three.js and used Vector3 instead of a custom vector class,
  • minor API improvements

That branch is complete, and I'll share it once I tidy it up a bit. However, it's sloooow.

I have another branch where I'm working on speed improvements. There's a lot that can be done here, mainly to do with calculating early outs to avoid as much processing as possible.

@SebiTimeWaster, I've taken a quick look at your code and you're doing something like this using bounding spheres for each polygon I think? I'll try recreating your example using my library when I find the time.

@SebiTimeWaster can your csg implementation handle texture coordinates?

Here's how texture coordinates look in mine.

2020-06-08 20_20_34-Discoverthreejs com - three js CSG Demo A

Here's the repo:
https://github.com/looeee/threejs-csg

There are two branches, _master_, which is pretty close to a wrapper of csg.js as I described above, and _advanced_. There I've expressed all the CSG operations using the LogicalOR and complement methods:

Union: _(Left || Right)_
Subtract: _!(!Left || Right)_
Intersect: _!(!Left || !Right)_

Doing that makes the operations a bit easier to reason about and also makes subtract and intersect slightly faster. There are also some experiments with doing a high-level bounding box based merge and cull before doing the full CSG operations, which gives some decent speedups when performing many operations at once.

A better approach, however, and what seems to be most used in other implementations, is to create a BVH of geometries and operations and traverse the tree to generate the final geometry.

@SebiTimeWaster for now I've decided to look into alternative CSG implementations rather than go further with this one. If there's anything useful from my repo feel free to take it.

EDIT: This tweet sums up my feelings exactly

It looks like the source for the Realtime CSG plugin for Unity that I linked above has been posted on Github and is MIT licensed if anyone is interested in taking a deep dive into that:

https://github.com/LogicalError/realtime-CSG-for-unity

He also has some technical posts about his CSG plugin on his blog, too, if you go back bit:

https://sandervanrossen.blogspot.com/search?q=Realtime+CSG

There was also a newer GDC talk from him back in March this year on CSG:

https://www.youtube.com/watch?v=Iqmg4gblreo

I haven't messed around with his work in Unity myself but the performance in videos looks great.

There's also this one which is based on the Unity CSG but is a standalone C# app, it might be easier to understand. It's quite a bit older though so it may not be as developed.

https://github.com/LogicalError/Realtime-CSG-demo

Godot engine also has CSG which I tested out and it has very decent performance. docs / code.

There's also Carve CSG and xcsg (which uses Carve), and Cork.

I wonder if the best solution here would be to take one of these existing solutions (probably Carve since it's CPP and seems to be used in lots of other packages) and convert it to Wasm.

I wonder if the best solution here would be to take one of these existing solutions (probably Carve since it's CPP and seems to be used in lots of other packages) and convert it to Wasm.

I'm less familiar with emscripten but that doesn't sound like a bad approach. It looks like Carve and Cork are GPL and LGPL licensed, though, so that's something to keep in mind.

Apparently Blender has just updated it's boolean operations tool and according to this tweet uses approaches from this paper:

http://www.cs.columbia.edu/cg/mesh-arrangements/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DefinitelyMaybe picture DefinitelyMaybe  ·  88Comments

goodsign picture goodsign  ·  101Comments

WaltzBinaire picture WaltzBinaire  ·  67Comments

mrdoob picture mrdoob  ·  75Comments

fernandojsg picture fernandojsg  ·  85Comments