Bevel V2 #98674

Open
opened 2022-06-08 17:05:32 +02:00 by Howard Trickey · 67 comments
Member

Bevel V2

I want to rewrite bevel in C++. Besides the change of language, there are these additional goals:

General

  • Be more specific about the specification of what bevel is supposed to do, given the years of experience we now have.
  • Design better data structures that are easier to understand (there may have been too much generality in the old data structures, before I knew exactly what patterns I would end up using).
  • Make an interface that gives Geometry Nodes more flexibility and control. Somehow let users directly specify the edges to be beveled rather than only by a pair of vertices (which has the limitation that sometimes it pulls in unintended edges).

Changed Algorithms

  • Maybe get rid of at least some of the square corner special cases.
  • Better approach to getting curvature continuity. Perhaps an optimization problem?
  • Redo UV adjustments in response to bevel to work in UV space directly instead of trying to find a position of a vertex in 3D space and a face to interpolate in and then hope interpolation does the right thing.

New Features

  • Overlap/Merge handling: when the bevel causes new edges to cross in the same plane, the result has shading artifacts and other bad properties. By merging and splitting edges, we can get the desired bevel without overlaps. This is a major, much requested feature. It is also very hard. In 2d, an algorithm like straight skeleton is a solution to this problem (look at the intermediate states before reaching the final straight skeleton. I have written a Blender Python addon that (imperfectly) applies this algorithm to the Inset problem. Trying to bring this same idea into 3d, however, appears very challenging.*Performance//
  • The current code has a lot of "iterate over the whole mesh" loops, and generally has not paid a lot of attention to performance. The rewrite should try to use the best performing algorithms, and multithreading if possible. Also, I should consider doing this all with Mesh data structures rather than BMesh. There are some adjacency relationships that will have to be discovered, but not as many as BMesh calculates.

Specification - Geometry

Geometry - Offset Lines

An edge that is adjacent to exactly two faces can be beveled. Beveling makes two offset edges parallel (in the normal case) to the original edge, in the two adjacent faces, and then removes the material in the faces between the offset edges and the original edge, and finally fills in the gap with one of

  • Flat face
  • An approximation, using n > 1 segments, of a curved surface that in the limit should have G1 (tangent) continuity (or G2 if possible). Currently, the cross-section of the surface can be some portion of an arc of a superellipse , with a superellipse parameter specifiable by the user. The spacing between the segments should be at equal arc lengths. Rather than the mathematically defined superellipse parameter, blender uses a value from 0 to 1, where 0 means a square completely inward profile; 1 means a square, completely outside profile; and 0.5 means a circular profile. These profiles are defined as they would be in a square corner. When the edges in Blender meet at other than 90°, the square version is transformed into the skewed square that fits into the angle.
  • Custom profile (as drawn by the user). If possible we should have an edge attribute that gives the orientation of non-symmetric profiles; in the absence of that, the orientation should be chosen to try to maximize consistency of orientations between adjacent beveled edges.

The distance of the offset edges from the original edge can be specified in a number of ways. In this picture:

offsetspec.png

the offset edges can be seen as the new edges in the right-hand picture. Some ways for users to specify the placement of those edges:

  • Offset (magenta line) - the distance each line moves on its respective face
  • Width (green line) - the distance across the newly made face between the two lines
  • Depth (yellow line) - the distance from the old edge to the new face, along the line that bisects the angle between the two faces
  • Percentage (percentage of pink line) - the distance moved along each face is a percentage of the edge along which the new edge endpoint slides
  • Constant radius (not shown) - the radius of a circle, perpendicular to the planes, that is pushed against the inside of both faces (so that they touch at two points of the circle, matching tangents to the touched planes; those two points are where the offset lines go). [This is not an option in the current Bevel, but has been a requested feature.]

Those are all global ways of specifying the bevel width. There is also, on the modifier, a per-edge weight that multiplies the above numbers. As we move to geometry nodes, we’d like to give more per-element control of bevel. One general possibility would be to give 4 offset values per edge (one per side, both ends) but that has the problem that with all of those degrees of freedom, there will be many situations where it is impossible to satisfy all the specs. We already have several situations that cause such spec conflicts (the “loop slide” feature, and the per-edge weights just mentioned). A cleaner spec would be to have only enough degrees of freedom that they can all be simultaneously satisfied and then have a separate preprocessing Node that makes all the compromises necessary to put it into the no-compromise-necessary form.

An alternative to specifying the offset lines, we can specify (angle, corner offset length) for face corner inserts. Suppose we are beveling edges e1 and e2, bounding face f, in the following picture, where c is a face corner. (In Geometry nodes, face corners don’t have directions; here we need the direction, so we may need a different “half edge” domain, or may just want to define that face corners have a defined outward edge associated with them.)

Screen Shot 2022-06-13 at 10.07.28 AM.png

If we give a specification of (angle=30°, length=0.5) then that specifies that this side of the bevel should look like this:

Screen Shot 2022-06-13 at 10.07.49 AM.png

Note that in the general case there might be other unbeveled edges between e1 and e2, and hence more faces than just f. The (angle, corner offset length) should behave as if those other edges are not there, and the corner of the face that is adjacent to e2 is one that rules this bevel side. The angle is also measured in the plane of that face. (A technicality: sometimes faces are non-planar; based on experience and past bug reports, it is best to use the cross product of the two adjacent edges to the corner in question as the “face normal”.) The (angle, offset length) specification is not user friendly; we expect that one of the edge-offset-oriented measures mentioned earlier will be the usual user interface and that those will be converted internally into this format. For geometry nodes, there might need to be some user conveniences, especially the ability to specify the angle as “the angle bisector between e1 and e2”, which is the angle that will give equal widths of the bevel from e1 and e2. Another thing to note is that the “loop slide” constraint will make use of the angle part of this spec, trivially, but will need an optimization problem solved to make the best compromise on the best corner offset length for each corner in connected loops.

It is currently not defined for Bevel to handle edges that have only one face attached, but the (angle, length) internal spec certainly allows for it. It also allows for tapered bevels, which has been a requested feature. We might want to think of UI ways for users to specify these features in Edit mode use of bevel.

Terminal edges (i.e., edges that are beveled and terminate at a vertex where no other edge is beveled) are special cases:

Screen Shot 2022-06-13 at 10.09.44 AM.png

We have one conceptually one face f adjacent to the corner, if we ignore unbeveled edges. But there have to be some unbeveled edges, since Blender doesn’t allow making faces like the above. So assume we have:

Screen Shot 2022-06-13 at 10.10.04 AM.png

We need to actually set two or three offset points at the terminal edge, forming one of these two bevel patterns:

Screen Shot 2022-06-13 at 10.11.12 AM.png

That is, we insert either two or three new vertices. The pattern on the right is the one that Bevel currently uses (except when there is exactly one face, out of plane, between the faces with c and d), but users might like the option of having the one on the left. Since there are at least two corners, we can use the first (d) and last (c) to place two of the new vertices. The last could be artificially set by a rule like: take the line joining the first two points, bisect it, make another line going up from the bisection point a set distance (perhaps the average of the two distances used for the adjacent two points). If there’s a third corner around (as there is in the above diagram, and usually will be), we could say that the one in the face just ccw from f2 is used to place the third point.

Geometry - Adjacent faces

In the easy case (and the only case, with the current Bevel), the faces that were adjacent to the beveled edge survive in a modified form: what remains are the parts of the faces that are not between the offset edges. (There also will be some material removed, and hence, adjustment to the original faces, at the vertices. See Vertex Mesh, below.)

However, the new “handle overlaps properly” functionality that we want to enable makes the question much more complicated: the offset lines may cross over other edge lines of the adjacent faces and eat into adjacent-to-adjacent faces. One case that is reasonably clear on how to handle is when the adjacent-to-adjacent faces (and still further adjacent faces) are coplanar with the adjacent faces and have sufficient extent to house the offset edges. E.g.:

bevelongrid.png

If we bevel the four selected edges and just ignore the fact that there are all sorts of other edges on the “floor”, we get:

bevelongrid2.png

Some faces will just get eaten away, while others will be left with irregular cuts taken out of them. If we just inset into the adjacent geometry regarded as one big face (well, in this case, a face with a hole in it), then afterwards intersect the outside edges of the bevel with all the existing edges on the floor, then throw away the stuff inside the bevel, we’ll get a pretty good result.

The general case will not have this nice coplanar set of adjacent faces. One thing to try: just flatten whatever we can onto a plane (before faces start to fold under), do a 2d inset then the intersection there, then transfer those intersections back to 3d. This may give some strange
distortions but is better than nothing. What happens if the inset goes outside the boundary of the faces that can be flattened? One choice is to just let that happen, then form new faces underneath to attach back to the outer boundary of the flattened plane. Another would be to implement some kind of clamping (but I was hoping to get away from that).

Geometry - Edge Mesh

Each original beveled edge gets removed and replaced by an edge mesh:

edgemesh.png

For an n-segment bevel, there will be n faces attached as shown. In the case where the offsets and angles are the same on each side at each end, the faces will be parallel to the original beveled edge. If you cut with a plane perpendicular (usually) to the original beveled edge, you get the profile. For non-custom profiles, the profile is specified with these parameters:

  • three points (arc beginning, arc middle, arc end)
  • superellipse parameter (in range 0 to 1)
  • number of segments
  • plane normal of plane to project on (may differ from the plane containing the three points)

The superellipse parameter and the number of segments determine what the profile looks like if the three points were (in the x,y plane): (1,0), (1,1), (0,1). E.g.:

Screen Shot 2022-06-13 at 10.16.43 AM.png

Then we can figure out the transform matrix that takes this pattern in the unit square into places where the edge-adjacent planes meet at a different angle, and have different sizes:

Screen Shot 2022-06-13 at 10.17.27 AM.png

Geometry - Vertex Mesh

When the beveled edges meet at or end at vertices, the profiles of the edges (flat, curved, or custom) need to be joined with a sensible vertex mesh construction. Leaving aside custom profiles for now, ta typical situation around a vertex looks like this:

pyr5.png

where there are three selected edges and two unselected ones at the vertex. Beveling the selected ones and cutting of the new bevels (let’s call those the edge meshes) where they meet at the vertex, we are left with a hole:

pyr5hole.png

This happens whenever there are 3 or more beveled edges meeting at a vertex. Notice how the unbeveled edges just attach to the inset vertex that is for the two beveled edges that are on either side of the unbeveled edge. As a matter of terminology, we call each newly created point that is the meeting point between the beveled edges a boundary point. Now, we need to fill the hole of, in this case, 3 boundary points, with what we call the vertex mesh.

vertexmesh.png

The above pattern doesn’t have a good name. I’ve been calling it the adj pattern (for adjacent pattern, I think), but am open to using a better name. It is what most 3D apps seemed to have settled on for this hole filling task. It has all quads except for possibly a center ngon (when the number of segments is odd). There seems to be no closed-form formulaic way of saying where the vertices go. The pattern is formed by putting a single vertex in the center, then performing a Catmull-Clark cubic subdivision some number of times. That will produce a pattern with a power-of-2 number of segments. To get some other number of segments, make the pattern with the next higher power of 2, then down-sample on the surface to get an even spacing with the desired number of segments. Where to put the center vertex is a bit of an art. It should be somewhere on the line that joins the original vertex to the average position of all of the boundary vertices. The fraction of the distance to move from the centroid to the original vertex is called the fullness. Current Blender has precalculated fullness values, dependent on the number of segments, that makes the vertex mesh most look like the octant of a sphere on a cube corner (when the profile value is 0.5, i.e., circular arc). For example, the fullness for a 2-segment profile is 0.559 and for a 10-segment profile it is 0.647.

Just doing the Catmull-Clark cubic subdivision to produce the adj-mesh has the problem that it moves the boundary vertices inward, which clearly doesn’t work for filling the hole, So an approach similar to Adi Levin’s [Filling N-sided holes by combined subdivision schemes ]] is used. However, we’ve had difficulty making using the math in that (and other Levin papers) to get the smoothness at the boundary where we’d like it. This may need some further research. Perhaps [ https:*www.researchgate.net/publication/4301214_A_Robust_Hole-Filling_Algorithm_for_Triangular_Mesh | this paper ’s technique to refine based on a Poisson equation with Direchlet boundary conditions can be used. Currently, Blender has special case code to do the adj-mesh for a cube corner, an attempt to make it smoother. It would be nice to avoid the need for special-casing cube corners in the new code. There is also special case code for the profile values 0 and 1 (square-in and square-out), which seems necessary to get good results for those cases. The special case code works on a cube corner, and then is transformed into the (possibly angled) corner that is needed.

A special case that is needed to avoid unsightly bulges is to handle cases like this, that I call pipe joints. If two of the edges coming in line up, as here:

pipeprebevel.png

then the vertex mesh needs to be as if the edge profile of the two lined-up edges continue across the vertex mesh:

pipepostbevel.png

To make this happen, the vertex mesh can be constructed as in the general case, but then it has to be snapped to the “pipe” profile.

Custom profiles are more difficult to make look good at the corners. One method is to use the same hole filling method as above (make an adj pattern, constrain the outer edges to the cut boundaries):

customvmesh.png

It does something, but is not very pleasing, usually. This is called the “Grid Fill” method in the current Blender interface for Custom Profile bevels. There is also the “Cutoff” method, which looks like this:

customcut.png

It is kind of like using profile shape 0 but only for the corner, not the boundaries.

Geometry - Miters

Miters are an additional option for the vertex meshes. For angles less than 180 degrees, we can replace the normal (sharp) miter:

sharpmiter.png

with an arc miter:

arcmiter.png

The effect here is as if we split the boundary point that is the meeting point between two successive boundary points into two, and then make an arc joining them in the plane of the two beveled edges, with the same number of segments as is being used for bevel generally. The shape of the arc is controlled by the same profile parameter that is used to specify the superellipse profile for edges. When the boundary point is split in two, the two vertices move along the nearest edge of the beveled edge mesh, away from their original meeting point. The amount that they move is called the spread, which is a user parameter.

Any unbeveled edges that were between the two beveled ones need to attach to on or the other of the now-split boundary edge. The choice is arbitrary, but try if there are an even number of them, it often looks good to attach half of them to the first boundary point, and half to the second.

If the beveled edges meet at an obtuse angle, there are two choices beyond the default sharp miter:

obtusesharp.png

with either an arc miter, formed the same was as for the non-obtuse angle case:

obtusearc.png

or a patch miter:

obtusepatch.png

A patch miter splits the original boundary point between two beveled edges into three boundary points, and makes two arcs: from the first to the second, and from the second to the third. For the patch miter, it usually looks best to attach the unbeveled in-between edges to the middle of the three boundary points for the miter.

There is a relation between miters and the pattern used for vertex-only bevels. If we are beveling the center vertex here:

vertexprebevel.png

then the pattern is that same as if we put a boundary vertex slid some direction along each edge out of that vertex, and then did what looks like the arc miter between those points:

vertexbevel.png

Above, we gave a method for specifying, per-between-bevel-edge-pair, the offset and angle of where the boundary point goes. Is there a way of extending that to deal with miters and maybe even vertex-only bevels? It seems that for edge bevels, we need two additional attributes per face corner, leading the complete set of attributes per face corner as:

  • angle
  • offset
  • miter type (enum: Sharp, Arc, Patch)
  • spread

For vertex-only bevels, the only parameter that matters is offset: the angle will always be zero and there is no mitering (though the pattern does look like an arc miter).

For custom profiles, it would be very convenient to add a fifth per face corner parameter:

  • profile direction (forward or reverse)

For now, leave the profile intersection type (grid vs cutoff) and profile pattern as globals for the whole bevel, not a per-face-corner thing.

Also for now, leave the superellipse parameter as a global, not a per face corner thing (though I could see it might be useful making it per-face-corner, let’s wait to see if users have a concrete use for it first).

Geometry - Cutting off the Edge meshes

Usually the edge meshes are cut off in a plane perpendicular to the beveled edge, leaving the hole to be filled, as specified above. However, there are two special cases.

First, if there is only one beveled edge attached to the vertex, it is terminated specially, as described above. A special-special case is the common one of the edge terminating with just one face between the two faces attached to the beveled edge. In that case, the edge mesh terminates on that third face (so the arc of its profile becomes part of that face).

Second, if there are only two beveled edges attached to a vertex, then we want to join the profiles together at the points where the individual edges of the edge mesh meet, like so:

edgemeet2.png

Though if the user specifies miters, then we are back in the case of, effectively, more than two boundary points, so use the regular hole filling mesh:

edgemeet2arc.png

(This may not be what a user would typically like; we could consider changing the spec of what happens here to be to use the same shaped arc, appropriately scaled, to join the ends. On the other hand, a user probably would not like to do the above without beveling the third vertical edge, taking us out of this special case.)

Materials and Custom Attributes (Notably: UVs)

The material of the original faces, even if cut up a bit, will of course be the same as their original materials. We need to specify what material gets assigned to each face in the edge meshes and edge face in the vertex meshes.

If the user specifies a Material Index of something other than -1, then all of the edge and vertex mesh faces use the material in the slot with the given index. For example, if the following cube is originally using a red material for all faces, but the Material Index is set to 1, and there is a green material index slot 1 (the second slot of the list of materials in the UI), then after bevel, the picture looks like this:

bevelmaterial.png

When there are edge attributes, such as “seam” and “crease”, the edges between the edge mesh and the old faces get the corresponding attribute copied. For instance, if the top two edges were a seam, then the resulting seams after bevel are shown here:

seambevel.png

It is not clear what should happen to bevel weights on edges. Right now all the edges of the edge mesh get some weight that is near to be less than the weight of the edge that was beveled.

A vertex value such as vertex crease is copied as is to all of the vertices that are in the corresponding vertex mesh. The value of a weight in a vertex group is similarly copied to all of the vertices in the vertex mesh.

The hardest thing to make work well is UV maps (and similar custom layers that use interpolation in faces -- the math layers). UV data is per face corner, and there can be multiple UV maps. While this isn’t explicitly specified in the UV data, there are implicit seams in the data: edges where at least one end has different UV values for the face corners on either side of the edge that vertex. Another important concept is that of a UV island -- an island consists of all the vertices in UV space that are connected in the graph sense (transitive connection).

For newly created vertices that are “inside” an old face, the BM_loop_interp_from_face
function can do a decent job of figuring out a UV value for that new vertex. But for vertices in edge meshes and face meshes, the question of what face a new vertex lies in is a bit ambiguous. This comes up most acutely for the central strips of edge and vertex meshes when there are an odd number of segments, and most importantly in those cases, the subcases where the vertices of a face straddle a seam. In that last case, if you interpolate UV data for a particular new face in different original edges that cross a seam, then you could create new UV edges in “unknown land” in UV space. Those UV edges in unknown land could cross other UV edges, and also could put faces in area where, say, a mapped image has no useful pixels. But even for other new vertices that don’t fall into those troublesome cross-seam cases, face interpolation still has another issue: the new vertices are usually not actually on the interpolation face, but rather hover somewhere over it in space. Projecting onto the face before interpolation can cause distortions -- e.g., you can have congruent strips in 3d space mapped into strips if different widths in UV space.

When deciding what to do about new faces that are on those odd-ssgment central strips, users expect “consistency” and “symmetry”, so that the when using the UV map for placing image-based material onto the beveled model, it doesn’t look haphazard. For instance, if there is a UV island whose boundary in UV space corresponds to edges in 3d space that are all beveled, you don’t want the central edges jumping back and forth between being on the island and not being on the island. The current Bevel code has tie breaking roles that makes these preferences of face to interpolate in, in order:

  • (Having found the connected components (islands) in UV space and arbitrarily assigned each a different “component id”) Choose the one with the lower component id.
  • If one face is selected and one is not, choose the selected one (this was an attempt to let users have some control over which way to choose).
    if faces have different material indices, choose the one with the lower material index.
  • Choose the face with the smaller z value of the face center
  • Choose the face with the smaller x value of the face center
  • Choose the face with the smaller y value of the face center

The current bevel has a lot of hard-to-get-right code trying to pick edges to snap to before interpolation (to try to minimize the distortion problems) and which face to interpolate in (to make a decision for the ambiguous center strip cases). Users still aren’t entirely happy with the results of relying on face interpolation. We should attempt to make the UVs for the new face corners directly in the 2d UV space, if that is possible.

Normals

In Blender, face corners can optionally have custom normals. For corners unaffected by bevel, any custom normals that were there before, should be there after.

If the user has specified harden normals, then custom normals are set in the face corners of the newly created edge meshes and faces meshes. They are set so that:
between two faces of an edge mesh, the normals match an average value of the two
between two faces of a vertex mesh, the normals match an average value of the two
between a face in a vertex mesh and one in an edge mesh, the normal of the vertex mesh corner should match that of the edge mesh corner
between a face in an edge mesh and one in a reconstructed original face, the normal of the edge mesh corner should match that of the reconstructed face corner.

Geometry - Output

It can be useful for other Nodes following bevel, and for addons, to be able to identify the edges that were newly created as a result of the bevel. Similarly for the faces (not counting the faces that were original but now may be cut up). There should be output attributes, boolean-valued, to identify new edges and new faces. In Edit mode bevel, these elements shall be selected after the bevel is done.

If the user has specified a face strength output, then values are set in the faceweight custom data layer: weak for faces in the vertex mesh, medium for faces in the edge mesh, and strong for the rest. (This layer can be used by a Weighted Normal modifier to achieve a similar effect on the custom normals as is achieved with the harden normals option to bevel.)

**Bevel V2** I want to rewrite bevel in C++. Besides the change of language, there are these additional goals: *General* - Be more specific about the specification of what bevel is supposed to do, given the years of experience we now have. - Design better data structures that are easier to understand (there may have been too much generality in the old data structures, before I knew exactly what patterns I would end up using). - Make an interface that gives Geometry Nodes more flexibility and control. Somehow let users directly specify the edges to be beveled rather than only by a pair of vertices (which has the limitation that sometimes it pulls in unintended edges). *Changed Algorithms* - Maybe get rid of at least some of the square corner special cases. - Better approach to getting curvature continuity. Perhaps an optimization problem? - Redo UV adjustments in response to bevel to work in UV space directly instead of trying to find a position of a vertex in 3D space and a face to interpolate in and then hope interpolation does the right thing. *New Features* - Overlap/Merge handling: when the bevel causes new edges to cross in the same plane, the result has shading artifacts and other bad properties. By merging and splitting edges, we can get the desired bevel without overlaps. This is a major, much requested feature. It is also very hard. In 2d, an algorithm like [straight skeleton ](https:*en.wikipedia.org/wiki/Straight_skeleton) is a solution to this problem (look at the intermediate states before reaching the final straight skeleton. I have written a Blender Python addon that (imperfectly) applies this algorithm to the Inset problem. Trying to bring this same idea into 3d, however, appears very challenging.*Performance// - The current code has a lot of "iterate over the whole mesh" loops, and generally has not paid a lot of attention to performance. The rewrite should try to use the best performing algorithms, and multithreading if possible. Also, I should consider doing this all with Mesh data structures rather than BMesh. There are some adjacency relationships that will have to be discovered, but not as many as BMesh calculates. **Specification - Geometry** *Geometry - Offset Lines* An edge that is adjacent to exactly two faces can be beveled. Beveling makes two offset edges parallel (in the normal case) to the original edge, in the two adjacent faces, and then removes the material in the faces between the offset edges and the original edge, and finally fills in the gap with one of - Flat face - An approximation, using n > 1 segments, of a curved surface that in the limit should have G1 (tangent) continuity (or G2 if possible). Currently, the cross-section of the surface can be some portion of an arc of a [superellipse ](https://en.wikipedia.org/wiki/Superellipse), with a superellipse parameter specifiable by the user. The spacing between the segments should be at equal arc lengths. Rather than the mathematically defined superellipse parameter, blender uses a value from 0 to 1, where 0 means a square completely inward profile; 1 means a square, completely outside profile; and 0.5 means a circular profile. These profiles are defined as they would be in a square corner. When the edges in Blender meet at other than 90°, the square version is transformed into the skewed square that fits into the angle. - Custom profile (as drawn by the user). If possible we should have an edge attribute that gives the orientation of non-symmetric profiles; in the absence of that, the orientation should be chosen to try to maximize consistency of orientations between adjacent beveled edges. The distance of the offset edges from the original edge can be specified in a number of ways. In this picture: ![offsetspec.png](https://archive.blender.org/developer/F13157022/offsetspec.png) the offset edges can be seen as the new edges in the right-hand picture. Some ways for users to specify the placement of those edges: - Offset (magenta line) - the distance each line moves on its respective face - Width (green line) - the distance across the newly made face between the two lines - Depth (yellow line) - the distance from the old edge to the new face, along the line that bisects the angle between the two faces - Percentage (percentage of pink line) - the distance moved along each face is a percentage of the edge along which the new edge endpoint slides - Constant radius (not shown) - the radius of a circle, perpendicular to the planes, that is pushed against the inside of both faces (so that they touch at two points of the circle, matching tangents to the touched planes; those two points are where the offset lines go). [This is not an option in the current Bevel, but has been a requested feature.] Those are all global ways of specifying the bevel width. There is also, on the modifier, a per-edge weight that multiplies the above numbers. As we move to geometry nodes, we’d like to give more per-element control of bevel. One general possibility would be to give 4 offset values per edge (one per side, both ends) but that has the problem that with all of those degrees of freedom, there will be many situations where it is impossible to satisfy all the specs. We already have several situations that cause such spec conflicts (the “loop slide” feature, and the per-edge weights just mentioned). A cleaner spec would be to have only enough degrees of freedom that they can all be simultaneously satisfied and then have a separate preprocessing Node that makes all the compromises necessary to put it into the no-compromise-necessary form. An alternative to specifying the offset lines, we can specify (angle, corner offset length) for face corner inserts. Suppose we are beveling edges e1 and e2, bounding face f, in the following picture, where c is a face corner. (In Geometry nodes, face corners don’t have directions; here we need the direction, so we may need a different “half edge” domain, or may just want to define that face corners have a defined outward edge associated with them.) ![Screen Shot 2022-06-13 at 10.07.28 AM.png](https://archive.blender.org/developer/F13157054/Screen_Shot_2022-06-13_at_10.07.28_AM.png) If we give a specification of (angle=30°, length=0.5) then that specifies that this side of the bevel should look like this: ![Screen Shot 2022-06-13 at 10.07.49 AM.png](https://archive.blender.org/developer/F13157056/Screen_Shot_2022-06-13_at_10.07.49_AM.png) Note that in the general case there might be other unbeveled edges between e1 and e2, and hence more faces than just f. The (angle, corner offset length) should behave as if those other edges are not there, and the corner of the face that is adjacent to e2 is one that rules this bevel side. The angle is also measured in the plane of that face. (A technicality: sometimes faces are non-planar; based on experience and past bug reports, it is best to use the cross product of the two adjacent edges to the corner in question as the “face normal”.) The (angle, offset length) specification is not user friendly; we expect that one of the edge-offset-oriented measures mentioned earlier will be the usual user interface and that those will be converted internally into this format. For geometry nodes, there might need to be some user conveniences, especially the ability to specify the angle as “the angle bisector between e1 and e2”, which is the angle that will give equal widths of the bevel from e1 and e2. Another thing to note is that the “loop slide” constraint will make use of the angle part of this spec, trivially, but will need an optimization problem solved to make the best compromise on the best corner offset length for each corner in connected loops. It is currently not defined for Bevel to handle edges that have only one face attached, but the (angle, length) internal spec certainly allows for it. It also allows for tapered bevels, which has been a requested feature. We might want to think of UI ways for users to specify these features in Edit mode use of bevel. Terminal edges (i.e., edges that are beveled and terminate at a vertex where no other edge is beveled) are special cases: ![Screen Shot 2022-06-13 at 10.09.44 AM.png](https://archive.blender.org/developer/F13157062/Screen_Shot_2022-06-13_at_10.09.44_AM.png) We have one conceptually one face f adjacent to the corner, if we ignore unbeveled edges. But there have to be some unbeveled edges, since Blender doesn’t allow making faces like the above. So assume we have: ![Screen Shot 2022-06-13 at 10.10.04 AM.png](https://archive.blender.org/developer/F13157064/Screen_Shot_2022-06-13_at_10.10.04_AM.png) We need to actually set two or three offset points at the terminal edge, forming one of these two bevel patterns: ![Screen Shot 2022-06-13 at 10.11.12 AM.png](https://archive.blender.org/developer/F13157066/Screen_Shot_2022-06-13_at_10.11.12_AM.png) That is, we insert either two or three new vertices. The pattern on the right is the one that Bevel currently uses (except when there is exactly one face, out of plane, between the faces with c and d), but users might like the option of having the one on the left. Since there are at least two corners, we can use the first (d) and last (c) to place two of the new vertices. The last could be artificially set by a rule like: take the line joining the first two points, bisect it, make another line going up from the bisection point a set distance (perhaps the average of the two distances used for the adjacent two points). If there’s a third corner around (as there is in the above diagram, and usually will be), we could say that the one in the face just ccw from f2 is used to place the third point. *Geometry - Adjacent faces* In the easy case (and the only case, with the current Bevel), the faces that were adjacent to the beveled edge survive in a modified form: what remains are the parts of the faces that are not between the offset edges. (There also will be some material removed, and hence, adjustment to the original faces, at the vertices. See Vertex Mesh, below.) However, the new “handle overlaps properly” functionality that we want to enable makes the question much more complicated: the offset lines may cross over other edge lines of the adjacent faces and eat into adjacent-to-adjacent faces. One case that is reasonably clear on how to handle is when the adjacent-to-adjacent faces (and still further adjacent faces) are coplanar with the adjacent faces and have sufficient extent to house the offset edges. E.g.: ![bevelongrid.png](https://archive.blender.org/developer/F13157069/bevelongrid.png) If we bevel the four selected edges and just ignore the fact that there are all sorts of other edges on the “floor”, we get: ![bevelongrid2.png](https://archive.blender.org/developer/F13157071/bevelongrid2.png) Some faces will just get eaten away, while others will be left with irregular cuts taken out of them. If we just inset into the adjacent geometry regarded as one big face (well, in this case, a face with a hole in it), then afterwards intersect the outside edges of the bevel with all the existing edges on the floor, then throw away the stuff inside the bevel, we’ll get a pretty good result. The general case will not have this nice coplanar set of adjacent faces. One thing to try: just flatten whatever we can onto a plane (before faces start to fold under), do a 2d inset then the intersection there, then transfer those intersections back to 3d. This may give some strange distortions but is better than nothing. What happens if the inset goes outside the boundary of the faces that can be flattened? One choice is to just let that happen, then form new faces underneath to attach back to the outer boundary of the flattened plane. Another would be to implement some kind of clamping (but I was hoping to get away from that). *Geometry - Edge Mesh* Each original beveled edge gets removed and replaced by an edge mesh: ![edgemesh.png](https://archive.blender.org/developer/F13157074/edgemesh.png) For an n-segment bevel, there will be n faces attached as shown. In the case where the offsets and angles are the same on each side at each end, the faces will be parallel to the original beveled edge. If you cut with a plane perpendicular (usually) to the original beveled edge, you get the profile. For non-custom profiles, the profile is specified with these parameters: - three points (arc beginning, arc middle, arc end) - superellipse parameter (in range 0 to 1) - number of segments - plane normal of plane to project on (may differ from the plane containing the three points) The superellipse parameter and the number of segments determine what the profile looks like if the three points were (in the x,y plane): (1,0), (1,1), (0,1). E.g.: ![Screen Shot 2022-06-13 at 10.16.43 AM.png](https://archive.blender.org/developer/F13157080/Screen_Shot_2022-06-13_at_10.16.43_AM.png) Then we can figure out the transform matrix that takes this pattern in the unit square into places where the edge-adjacent planes meet at a different angle, and have different sizes: ![Screen Shot 2022-06-13 at 10.17.27 AM.png](https://archive.blender.org/developer/F13157086/Screen_Shot_2022-06-13_at_10.17.27_AM.png) *Geometry - Vertex Mesh* When the beveled edges meet at or end at vertices, the profiles of the edges (flat, curved, or custom) need to be joined with a sensible vertex mesh construction. Leaving aside custom profiles for now, ta typical situation around a vertex looks like this: ![pyr5.png](https://archive.blender.org/developer/F13157089/pyr5.png) where there are three selected edges and two unselected ones at the vertex. Beveling the selected ones and cutting of the new bevels (let’s call those the edge meshes) where they meet at the vertex, we are left with a hole: ![pyr5hole.png](https://archive.blender.org/developer/F13157092/pyr5hole.png) This happens whenever there are 3 or more beveled edges meeting at a vertex. Notice how the unbeveled edges just attach to the inset vertex that is for the two beveled edges that are on either side of the unbeveled edge. As a matter of terminology, we call each newly created point that is the meeting point between the beveled edges a boundary point. Now, we need to fill the hole of, in this case, 3 boundary points, with what we call the vertex mesh. ![vertexmesh.png](https://archive.blender.org/developer/F13157095/vertexmesh.png) The above pattern doesn’t have a good name. I’ve been calling it the adj pattern (for adjacent pattern, I think), but am open to using a better name. It is what most 3D apps seemed to have settled on for this hole filling task. It has all quads except for possibly a center ngon (when the number of segments is odd). There seems to be no closed-form formulaic way of saying where the vertices go. The pattern is formed by putting a single vertex in the center, then performing a Catmull-Clark cubic subdivision some number of times. That will produce a pattern with a power-of-2 number of segments. To get some other number of segments, make the pattern with the next higher power of 2, then down-sample on the surface to get an even spacing with the desired number of segments. Where to put the center vertex is a bit of an art. It should be somewhere on the line that joins the original vertex to the average position of all of the boundary vertices. The fraction of the distance to move from the centroid to the original vertex is called the fullness. Current Blender has precalculated fullness values, dependent on the number of segments, that makes the vertex mesh most look like the octant of a sphere on a cube corner (when the profile value is 0.5, i.e., circular arc). For example, the fullness for a 2-segment profile is 0.559 and for a 10-segment profile it is 0.647. Just doing the Catmull-Clark cubic subdivision to produce the adj-mesh has the problem that it moves the boundary vertices inward, which clearly doesn’t work for filling the hole, So an approach similar to Adi Levin’s [Filling N-sided holes by combined subdivision schemes ]] is used. However, we’ve had difficulty making using the math in that (and other Levin papers) to get the smoothness at the boundary where we’d like it. This may need some further research. Perhaps [[ https:*www.researchgate.net/publication/4301214_A_Robust_Hole-Filling_Algorithm_for_Triangular_Mesh | this paper ](http:*www.math.tau.ac.il/~levin/adi/paper8.htm)’s technique to refine based on a Poisson equation with Direchlet boundary conditions can be used. Currently, Blender has special case code to do the adj-mesh for a cube corner, an attempt to make it smoother. It would be nice to avoid the need for special-casing cube corners in the new code. There is also special case code for the profile values 0 and 1 (square-in and square-out), which seems necessary to get good results for those cases. The special case code works on a cube corner, and then is transformed into the (possibly angled) corner that is needed. A special case that is needed to avoid unsightly bulges is to handle cases like this, that I call pipe joints. If two of the edges coming in line up, as here: ![pipeprebevel.png](https://archive.blender.org/developer/F13157099/pipeprebevel.png) then the vertex mesh needs to be as if the edge profile of the two lined-up edges continue across the vertex mesh: ![pipepostbevel.png](https://archive.blender.org/developer/F13157102/pipepostbevel.png) To make this happen, the vertex mesh can be constructed as in the general case, but then it has to be snapped to the “pipe” profile. Custom profiles are more difficult to make look good at the corners. One method is to use the same hole filling method as above (make an adj pattern, constrain the outer edges to the cut boundaries): ![customvmesh.png](https://archive.blender.org/developer/F13157105/customvmesh.png) It does something, but is not very pleasing, usually. This is called the “Grid Fill” method in the current Blender interface for Custom Profile bevels. There is also the “Cutoff” method, which looks like this: ![customcut.png](https://archive.blender.org/developer/F13157107/customcut.png) It is kind of like using profile shape 0 but only for the corner, not the boundaries. *Geometry - Miters* Miters are an additional option for the vertex meshes. For angles less than 180 degrees, we can replace the normal (sharp) miter: ![sharpmiter.png](https://archive.blender.org/developer/F13157111/sharpmiter.png) with an arc miter: ![arcmiter.png](https://archive.blender.org/developer/F13157115/arcmiter.png) The effect here is as if we split the boundary point that is the meeting point between two successive boundary points into two, and then make an arc joining them in the plane of the two beveled edges, with the same number of segments as is being used for bevel generally. The shape of the arc is controlled by the same profile parameter that is used to specify the superellipse profile for edges. When the boundary point is split in two, the two vertices move along the nearest edge of the beveled edge mesh, away from their original meeting point. The amount that they move is called the spread, which is a user parameter. Any unbeveled edges that were between the two beveled ones need to attach to on or the other of the now-split boundary edge. The choice is arbitrary, but try if there are an even number of them, it often looks good to attach half of them to the first boundary point, and half to the second. If the beveled edges meet at an obtuse angle, there are two choices beyond the default sharp miter: ![obtusesharp.png](https://archive.blender.org/developer/F13157118/obtusesharp.png) with either an arc miter, formed the same was as for the non-obtuse angle case: ![obtusearc.png](https://archive.blender.org/developer/F13157125/obtusearc.png) or a patch miter: ![obtusepatch.png](https://archive.blender.org/developer/F13157127/obtusepatch.png) A patch miter splits the original boundary point between two beveled edges into three boundary points, and makes two arcs: from the first to the second, and from the second to the third. For the patch miter, it usually looks best to attach the unbeveled in-between edges to the middle of the three boundary points for the miter. There is a relation between miters and the pattern used for vertex-only bevels. If we are beveling the center vertex here: ![vertexprebevel.png](https://archive.blender.org/developer/F13157139/vertexprebevel.png) then the pattern is that same as if we put a boundary vertex slid some direction along each edge out of that vertex, and then did what looks like the arc miter between those points: ![vertexbevel.png](https://archive.blender.org/developer/F13157143/vertexbevel.png) Above, we gave a method for specifying, per-between-bevel-edge-pair, the offset and angle of where the boundary point goes. Is there a way of extending that to deal with miters and maybe even vertex-only bevels? It seems that for edge bevels, we need two additional attributes per face corner, leading the complete set of attributes per face corner as: - angle - offset - miter type (enum: Sharp, Arc, Patch) - spread For vertex-only bevels, the only parameter that matters is offset: the angle will always be zero and there is no mitering (though the pattern does look like an arc miter). For custom profiles, it would be very convenient to add a fifth per face corner parameter: - profile direction (forward or reverse) For now, leave the profile intersection type (grid vs cutoff) and profile pattern as globals for the whole bevel, not a per-face-corner thing. Also for now, leave the superellipse parameter as a global, not a per face corner thing (though I could see it might be useful making it per-face-corner, let’s wait to see if users have a concrete use for it first). *Geometry - Cutting off the Edge meshes* Usually the edge meshes are cut off in a plane perpendicular to the beveled edge, leaving the hole to be filled, as specified above. However, there are two special cases. First, if there is only one beveled edge attached to the vertex, it is terminated specially, as described above. A special-special case is the common one of the edge terminating with just one face between the two faces attached to the beveled edge. In that case, the edge mesh terminates on that third face (so the arc of its profile becomes part of that face). Second, if there are only two beveled edges attached to a vertex, then we want to join the profiles together at the points where the individual edges of the edge mesh meet, like so: ![edgemeet2.png](https://archive.blender.org/developer/F13157152/edgemeet2.png) Though if the user specifies miters, then we are back in the case of, effectively, more than two boundary points, so use the regular hole filling mesh: ![edgemeet2arc.png](https://archive.blender.org/developer/F13157154/edgemeet2arc.png) (This may not be what a user would typically like; we could consider changing the spec of what happens here to be to use the same shaped arc, appropriately scaled, to join the ends. On the other hand, a user probably would not like to do the above without beveling the third vertical edge, taking us out of this special case.) *Materials and Custom Attributes (Notably: UVs)* The material of the original faces, even if cut up a bit, will of course be the same as their original materials. We need to specify what material gets assigned to each face in the edge meshes and edge face in the vertex meshes. If the user specifies a Material Index of something other than -1, then all of the edge and vertex mesh faces use the material in the slot with the given index. For example, if the following cube is originally using a red material for all faces, but the Material Index is set to 1, and there is a green material index slot 1 (the second slot of the list of materials in the UI), then after bevel, the picture looks like this: ![bevelmaterial.png](https://archive.blender.org/developer/F13157165/bevelmaterial.png) When there are edge attributes, such as “seam” and “crease”, the edges between the edge mesh and the old faces get the corresponding attribute copied. For instance, if the top two edges were a seam, then the resulting seams after bevel are shown here: ![seambevel.png](https://archive.blender.org/developer/F13157168/seambevel.png) It is not clear what should happen to bevel weights on edges. Right now all the edges of the edge mesh get some weight that is near to be less than the weight of the edge that was beveled. A vertex value such as vertex crease is copied as is to all of the vertices that are in the corresponding vertex mesh. The value of a weight in a vertex group is similarly copied to all of the vertices in the vertex mesh. The hardest thing to make work well is UV maps (and similar custom layers that use interpolation in faces -- the math layers). UV data is per face corner, and there can be multiple UV maps. While this isn’t explicitly specified in the UV data, there are implicit seams in the data: edges where at least one end has different UV values for the face corners on either side of the edge that vertex. Another important concept is that of a UV island -- an island consists of all the vertices in UV space that are connected in the graph sense (transitive connection). For newly created vertices that are “inside” an old face, the BM_loop_interp_from_face function can do a decent job of figuring out a UV value for that new vertex. But for vertices in edge meshes and face meshes, the question of what face a new vertex lies in is a bit ambiguous. This comes up most acutely for the central strips of edge and vertex meshes when there are an odd number of segments, and most importantly in those cases, the subcases where the vertices of a face straddle a seam. In that last case, if you interpolate UV data for a particular new face in different original edges that cross a seam, then you could create new UV edges in “unknown land” in UV space. Those UV edges in unknown land could cross other UV edges, and also could put faces in area where, say, a mapped image has no useful pixels. But even for other new vertices that don’t fall into those troublesome cross-seam cases, face interpolation still has another issue: the new vertices are usually not actually on the interpolation face, but rather hover somewhere over it in space. Projecting onto the face before interpolation can cause distortions -- e.g., you can have congruent strips in 3d space mapped into strips if different widths in UV space. When deciding what to do about new faces that are on those odd-ssgment central strips, users expect “consistency” and “symmetry”, so that the when using the UV map for placing image-based material onto the beveled model, it doesn’t look haphazard. For instance, if there is a UV island whose boundary in UV space corresponds to edges in 3d space that are all beveled, you don’t want the central edges jumping back and forth between being on the island and not being on the island. The current Bevel code has tie breaking roles that makes these preferences of face to interpolate in, in order: - (Having found the connected components (islands) in UV space and arbitrarily assigned each a different “component id”) Choose the one with the lower component id. - If one face is selected and one is not, choose the selected one (this was an attempt to let users have some control over which way to choose). if faces have different material indices, choose the one with the lower material index. - Choose the face with the smaller z value of the face center - Choose the face with the smaller x value of the face center - Choose the face with the smaller y value of the face center The current bevel has a lot of hard-to-get-right code trying to pick edges to snap to before interpolation (to try to minimize the distortion problems) and which face to interpolate in (to make a decision for the ambiguous center strip cases). Users still aren’t entirely happy with the results of relying on face interpolation. We should attempt to make the UVs for the new face corners directly in the 2d UV space, if that is possible. *Normals* In Blender, face corners can optionally have custom normals. For corners unaffected by bevel, any custom normals that were there before, should be there after. If the user has specified harden normals, then custom normals are set in the face corners of the newly created edge meshes and faces meshes. They are set so that: between two faces of an edge mesh, the normals match an average value of the two between two faces of a vertex mesh, the normals match an average value of the two between a face in a vertex mesh and one in an edge mesh, the normal of the vertex mesh corner should match that of the edge mesh corner between a face in an edge mesh and one in a reconstructed original face, the normal of the edge mesh corner should match that of the reconstructed face corner. Geometry - Output It can be useful for other Nodes following bevel, and for addons, to be able to identify the edges that were newly created as a result of the bevel. Similarly for the faces (not counting the faces that were original but now may be cut up). There should be output attributes, boolean-valued, to identify new edges and new faces. In Edit mode bevel, these elements shall be selected after the bevel is done. If the user has specified a face strength output, then values are set in the faceweight custom data layer: weak for faces in the vertex mesh, medium for faces in the edge mesh, and strong for the rest. (This layer can be used by a Weighted Normal modifier to achieve a similar effect on the custom normals as is achieved with the harden normals option to bevel.)
Howard Trickey self-assigned this 2022-06-08 17:05:32 +02:00
Author
Member

Changed status from 'Needs Triage' to: 'Confirmed'

Changed status from 'Needs Triage' to: 'Confirmed'
Author
Member

Added subscribers: @howardt, @HooglyBoogly, @HDMaster84

Added subscribers: @howardt, @HooglyBoogly, @HDMaster84

Added subscriber: @JanErik

Added subscriber: @JanErik

Added subscriber: @mod_moder

Added subscriber: @mod_moder

Added subscriber: @NahuelBelich

Added subscriber: @NahuelBelich

Added subscriber: @TheRedWaxPolice

Added subscriber: @TheRedWaxPolice

Cool stuff..
I hope you consider adding an option for face beveling in this Bevel V2... 👍

Cool stuff.. I hope you consider adding an option for face beveling in this Bevel V2... 👍
Howard Trickey removed their assignment 2022-06-09 13:19:51 +02:00
Author
Member

Face beveling is pretty much just Inset, right? Is the reason you want this because you want it in a modifier? Or are there edge-bevel options that you would like that aren't in Inset?
I could consider adding Face beveling, but feel we would then have to do something about the big overlap in functionality between Inset and Bevel.

Face beveling is pretty much just Inset, right? Is the reason you want this because you want it in a modifier? Or are there edge-bevel options that you would like that aren't in Inset? I could consider adding Face beveling, but feel we would then have to do something about the big overlap in functionality between Inset and Bevel.

Added subscriber: @costa

Added subscriber: @costa

Sounds very exciting Howard especially the curvature continuity I wonder how it will be tackled,
I was wondering if the long awaited feature of having edge groups to have different sets of bevel will arrive with this?
Perhaps having an option to limit bevel by attributes and then attribute's domain is edge.

Sounds very exciting Howard especially the curvature continuity I wonder how it will be tackled, I was wondering if the long awaited feature of having edge groups to have different sets of bevel will arrive with this? Perhaps having an option to limit bevel by attributes and then attribute's domain is edge.

In #98674#1371474, @howardt wrote:
Face beveling is pretty much just Inset, right? Is the reason you want this because you want it in a modifier? Or are there edge-bevel options that you would like that aren't in Inset?
I could consider adding Face beveling, but feel we would then have to do something about the big overlap in functionality between Inset and Bevel.

It's a little bit more than just inset though.
In addition of parameters like "Thickness/Depth/Individual", if it was part of the bevel tool, we would also be able to add segments, adjust the profile shape, the angle, use as a modifier etc. Those alone would make the overlap go away since it can't be achieved using regular edge beveling or just inset...

Also, people usually expect face beveling to be part of the bevel tool, not the inset, so I think it would make more sense and be more intuitive if it was part of it.

> In #98674#1371474, @howardt wrote: > Face beveling is pretty much just Inset, right? Is the reason you want this because you want it in a modifier? Or are there edge-bevel options that you would like that aren't in Inset? > I could consider adding Face beveling, but feel we would then have to do something about the big overlap in functionality between Inset and Bevel. It's a little bit more than just inset though. In addition of parameters like "Thickness/Depth/Individual", if it was part of the bevel tool, we would also be able to add segments, adjust the profile shape, the angle, use as a modifier etc. Those alone would make the overlap go away since it can't be achieved using regular edge beveling or just inset... Also, people usually expect face beveling to be part of the bevel tool, not the inset, so I think it would make more sense and be more intuitive if it was part of it.

Added subscriber: @Igrom

Added subscriber: @Igrom

Added subscriber: @jc4d

Added subscriber: @jc4d

Added subscriber: @ThinkingPolygons

Added subscriber: @ThinkingPolygons

+1 for face beveling

+1 for face beveling

Added subscriber: @Dangry

Added subscriber: @Dangry

Added subscriber: @MACHIN3

Added subscriber: @MACHIN3

Added subscriber: @Zuorion-4

Added subscriber: @Zuorion-4

Added subscriber: @Format64

Added subscriber: @Format64

I wrote about current mark sharp / seam bevel options being very different from edit mode mark sharp / seam commands on RCS . What do you think about renaming them into "propagate along" or something else? Should this setting even be exposed to user? Are interrupted seams / sharps on some corners even desired?

I wrote about current mark sharp / seam bevel options being very different from edit mode mark sharp / seam commands on [RCS ](https://blender.community/c/rightclickselect/E08g/?sorting=hot). What do you think about renaming them into "propagate along" or something else? Should this setting even be exposed to user? Are interrupted seams / sharps on some corners even desired?
Member

Thanks for the detailed design task @howardt. I have some thoughts which I'll list here.

  • Cutoff method
    I have personally rarely seem this used. It doesn't really mirror anything that happens in real life. It might be fine to just remove this in the new code, especially if there is a general focus on improving curvature continuity.
  • Mesh vs. BMesh
    There is definitely a valid tradeoff here. Mesh is not as well suited as BMesh to small consecutive changes in edit mode. However, I think Mesh would be the better choice.
    It interfaces better with geometry nodes (and better with C++ data structures in general). Mesh allows for better performance in a procedural context where performance can really help. Often a mesh is almost completely rebuilt by Bevel anyway.
  • Geometry Node
    I would recommend only creating a node rather than adjusting the modifier as well. The modifier can be kept around, allowing easier iteration for a node, since the modifier's functionality doesn't have to be replaced directly.
    This would mean that the design wouldn't have to be compromised to support the modifier workflow as well. It also aligns well with the general goal of replacing modifiers with builtin node group presets.
  • Attribute API
    Recently the attribute API has been becoming the standard way of interacting with geometry data layers. As opposed to working with the CustomData API, using the attribute API (BKE_attribute.hh) gives access to basic data arrays, leading to better performance / lower overhead.
    Making code that deals with a single attribute at a time generally makes it more readable as well. This has some limitations that will be resolved in the future. For example, editing generic attributes in edit mode hasn't been properly implemented yet, and the attribute API mainly just interacts with generic attributes.
  • Attribute/Field Outputs
    For greater flexibility, I think the node should output a selection of the new faces rather than using it to set various data internally. For example, the node doesn't have to adjust materials at all, because that can be accomplished with a "Set Material" node afterwards.
    *** This is easier to explain and has the benefit of not relying on material indices, which can be problematic in a procedural context.
  • Custom Profile
    It would be interesting to consider not using a superellipse parameter and only supporting curve profile inputs. The superellipse curve could be generated by a separate node. This has the benefit of reducing the redundancy and surface area of the algorithm's inputs.
  • Face Weights
    The "harden normals" workflow including setting face weights strikes me as something that could be accomplished more generically. #93551 describes how we imagined the custom normal workflow would work in geometry nodes. I'm not sure bevel has to implement any of this itself.
Thanks for the detailed design task @howardt. I have some thoughts which I'll list here. * **Cutoff method** **I have personally rarely seem this used. It doesn't really mirror anything that happens in real life.** It might be fine to just remove this in the new code, especially if there is a general focus on improving curvature continuity. * **Mesh vs. BMesh** **There is definitely a valid tradeoff here. `Mesh` is not as well suited as `BMesh` to small consecutive changes in edit mode.** However, I think `Mesh` would be the better choice. ***It interfaces better with geometry nodes (and better with C++ data structures in general).*** `Mesh` allows for better performance in a procedural context where performance can really help. Often a mesh is almost completely rebuilt by Bevel anyway. * **Geometry Node** **I would recommend only creating a node rather than adjusting the modifier as well.** The modifier can be kept around, allowing easier iteration for a node, since the modifier's functionality doesn't have to be replaced directly. **This would mean that the design wouldn't have to be compromised to support the modifier workflow as well.** It also aligns well with the general goal of replacing modifiers with builtin node group presets. * **Attribute API** **Recently the attribute API has been becoming the standard way of interacting with geometry data layers.** As opposed to working with the `CustomData` API, using the attribute API (`BKE_attribute.hh`) gives access to basic data arrays, leading to better performance / lower overhead. **Making code that deals with a single attribute at a time generally makes it more readable as well.** This has some limitations that will be resolved in the future. For example, editing generic attributes in edit mode hasn't been properly implemented yet, and the attribute API mainly just interacts with generic attributes. * **Attribute/Field Outputs** **For greater flexibility, I think the node should output a selection of the new faces rather than using it to set various data internally.** For example, the node doesn't have to adjust materials at all, because that can be accomplished with a "Set Material" node afterwards. *** This is easier to explain and has the benefit of not relying on material indices, which can be problematic in a procedural context. * **Custom Profile** **It would be interesting to consider not using a superellipse parameter and only supporting curve profile inputs. The superellipse curve could be generated by a separate node.** This has the benefit of reducing the redundancy and surface area of the algorithm's inputs. * **Face Weights** **The "harden normals" workflow including setting face weights strikes me as something that could be accomplished more generically.** #93551 describes how we imagined the custom normal workflow would work in geometry nodes. I'm not sure bevel has to implement any of this itself.
Member

Added subscriber: @lichtwerk

Added subscriber: @lichtwerk
Member

Geometry - Adjacent faces

In the easy case (and the only case, with the current Bevel), the faces that were adjacent to the beveled edge survive in a modified form: what remains are the parts of the faces that are not between the offset edges. (There also will be some material removed, and hence, adjustment to the original faces, at the vertices. See Vertex Mesh, below.)

However, the new “handle overlaps properly” functionality that we want to enable makes the question much more complicated: the offset lines may cross over other edge lines of the adjacent faces and eat into adjacent-to-adjacent faces. One case that is reasonably clear on how to handle is when the adjacent-to-adjacent faces (and still further adjacent faces) are coplanar with the adjacent faces and have sufficient extent to house the offset edges. E.g.:

I am not deep into this, but would generating a tube around "to-be-beveled" edges work that are just booled/cut away and then remaining geometry connected (this can get messy on the "connecting" areas, but not sure if there is a way around?)
Something in the spirit of:

> Geometry - Adjacent faces > > In the easy case (and the only case, with the current Bevel), the faces that were adjacent to the beveled edge survive in a modified form: what remains are the parts of the faces that are not between the offset edges. (There also will be some material removed, and hence, adjustment to the original faces, at the vertices. See Vertex Mesh, below.) > > However, the new “handle overlaps properly” functionality that we want to enable makes the question much more complicated: the offset lines may cross over other edge lines of the adjacent faces and eat into adjacent-to-adjacent faces. One case that is reasonably clear on how to handle is when the adjacent-to-adjacent faces (and still further adjacent faces) are coplanar with the adjacent faces and have sufficient extent to house the offset edges. E.g.: I am not deep into this, but would generating a tube around "to-be-beveled" edges work that are just booled/cut away and then remaining geometry connected (this can get messy on the "connecting" areas, but not sure if there is a way around?) Something in the spirit of: - https://blenderartists.org/t/wip-bevel-after-boolean/693072/ - https://blenderartists.org/t/mesh-fushion-bevel-boolean-fuse-blender-solution/693512 or refering to [D15151: Geometry Nodes: add 'Intersecting Edges' output for boolean node](https://archive.blender.org/developer/D15151)
Author
Member

Thanks, Vitalii, Hans, and Philip for your comments.

Vitalii: I had forgotten the "Mark Seam" and "Mark Sharp" options while writing the spec above. I agree with you that we should just make that (propagation, to give it a better name) always happen. I'd rather not add an option to "Mark Seam" and "Mark Sharp", in the spirit of what Hans said about moving to a philosophy of having bevel just output "what changed" and letting later nodes do things with those changed things. In order to get the effect you want, we probably need to not just say "these are the new edges", but also "these are the new edges that are at the boundary between new and old faces".

Hans:

  • I agree, let's do this in Mesh, not BMesh. Is there common code somewhere for analyzing adjacencies in Mesh? I can do it myself -- I already did some things like that in Boolean -- but wonder whether some common, parallelized code has been / should be developed. Do you have a good example of an existing Geometry Node that I could study to give me an idea of how to implement this new node? Something that takes in some vertex/edge/face corner attributes and does something to the geometry because of those attributes?
  • Good idea to leave the existing code as is for quite a while, concentrating on the new node that then doesn't have to exactly replicate the old behavior.
  • Attribute API: thanks for the pointer, I'll be sure to study it. Any good examples of its use that you recommend I look at?
  • Attribute/Field outputs: I agree, let's give enough "These are what changed and how" attributes as outputs and let further manipulations like setting materials, setting face weights or hardening normals happen outside the node.
  • Custom profile always: interesting idea. I think the code needs profiles for both n-segments and power-of-two-greater-than-or-equal-to-n-segments, if I recall correctly, and this may complicate things a bit. Also, doesn't it kind of make the node useless without an extra node attached to the input to generate the profile? What would be the default if nothing is attached to that input? A flat segment?

On the subject of extra nodes needed to make the node useful: I've been second-guessing myself as to whether the idea of using (angle, offset) per face corner is the right input to this geometry node. While general enough to do anything, and not providing too many constraints (overconstrainig, in other words), it seems very awkward to use "raw". It would almost certainly require another node to take user-friendly specs (like: "constant offset width") into that form. Do we really want to design nodes that are only practically useful when combined with other preprocessing nodes?

Thanks, Vitalii, Hans, and Philip for your comments. Vitalii: I had forgotten the "Mark Seam" and "Mark Sharp" options while writing the spec above. I agree with you that we should just make that (propagation, to give it a better name) always happen. I'd rather not add an option to "Mark Seam" and "Mark Sharp", in the spirit of what Hans said about moving to a philosophy of having bevel just output "what changed" and letting later nodes do things with those changed things. In order to get the effect you want, we probably need to not just say "these are the new edges", but also "these are the new edges that are at the boundary between new and old faces". Hans: - I agree, let's do this in Mesh, not BMesh. Is there common code somewhere for analyzing adjacencies in Mesh? I can do it myself -- I already did some things like that in Boolean -- but wonder whether some common, parallelized code has been / should be developed. Do you have a good example of an existing Geometry Node that I could study to give me an idea of how to implement this new node? Something that takes in some vertex/edge/face corner attributes and does something to the geometry because of those attributes? - Good idea to leave the existing code as is for quite a while, concentrating on the new node that then doesn't have to exactly replicate the old behavior. - Attribute API: thanks for the pointer, I'll be sure to study it. Any good examples of its use that you recommend I look at? - Attribute/Field outputs: I agree, let's give enough "These are what changed and how" attributes as outputs and let further manipulations like setting materials, setting face weights or hardening normals happen outside the node. - Custom profile always: interesting idea. I think the code needs profiles for both n-segments and power-of-two-greater-than-or-equal-to-n-segments, if I recall correctly, and this may complicate things a bit. Also, doesn't it kind of make the node useless without an extra node attached to the input to generate the profile? What would be the default if nothing is attached to that input? A flat segment? On the subject of extra nodes needed to make the node useful: I've been second-guessing myself as to whether the idea of using (angle, offset) per face corner is the right input to this geometry node. While general enough to do anything, and not providing too many constraints (overconstrainig, in other words), it seems very awkward to use "raw". It would almost certainly require another node to take user-friendly specs (like: "constant offset width") into that form. Do we really want to design nodes that are only practically useful when combined with other preprocessing nodes?
Author
Member

And Phillipp: The idea of using pipe booleans has occurred to me, and I may eventually try that, but at the moment our thoughts are to follow the "straight skeleton" method, with can deal with the intersection/merging of advancing edges when there are concave angles.

And Phillipp: The idea of using pipe booleans has occurred to me, and I may eventually try that, but at the moment our thoughts are to follow the "straight skeleton" method, with can deal with the intersection/merging of advancing edges when there are concave angles.

Added subscriber: @AndyCuccaro

Added subscriber: @AndyCuccaro

Added subscriber: @Lorathor

Added subscriber: @Lorathor

Added subscriber: @DuarteRamos

Added subscriber: @DuarteRamos

Added subscriber: @Moult

Added subscriber: @Moult

Added subscriber: @Nominous

Added subscriber: @Nominous
Member

Sorry for the delayed response.

Is there common code somewhere for analyzing adjacencies in Mesh?

Probably the closest existing thing is BKE_mesh_mapping.h, which calculates some topology. I haven't been very satisfied with that in the past though, the fact that it's a C API makes it a bit unpleasant to use.
In geometry nodes, we've mostly been making functions like create_vert_to_edge_map. That structure probably isn't very fast, but I think it's generally not a bottleneck yet.

I also think this sort of topology information should be cached on Mesh so it can potentially be reused. Some parallel code that stores topology information on a mesh which can be invalidated when it changes would be great to have.

Do you have a good example of an existing Geometry Node that I could study to give me an idea of how to implement this new node?

The node that does the most advanced work with meshes is probably the extrude mesh node (node_geo_extrude_mesh.cc). That should have all the basic structure of a bevel node. Let me know if you have any other questions about that.

Attribute API... Any good examples of its use that you recommend I look at?

Most attribute_foreach loops should provide useful examples. The attribute can be retrieved from there and created on the result. Then attribute_math::convert_to_static_type can be used to write interpolation code for each type as necessary.

Custom profile always... Also, doesn't it kind of make the node useless without an extra node attached to the input to generate the profile?

Good point, that might be a bit annoying to use. I still feel like it might be worth it for the simplicity though, if the default when no profile curve was connected was a totally round profile. That way the default common case is already handled, and any further customization uses the same workflow. I did a bit of design for that idea a while ago here: #86841. The power-of-two-at-least-n is already handled in the profile case I think, it just means sampling the curve at a higher resolution and also at N probably.

Do we really want to design nodes that are only practically useful when combined with other preprocessing nodes?

Yeah, this is a good question. I'm sure it's worth experimenting with this as part of the development. I think if most of the basic use cases ("give me a bevel with a size on some of the edges") are covered by the basic node inputs and still relatively simple to use, it's probably okay. But it might end up being too awkward. Another option is having a choice of input mode on the node, so at least the ultimate flexibility is an option. Personally I would err on the side of generality and simplify things as necessary-- especially early in development.

Sorry for the delayed response. > Is there common code somewhere for analyzing adjacencies in Mesh? Probably the closest existing thing is `BKE_mesh_mapping.h`, which calculates some topology. I haven't been very satisfied with that in the past though, the fact that it's a C API makes it a bit unpleasant to use. In geometry nodes, we've mostly been making functions like `create_vert_to_edge_map`. That structure probably isn't very fast, but I think it's generally not a bottleneck yet. I also think this sort of topology information should be cached on Mesh so it can potentially be reused. Some parallel code that stores topology information on a mesh which can be invalidated when it changes would be great to have. > Do you have a good example of an existing Geometry Node that I could study to give me an idea of how to implement this new node? The node that does the most advanced work with meshes is probably the extrude mesh node (`node_geo_extrude_mesh.cc`). That should have all the basic structure of a bevel node. Let me know if you have any other questions about that. > Attribute API... Any good examples of its use that you recommend I look at? Most `attribute_foreach` loops should provide useful examples. The attribute can be retrieved from there and created on the result. Then `attribute_math::convert_to_static_type` can be used to write interpolation code for each type as necessary. > Custom profile always... Also, doesn't it kind of make the node useless without an extra node attached to the input to generate the profile? Good point, that might be a bit annoying to use. I still feel like it might be worth it for the simplicity though, if the default when no profile curve was connected was a totally round profile. That way the default common case is already handled, and any further customization uses the same workflow. I did a bit of design for that idea a while ago here: #86841. The power-of-two-at-least-n is already handled in the profile case I think, it just means sampling the curve at a higher resolution and also at N probably. > Do we really want to design nodes that are only practically useful when combined with other preprocessing nodes? Yeah, this is a good question. I'm sure it's worth experimenting with this as part of the development. I think if most of the basic use cases ("give me a bevel with a size on some of the edges") are covered by the basic node inputs and still relatively simple to use, it's probably okay. But it might end up being too awkward. Another option is having a choice of input mode on the node, so at least the ultimate flexibility is an option. Personally I would err on the side of generality and simplify things as necessary-- especially early in development.

Added subscriber: @Giles-Barton-Owen

Added subscriber: @Giles-Barton-Owen

Added subscriber: @WilliamReynish

Added subscriber: @WilliamReynish

For custom profiles and corners, could one solve this kind of case:

customcut.png

...by doing this:

Screenshot 2022-07-02 at 21.03.54.png

Something like this is what one would get with a physical wood cutting, and IMHO seems more likely to be useful than strange grids fills.

For custom profiles and corners, could one solve this kind of case: ![customcut.png](https://archive.blender.org/developer/F13250319/customcut.png) ...by doing this: ![Screenshot 2022-07-02 at 21.03.54.png](https://archive.blender.org/developer/F13250326/Screenshot_2022-07-02_at_21.03.54.png) Something like this is what one would get with a physical wood cutting, and IMHO seems more likely to be useful than strange grids fills.
Author
Member

That would work sometimes. Other times, especially when the profile is asymmetrical, it will look bad too, just in a different way. It is a good point however to fall back on what physical woodcutting would do, as that is the original inspiration for the whole act of beveling.

That would work sometimes. Other times, especially when the profile is asymmetrical, it will look bad too, just in a different way. It is a good point however to fall back on what physical woodcutting would do, as that is the original inspiration for the whole act of beveling.

Added subscriber: @Yacine-Teach

Added subscriber: @Yacine-Teach
Member

Added subscriber: @EAW

Added subscriber: @EAW

Added subscriber: @Schiette

Added subscriber: @Schiette

Added subscriber: @Grady

Added subscriber: @Grady

Added subscriber: @emilis

Added subscriber: @emilis
Member

Added subscriber: @JulienKaspar

Added subscriber: @JulienKaspar

Added subscriber: @JamellMoore

Added subscriber: @JamellMoore
Contributor

Added subscriber: @persun

Added subscriber: @persun

Added subscriber: @SteffenD

Added subscriber: @SteffenD

Added subscriber: @Zorro_weaver

Added subscriber: @Zorro_weaver

Added subscriber: @bencrulis

Added subscriber: @bencrulis

Added subscriber: @syndaryl

Added subscriber: @syndaryl

Added subscriber: @3dFigaro

Added subscriber: @3dFigaro

Added subscriber: @Caco-Oportot

Added subscriber: @Caco-Oportot

Question - right now profile for inverted circle is something along lines of 0.085786 instead of 0.1:

bevel_profile_inv_circle.png

Is this something that can be fixed or it's just nature of math involved? 0.085786 is pretty hard value to figure out on your own without trial and error matching.

Question - right now profile for inverted circle is something along lines of `0.085786` instead of `0.1`: ![bevel_profile_inv_circle.png](https://archive.blender.org/developer/F14181130/bevel_profile_inv_circle.png) Is this something that can be fixed or it's just nature of math involved? `0.085786` is pretty hard value to figure out on your own without trial and error matching.
Member

@Format64 There is no inverted circle profile. The math does not allow it. You can tune the profile to look like an inverted circle, but it is never a perfect circle.

The mapping of shape values to superellipse exponents could definitly be changed to have more of the important points at simple values, but that would require versioning.

@Format64 There is no inverted circle profile. The math does not allow it. You can tune the profile to look like an inverted circle, but it is never a perfect circle. The mapping of shape values to superellipse exponents could definitly be changed to have more of the important points at simple values, but that would require versioning.
Philipp Oeser removed the
Interest
Modeling
label 2023-02-09 15:27:41 +01:00

Are they going to fix the problems of intersections of faces?
Please!!!!

Are they going to fix the problems of intersections of faces? **Please!!!!**
Author
Member

Indeed, the main impetus for this work is to fix cases like that.

Indeed, the main impetus for this work is to fix cases like that.

@howardt Thanks for your dedication to the bevel modifier!

Will this rewrite include anything to circumvent this issue?

#97000

image

@howardt Thanks for your dedication to the bevel modifier! Will this rewrite include anything to circumvent this issue? https://projects.blender.org/blender/blender/issues/97000 ![image](/attachments/953ff57d-af9f-4d59-848a-6a1092b880dd)
2.1 MiB

cool that people are working on the basics, improving them, instead of just having a bunch of new stuff to Blender.
i have a case in which the rework could try to address (if it doesn't already plan on addressing)

hopefully the images are self explanatory - i ain't a 3d pro to explain it. the only i can say is the way blender chooses to create the n-gon when bevelling an edge (destroying existing faces when it doesn't need to) is weird, when it could do a better job. like the images show, hopefully.

cool that people are working on the basics, improving them, instead of just having a bunch of new stuff to Blender. i have a case in which the rework could try to address (if it doesn't already plan on addressing) hopefully the images are self explanatory - i ain't a 3d pro to explain it. the only i can say is the way blender chooses to create the n-gon when bevelling an edge (destroying existing faces when it doesn't need to) is weird, when it could do a better job. like the images show, hopefully.
Member

I don't know if this is on the radar, but the edges having the bevel widths on them actually causes problems with the current implementation, for instance: if I want to have an uneven bevel along a subdivided edge, setting the bevel width per edge ends up smoothing out that variation, having the bevel be a combination of edge selection (boolean) and vertex width (float) would make this outcome possible.

In the example below, on the left I set the edge bevel weights at random, as we can see it's basically a straight bevel. On the right I manipulated the points to emulate the result I expected.

image

I don't know if this is on the radar, but the edges having the bevel widths on them actually causes problems with the current implementation, for instance: if I want to have an uneven bevel along a subdivided edge, setting the bevel width per edge ends up smoothing out that variation, having the bevel be a combination of edge selection (boolean) and vertex width (float) would make this outcome possible. In the example below, on the left I set the edge bevel weights at random, as we can see it's basically a straight bevel. On the right I manipulated the points to emulate the result I expected. ![image](/attachments/ff57391c-aed6-427c-8820-638021c2f2d7)
138 KiB

Varied bevel width in offset mode only works properly if you disable loop slide:

image
image

Though I find the way width is interpolated very unintuitive.

Percent mode bevel supports loop slide, but interpolation of width is different again:

image
image

Varied bevel width in offset mode only works properly if you disable loop slide: ![image](/attachments/cc8560f3-771d-40fd-bb5e-5acec2dab3a0) ![image](/attachments/1f6fca29-9c76-4545-95f3-7cfc8fdac9d7) Though I find the way width is interpolated very unintuitive. Percent mode bevel supports loop slide, but interpolation of width is different again: ![image](/attachments/40b7a110-8e81-40be-848c-f615a58581e9) ![image](/attachments/64276a66-c5b9-4a3c-9469-b6cacaeff157)

@howardt
A question - is it supposed to support the automatic depth of the bevel on a flat surface so that it can be used to model procedural cutouts, engravings and notches? Or does the term "depth" have a different meaning here?

image

@howardt A question - is it supposed to support the automatic depth of the bevel on a flat surface so that it can be used to model procedural cutouts, engravings and notches? Or does the term "depth" have a different meaning here? ![image](/attachments/5d8426c1-6af8-4454-8cf1-f0bec091c81a)

Hey, where in the process is all this? I mean the current implementation have some ugly bugs that breaks UV maps and gives quite a lot more work, so I would really love to have something that functions properly instead :)

Hey, where in the process is all this? I mean the current implementation have some ugly bugs that breaks UV maps and gives quite a lot more work, so I would really love to have something that functions properly instead :)
Author
Member

I hit some hard bugs and am taking a break from this while I work on a new much faster exact boolean. Sorry. I hope to get back to bevel v2 in a couple of months.

I hit some hard bugs and am taking a break from this while I work on a new much faster exact boolean. Sorry. I hope to get back to bevel v2 in a couple of months.

any news ? when it will realese?

any news ? when it will realese?
Author
Member

Sorry no update. I'm still working on the faster exact boolean, and that is going to take a few more months at least.

Sorry no update. I'm still working on the faster exact boolean, and that is going to take a few more months at least.

Any chance of seeing Bevel V2 in Blender 4.1?

Any chance of seeing Bevel V2 in Blender 4.1?
Author
Member

Sorry, no. Still working on the exact boolean v2.

Sorry, no. Still working on the exact boolean v2.

Thanks for the update; what's the issue # for the exact boolean v2? Or is that project part of this one?

Thanks for the update; what's the issue # for the exact boolean v2? Or is that project part of this one?
Author
Member

I didn't have an issue for exact boolean v2, but I just made one: #114476

I didn't have an issue for exact boolean v2, but I just made one: https://projects.blender.org/blender/blender/issues/114476

That is a huge milestone, can`t wait to see proper bevels on booleans regardless the topology. Can we expect it within a year?

That is a huge milestone, can`t wait to see proper bevels on booleans regardless the topology. Can we expect it within a year?
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
46 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#98674
No description provided.