deadsy / sdfx

A simple CAD package using signed distance functions
MIT License
518 stars 52 forks source link

Rounded union results in a bump and a missing face #34

Open l29ah opened 3 years ago

l29ah commented 3 years ago

Probably related to https://github.com/Haskell-Things/ImplicitCAD/issues/204 except your implementation miscalculates the bounding box. Example code:

         box1 := sdf.Box2D(sdf.V2{10, 10}, 0)
         box2 := sdf.Box2D(sdf.V2{10, 20}, 0)
         box2 = sdf.Transform2D(box2, sdf.Translate2d(sdf.V2{10, 5}))
         uni2d := sdf.Union2D(box1, box2)
         uni2d.(*sdf.UnionSDF2).SetMin(sdf.RoundMin(10.0))
         uni := sdf.Extrude3D(uni2d, 1)
         render.RenderSTL(sdf.ScaleUniform3D(uni, shrink), 400, "test.stl")

Result: screenshot-messed

deadsy commented 3 years ago

In general the blending functions that can be used on a union (ie changing the underlying minimum function) can generate undesirable artifacts. E,g, if you try to fillet a union the surface can bump out on the opposite side. If those artifacts are outside the bounding box of the top level entity then you end up with a hole because only triangles within the bounding box are rendered.

The simple fix/work-around for this is to intersect the entity with a box that matches the bounding box of the entity. This cuts-off any artifacts outside of the bounding-box and gives you a clean render.

Example:

https://github.com/deadsy/sdfx/blob/7d6a54f01a9c16b2d3db17aeea5aa5ea6cf19af9/examples/cylinder_head/main.go#L371

Having said that it might me useful to have a function that takes an sdf and returns an sdf for the bounding box of that entity.

l29ah commented 3 years ago

Have you considered https://github.com/Haskell-Things/ImplicitCAD/issues/204#issuecomment-509653111 instead of trying to patch up the result after the damage is done?

l29ah commented 3 years ago

Meanwhile the bounding box hack won't work when the entity doesn't share a surface with the bounding box (when it's rotated for instance).

deadsy commented 3 years ago

The essential problem is that altering the min function to blend the two objects is a neat hack that doesn't really change the underlying geometry of the model. ie - you get what you get, and because it's a spatial field thing it may have an influence where you don't want it.

You don't have to use the BB to clean up the faces. You can use whatever you like. ie - some other box, surface, envelope- whatever. If you do an intersect it will cleanup the external faces and remove inadvertant bumps.

I'll grant you that the aesthetic appeal of doing this (from a coding sense) is not high. It feels hacky. However- building fillets as actual geometric objects is not trivial, indeed a principal motivation for writing this code was to generate filleted intersections without doing too much work.