pmndrs / drei

🥉 useful helpers for react-three-fiber
https://drei.pmnd.rs/
MIT License
7.84k stars 641 forks source link

Constructive Solid Geometry #390

Open jarjav opened 3 years ago

jarjav commented 3 years ago

Describe the feature you'd like:

Constructive Solid Geometry (CSG) Support

Suggested implementation:

<mesh ref={boxRef}>
  <boxGeometry />
  <meshPhongMaterial />
</mesh>

<mesh ref="refSphere">
  <sphereGeometry />
  <meshPhongMaterial />
</mesh>

<union a={boxRef} b={sphereRef}>
<subtract a={boxRef} b={sphereRef}>
<intersect a={boxRef} b={sphereRef}>

csg

joshuaellis commented 3 years ago

This is cool! How is this done in threejs regularly?

jarjav commented 3 years ago

This is cool! How is this done in threejs regularly?

There are some CSG libraries for threejs. Look at https://www.npmjs.com/search?q=three-csg for inspiration. But none for react-three-fiber. Therefore I asked to add this feature to drei library.

joshuaellis commented 3 years ago

Okay, I think realistically this requires someone who has used CSG before. But as an API implementation, I'd probably recommend something like this:

const Component = () => {
  return (
    <mesh>
      <Union {...geometryProps}>
        <boxGeometry attachCsg="a" />
        <sphereGeometry attachCsg="b" />
      </Union>
      <meshPhongMaterial />
    </mesh>  
  )
}

Although you could potentially get rid of the attachCsg and just have it based on child order. The HOC would return a geometry if possible... 🤔 Although you can't give geometry a position, so how does each one know where to sit? In which case maybe something like this would work:

const Component = () => {
  return (
    <Union {...meshProps}>
      <mesh>
        <boxGeometry attachCsg="a" />
      </mesh>
      <mesh>
        <sphereGeometry attachCsg="b" />
      </mesh>
      <meshPhongMaterial />
    </Union>
  )
}

where we either take child A's material, or a material passed as part of the HOC...

jarjav commented 3 years ago

you are right, searching google, maybe approach like in modeler-csg lib would be the right way ---> https://github.com/szymonkaliski/modeler

<Canvas>
    <ambientLight color={0x888888} />
    <spotLight position={[0, 10, 10]} />
    <Model>
      <subtract>
        <cube />
        <sphere radius={1.3} />
      </subtract>
    </Model>
  </Canvas>

besides used shapes of course

jacobbroughton commented 2 years ago

you are right, searching google, maybe approach like in modeler-csg lib would be the right way ---> https://github.com/szymonkaliski/modeler

<Canvas>
    <ambientLight color={0x888888} />
    <spotLight position={[0, 10, 10]} />
    <Model>
      <subtract>
        <cube />
        <sphere radius={1.3} />
      </subtract>
    </Model>
  </Canvas>

besides used shapes of course


I personally cannot get that library to work, once i finally got past the dependency tree issues it's Model / Subtract didn't work for me :/

looeee commented 2 years ago

Okay, I think realistically this requires someone who has used CSG before. But as an API implementation, I'd probably recommend something like this:

const Component = () => {
  return (
    <mesh>
      <Union {...geometryProps}>
        <boxGeometry attachCsg="a" />
        <sphereGeometry attachCsg="b" />
      </Union>
      <meshPhongMaterial />
    </mesh>  
  )
}

I think that looks pretty good. The main issue here is that all the existing three.js CSG libraries (including/especially mine) are slow and often buggy. They're not suitable for real time CSG operations except on very simple geometries.

I think the best three.js CSG library currently is manthrax/THREE-CSGMesh. But again, while it will be fine with simple spheres and cylinders, I don't think it'll handle any random geometry you throw at it. Definitely not in real time.

The issue with these libraries is that they're all based on Evan Wallace's csg.js - made many years before he founded Figma I guess 😅 It's a nice library but it's intended to be easy to understand rather than performant. It subdivides the geometry into a BSP tree which is simple but slow.

When I was making threejs-csg my goal was to update this library and make it fast enough for real time use. I found out that there's no way to do that without using completely different algorithms. I ended up doing quite a review of existing open-source (non-JS) CSG libraries to try and find something simple and easy to convert to JS. What I found was that existing solutions are either very slow (not intended for real time use) or highly complex. It would be amazing for someone to write a fast CSG library in JS but it's a pretty big undertaking. For example the guy that created this Unity Realtime CSG plugin wrote some awesome blog posts about how it works - but also, it took him something like 3 or 4 years to develop!

I don't mean to say you shouldn't add this to drei - just be aware of the limitations and that you'll probably get lots of bug reports about "why is CSG so slow" and "I tried to do CSG on my amazing million polygon realistic face model and it made my laptop explode" and so on.

promontis commented 2 years ago

@looeee what about using WASM for this? https://github.com/IFCjs/web-ifc does the same AFAIK.

looeee commented 2 years ago

Yeah, CSG ops are a prime candidate for wasm.

I don't think that's a CSG library though, looks like it's an IFC file loader.

promontis commented 2 years ago

Yeah, I meant that it is using WASM for CSG. It is indeed a IFC file loader.

looeee commented 2 years ago

Ah you're right. And guess what... it's using Evan Wallace's CSG.js, just converted to C++ 😆 That's cool though, means it would be easy to adapt to three.js.

https://github.com/IFCjs/web-ifc/blob/main/src/wasm/deps/csgjs-cpp/csgjs.h

promontis commented 2 years ago

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

looeee commented 2 years ago

Yeah, that's the Unity Realtime CSG plugin I was talking about. The blog posts are here: http://sandervanrossen.blogspot.com/2016/08/realtime-csg-released.html There's a repo with code here: https://github.com/LogicalError/realtime-CSG-for-unity Although I don't think it contains the full tool.

And he talks about creating a successor plugin called Chisel which has a repo here: https://github.com/RadicalCSG/Chisel.Prototype

These are the projects that I identified as most likely to be useful to base a three.js tool on. The other one was the Godot CSG implementation but it's deeply tied into the Godot engine source code. Chisel is also written in C# compared to Godot in C++ so it's easier to understand (for me at least!).

Other candidates are Carve and Cork although they have more restrictive licenses.

promontis commented 2 years ago

@looeee what about using https://github.com/donalffons/opencascade.js?

looeee commented 2 years ago

Oh, nice! I did see CascadeStudio when it was released a few months back, I didn't know they had released the CAD library as open source though.

It's a full CAD library rather than just CSG - that might make it harder to create a simple API in Drei. On the other hand if we could create a simple wrapper then we'd have CAD in Drei! 😮

The main issue is that it's got a more restrictive license - GNU Lesser General Public License v2.1 which I'm not familiar with. Would that mean Drei would have to be GNU licensed too if we used here (or at least the CSG component)? And also any apps that people create with it?

joshuaellis commented 2 years ago

I'm no lawyer (surprisingly), but it depends what we do with it, if we make a copy of it and include it in the library, we probably need to credit the original source and make sure everyone know where it came from and that this is a forked version.

I don't think we need to change the license of drei but like most cases with OSS if there's a license problem, it can always be discussed and solved post trying it out :)

looeee commented 2 years ago

Looking into it a bit, the GPL is a viral (copyleft) license which means that derivative works need to use the same license.

The GPL series are all copyleft licenses, which means that any derivative work must be distributed under the same or equivalent license terms. This is in distinction to permissive software licenses, of which the BSD licenses and the MIT License are widely used, less restrictive examples. GPL was the first copyleft license for general use.

So it boils down to what a derivative work is.

In copyright law, a derivative work is an expressive creation that includes major copyrightable elements of an original, previously created first work (the underlying work). The derivative work becomes a second, separate work independent in form from the first.

The drei component that uses this would definitely be a derivative work, which is not a big deal because we can just include the license at the top of that file. However, I guess any app that includes that component would also be a derivative work - in which case we'd need to tell users that any app they build using that component needs to be GPL licensed.

promontis commented 2 years ago

@looeee or we drop this, and we all wait for https://buerli.io/ :) Some people from pmndrs are actually in the company behind that platform. I think it is wonderful even though it is a pretty big undertaking (read: taking long)

promontis commented 2 years ago

@looeee @joshuaellis it is the GNU lesser license. The LGPL and GPL licenses differ with one major exception; with LGPL the requirement that you open up the source code to your own extensions to the software is removed. So, I think it is fine. I don't think this is a problem. Also it is a weak copyleft, so I don't see any issues here.

promontis commented 2 years ago

@looeee or we drop this, and we all wait for https://buerli.io/ :) Some people from pmndrs are actually in the company behind that platform. I think it is wonderful even though it is a pretty big undertaking (read: taking long)

Thinking about that... I would love to see an opensource buerli.io. I think going for OpenCascade is the best option for this. It is the only real open source CAD kernel. Buerli uses a proprietary CAD kernel (smlib), which is probably a lot better. However, Buerli has to be paid as well (to again pay smlib and such), so I don't think it will ever be opensource (which is understandable).

Adding CSG can also work, but IMO a CAD engine is far superior.

I'd love to start working on Drei and https://github.com/donalffons/opencascade.js. What about you guys.

promontis commented 2 years ago

Also interesting: https://github.com/donalffons/opencascade.js/discussions/84

looeee commented 2 years ago

Also it is a weak copyleft, so I don't see any issues here.

Ah, that seems ok. I wasn't aware of the difference between weak/strong copyleft - doing some reading now and it seems to mean all the stuff about derived work is irrelevant. Just need to include the license with any copies of the library which would happen automatically if it's installed through NPM.

In that case I withdraw all objections 😁 Fully in favor of exploring opencascade.js.

Adding CSG can also work, but IMO a CAD engine is far superior.

Totally agree, although it is more complex. A CSG component fits nicely into Drei, as a simple small component with a tiny API. A full CAD component would be more complex - might be better to host it in a separate repo.

promontis commented 2 years ago

@looeee you know a cool name for this separate repo? Talked to @gsimone and he said to start in our own repo first, and then we could move it to pmndrs.

promontis commented 2 years ago

Initial commit ... https://github.com/promontis/cad

Copied over most stuff from Drei and a bit from react-use-measure to get up to speed and have a similar code base

promontis commented 2 years ago

added you guys to the repo as maintainer... Maybe we can get something going for a couple of weeks and then move it to pmndrs?

looeee commented 2 years ago

Awesome! Thank you so much for getting the ball rolling 😍

Unfortunately between work and real life I don't have a lot of time for open source right now so I won't be able to help much in the next couple of months. I'll give feedback and do some testing though.

looeee commented 2 years ago

@looeee you know a cool name for this separate repo?

My first idea, although not very exciting, was react-cad. Turns out that already exists though and is also built on opencascade. I don't think they got that far with development though and there hasn't been any activity for some time. Still, might be worth scanning the repo for ideas?

As for an actual name, let me think about it. CSG libs often get called things like Chisel, Carve, Crunch, Chonk or whatever (ok I made the last two up). Maybe something like that?

ThreeDfish commented 2 years ago

Ah you're right. And guess what... it's using Evan Wallace's CSG.js, just converted to C++ 😆 That's cool though, means it would be easy to adapt to three.js.

https://github.com/IFCjs/web-ifc/blob/main/src/wasm/deps/csgjs-cpp/csgjs.h

@looeee How easy? Does that mean you could do it? For money? Am I correct to assume that this would be significantly more performant than current solutions?

Kinatzo commented 2 years ago

@looeee Could you give some examples when the existing three.js CSG libraries perform porly, and in which cases it would be ok to use.

My use case is making a round hole in a box. I'm considering if it's worth using a white cylinder to simulate the hole to improve performance instead of making an actual hole with csg:

image

Which option would be best if I only create the box and the hole once?

Which option would be best if I need to edit box parameters? With the white cylinder simulation I can just re-scale and re-position the mesh, with csg I would have to recreate it.

(Sorry if I am off topic!)

looeee commented 2 years ago

@Kinatzo probably better to ask this on the forum:

https://discourse.threejs.org/

jayPreak commented 10 months ago

So still theres no libraries to work on csg for union/intersection/separation functions?

isaac-mason commented 10 months ago

@jayPreak see https://github.com/pmndrs/react-three-csg and the lib that powers it https://github.com/gkjohnson/three-bvh-csg 🙂

jayPreak commented 10 months ago

@jayPreak see https://github.com/pmndrs/react-three-csg and the lib that powers it https://github.com/gkjohnson/three-bvh-csg 🙂

Thanks a lott!!