BelfrySCAD / BOSL2

The Belfry OpenScad Library, v2.0. An OpenSCAD library of shapes, masks, and manipulators to make working with OpenSCAD easier. BETA
https://github.com/BelfrySCAD/BOSL2/wiki
BSD 2-Clause "Simplified" License
888 stars 109 forks source link

Speeding up creation of smooth 3d-polygons #568

Open numerys opened 3 years ago

numerys commented 3 years ago

When constructing objects like casings or similar it take a lots of time to construct smooth edges with Bezier.

I've found a closed source solution which offers a solution to speed up constructing smooth edges.

I tried any OpenScad library I've found but could not find one wich supports Bezier surfaces with user-defined boundaries.

Nevertheles I've found in BOSL2 the function fillet_path which looks like a 2D version of what the closed source solution does in 3D.

I would like to have such capability in OpenScad. I guess many users would greatly benefit.

numerys commented 3 years ago

I tested the function bezier_patch which is near the mentioned closed source solution. Could bezier_patch be used in the same manner?

revarbat commented 3 years ago

We don't have NURBS code, of course, but the same idea should be doable with bezier patches. The trick is the interface. The mentioned closed source solution has a GUI for selecting edges to form patches between. The demo video showed the creation of fairly complex sets of patches at once. So I see a couple levels of complexity here. First is to make a patch that curves between two-to-four other patches. Making multiple joined patches at once would be more complex, but it would allow extra control of transition curves.

numerys commented 3 years ago

Is it possible to create a smooth surface with a closed path of 3d bezier curves like in example 4-6 of this?

Or another approach could be to use 3d-planes instead of 2d-lines like here. Maybe there is just a small change to the existent 2d code needed?

adrianVmariano commented 3 years ago

What sort of objects are you trying to construct? What is your starting definition for the objects? The methods in rounding.scad aren't able to address your problem? Note that round_corners will do what fillet_path does but in 3d. And rounded_prism will create a variety of smoothed 3d objects. You can make rounded 3d objects with offset_sweep as well.

adrianVmariano commented 3 years ago

I took a look at the video. I think that a fully general solution as shown in xnurbs would be difficult. I spent quite a lot of time working out G2 continuity conditions and implementing them in bezier patches, but my existing solution can only handle a vertex with 3 edges, so it lacks generality. It also creates a lot of conditions that constrain the characteristics of the roundovers. I don't know if numerys wants to design a car side mirror as shown on the xnurbs site, or has less ambitious goals. I think rounded_prism is a pretty good solution but it doesn't handle the case of saddles, at least not directly. Maybe it could be done with a union of rounded prisms.

revarbat commented 3 years ago

I've thought on the design of bezier path construction functions for making patches. It requires the concept of what I've been calling bezier ribbons, which are basically contiguous sets of patches, much like how bezier paths are contiguous sets of bezier segments. I actually have stashed code for that. Even with that, though, defining ribbons with constructs similar to bez_tang(), etc, is still rather unintuitive and rather complex. You end up having a call that defines a point and 3 to 6 control-point vectors.

adrianVmariano commented 3 years ago

In the first xnurbs video the demo starts with rectangular faces and associates the edges to produce the shape. The rounded_prism module takes a strategy of starting with the polyhedron and replacing the edges with roundings, which is I would say rather analagous to what xnurbs does, but more limited because it has to be a a prism, and you can't create saddle shapes like the one in the demo. I could imagine a way of creating code to take polygons and connect the edges with beziers, but filling in the corners is hard to figure out in a general manner with this approach.

revarbat commented 3 years ago

It's relatively straightforward, given a pair of planes with known bounding edges, to generate a cubic patch to arc between two edges with control points that are tangential to the given planes. Joining two patches is perhaps even easier. If you have a third and/or fourth patch that shares corners with the first two, you can even make a patch that matches those edges as well. There's some leeway for placement of the middle patch points, but there are reasonable defaults that can make good curve results.

revarbat commented 3 years ago

Basically, attaching a patch to the side of one or more other patches is just a matter to matching the edge points, and then taking the tangent(s) as constraints for calculating where the middle control points are.

adrianVmariano commented 3 years ago

The thing is that you really want to be able to create G2 patches connecting the pair of starting planes, like they do in the xnurbs demo. You can do that with 4th order beziers like I do in rounding.scad, but creating a corner patch in the middle can be tricky. The corner interface can substantially constrain all the patches if you want to maintain G2 everywhere, and I only know how to do this for the case of 3 edges at a corner and I think maybe 4 edges at a corner. (I haven't done that but I think I know how.) For more edges I don't know what to do, because the patches only have four sides. Some sort of subdivision would be needed. One of the interesting things xnurbs allows is for you to vary the constraints, so to create a non-smooth joint in one place and G2 elsewhere. But for us to do that would be pretty messy, I think, unless a way can be found to make it into a sort of sequential process.

I mean, I really cool idea would be to have an arbitrary polyhedron smoother that crawls across a polyhedron and builds a bezier that rounds all its corners and edges, but it's hard to see how to do this generically without running into a lot of difficulties. Basically rounded_prism was my effort to do this as generically as I could. (If I recall correctly I was forced to have a uniform roundover at the top, for example, by the G2 requirement, so you can't vary the top roundover from edge to edge.)

revarbat commented 3 years ago

G2 (curvature continuity) is definitely nice, but it's not always necessary. For a lot of use cases, G1 (tangential continuity) is all that is needed or wanted, and can be handled adequately with cubic patches. G1 makes for relatively simple constraints. Doing full G2 can be handled later as we figure out how to.

adrianVmariano commented 3 years ago

Do you know how to make an arbitrary corner with G1 continuity, so like a polyhedron with 8 edges meeting at a point? If you know how to do that you could I assume make a generic polyhedron rounder that would take a VNF as input and produce a bezier output, or computed polyhedron output from the bezier, that rounds the edges. Of course, you want a polyhedron where the faces are intact, not triangulated.

The xnurbs example seemed to show G2 and G0, by the way. I think the idea was that you either want smooth, or you want a corner.

RonaldoCMP commented 3 years ago

Adrian is right if we restrict ourselves to rectangular and triangular Bezier patches. However, some development of these basic patches were done by box splines (that I have not studied yet) which allows to handle more general polygon shapes. I have done an experiment with the Kobbelt subdivision algorithm for triangulations with borders and got some promising (but not easy to get) results as seen in the following images.

[image: RoundedTip5pyramid_detail.PNG] [image: RoundedTip5pyramid.PNG]

Here is a rounding of the tip of a pentagonal pyramid. It has a clear G1 joint with the pyramid base at the blue line joint except at the vertices of the joint where the pyramid has no tangent plane. The Kobbelt subdivision method was applied to a triangulation of the pyramid top with some degenerate triangles artificially inserted at the pyramid edges. And that is the hard point of this strategy: to choose an appropriate triangulation to get the desired continuity result and border line. As far as I understand, the triangulation subdivision approaches a box spline as the number of iterations tends to infinity. In the cases displayed here, 5 iterations of the method were applied.

Em ter., 6 de jul. de 2021 às 20:07, adrianVmariano < @.***> escreveu:

Do you know how to make an arbitrary corner with G1 continuity, so like a polyhedron with 8 edges meeting at a point? If you know how to do that you could I assume make a generic polyhedron rounder that would take a VNF as input and produce a bezier output, or computed polyhedron output from the bezier, that rounds the edges. Of course, you want a polyhedron where the faces are intact, not triangulated.

The xnurbs example seemed to show G2 and G0, by the way. I think the idea was that you either want smooth, or you want a corner.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/revarbat/BOSL2/issues/568#issuecomment-875012573, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEYKSLNIJX3W7JJMLZFV2R3TWNIARANCNFSM46D3HB7Q .

adrianVmariano commented 3 years ago

I can't see the images.

RonaldoCMP commented 3 years ago

Here they are again:

RoundedTip5pyramid RoundedTip5pyramid_detail

adrianVmariano commented 3 years ago

Is the joint at the blue lines not G2? (Curvature zero for both?) It looks nice. Can you also produce a result where the edges are completely rounded? And how much control do you have over the amount of rounding?

RonaldoCMP commented 3 years ago

I cannot assure the joint is G2 but I bet it is for that particular example. Here is a version where the pyramid edges are also rounded:

Rounded5pyramid

The edge rounding has a cubic Bezier section. The base of the pyramid was built by skin from the border of the subdivided tip. Maybe it is possible to have some control on the tip rounding by changing the triangulation of the pyramid tip that is input to the subdivision algorithm. That is the tricky part of the strategy: to find an appropriate triangulation for the corner in order to get the devised result. For the image above, I used the following triangulation of the tip:

PyramidTipTriangulation

revarbat commented 3 years ago

To be honest, I had no intention of handling corners as such. That would be rather difficult, I think. What I'm thinking of just takes a pair of specified edges of two existing cubic patches, then creates a patch that has matching edges, and calculates the central control points from the tangential planes of the patch edges. This can either be for opposing edges of the new patch, or for adjacent edges, which adds more constraints from the intersection lines of the tangential edge planes.

adrianVmariano commented 3 years ago

If you don't handle corners then how do you actually use it to make something?

revarbat commented 3 years ago

I'm proposing a function to allow creation of patches to join two other patch edges. It's not a complete general solution, because we just don't yet know how to make a complete general solution. This lets you, say, make a boxy shape with rounded edges by first creating the flat face patches, then use this joiner to make patches that join the edges together. The corners, if they are the joining of 3 or 4 edges, can be done with this. More complex corners will need to be hand-coded.

revarbat commented 3 years ago

To clarify, the algorithm I have in my head will:

The main algorithm is to compute the tangential planes of the known edges at each edge control point, and to use constraints from adjacent pairs of edges to get the tangential vectors to the interior control points.

adrianVmariano commented 3 years ago

I'm not quite sure how you create the patches that underlie this. It seems like starting with the polyhedron and using that to define the patches is an easy strategy. And of course, that's what I do with rounded_prism. It's less powerful since it assumes you're starting with planar pieces, but if you knew how to make fancy curved patches you could just do that directly.

How much can you decouple the rounding for different corners? The biggest limitation of rounded_prism with its G2 curvature is that there is strong coupling, so I need to apply roundings in one of two ways, either by applying half-roundings to every face or, the way I actually did it, by rounding the top and bottom together and allowing the "sides" to be independent of each other. This gets confusing with a more general shape that doesn't have "sides". But the idea I had would be you specify parameters at each edge/corner for a polyhedron and then crawl the polyhedron and replace all the edges and corners with patches. And you issue an error if there are more than 4 edges at a vertex.

The next question is whether one of the methods that Ronaldo has worked on can handle this kind of situation, perhaps with more generality.

Another question: should we add a no_triangles option to vnf_vertex_array (and skin) so that you can create untriangulated shapes suitable for downstream processing?

RonaldoCMP commented 3 years ago

In principle, we could try to approach the rounding of any corner, whatever its valence, by quadrangular patches. It is enough to subdivide the corner topology similarly to the Catmull-Clark subdivision.

cc_subdiv

The corner would then be modeled by 3*V quadrangular patches where V is the corner valence. To have a given smoothness we need to impose a set of linear equations for each boundary between any pair of adjacent patches in a total of 9 equation sets per corner valence. The unknowns of those equations will be the control points of the patches. I don't know if such a linear system has a solution for any corner valence and boundary conditions, probably not. If it has many solutions, what would be expectable when some solution exists, we have a degree of freedom to define the surface shape.

The limit surface of Catmull-Clark subdivision method for any mesh without border may be represented as a bi-cubic B-spline that is C2 except at the "extraordinary points", those with a valence other than 4, where it is C1. So it is expectable that the linear system above should not impose a C2 condition at the extraordinary points.

I am working on the implementation of a C-C subdivision method byproduct that accepts meshes with borders and C0 and C1 boundary conditions at the mesh borders. As typical to subdivision methods, it produces successive refinements of the mesh that has a limit surface with the desired smoothness. I could not find any subdivision method that meet C2/G2 boundary conditions.

Despite their conceptual simplicity, subdivision methods are hard to implement. I am using my vnf extension (vnfe) of the vnf structure to operate on the incoming mesh and produce the output refinement of each iteration. Even so, the runtime is high. The great advantage of the subdivision methods is its generality. The limit surface of the methods for meshes with boundary conditions is not in general representable by Bezier/B-spline patches.

I don't believe that subdivision methods, due to their complexity, are appropriate to polyhedron corner roundings. Its generality is however able to handle the design of more complex circumstances like furcations.

furcation

(Extracted from an Adi Levin's paper)

RonaldoCMP commented 3 years ago

Thinking a little more about using subdivision for corner rounding, I realized that the mesh of an iterated C-C subdivision has a regularity that enables an implicit representation that exempts the use of VNF or VNFE to have all adjacency relations required by the method. That should reduce drastically the code complexity and provide a much better performance. Besides, I have found another Adi Levin's paper in http://multires.caltech.edu/pubs/sig00notes.pdf presenting another extension of the C-C method exactly for this purpose. The inputs for the method are the parametric curves at the borders and their cross-derivatives functions. For reasonable conditions on these boundary functions, it is proven that the limit surface is C2 except at the unique extraordinaire point, the descendant of the tip point of the corner, where it is C1.