Bevel Improvements
Open, LowPublic

Description

Blender users have many desires for improvements to the Bevel tool and Modifier. This task is for exploring priorities for implementing those, as well as designs for doing so.

Some current TODOs and feature requests

Following comments will have some initial explorations of the problems and designs for solving each of these.

Details

Type
Design

Better handling of profile = 1, profile = 0.25, and implement profile = 0 cases

The current code for the "vmesh" (vertex mesh) at the corners of edge bevels is approximately this:

  • Build "profile triangles" across the ends of beveled edges, near the beveled vertex.
  • Build "boundaries" by putting multi-segment lines in the profile triangles. The "profile" parameter controls the shape that the multisegment lines are trying to approximate. If the triangle is a right triangle, the profile parameter has these special cases:
    • 0.5 : a quarter circular arc
    • 0.25 : follows the flat hypotenuse
    • 1.0 : follows the straight lines that complete a square on the other side of the hypotenuse
    • 0.0 : follows the two non-hypotenuse sides of the triangle
    • (in general, the profile is a scaled version of the "super-ellipse" parameter)
  • If the profile triangle is not a right triangle, the above profiles are scaled / stretched / rotated into the position of the actual profile triangle.
  • Add a center vertex at the vertex where the beveled edges meet, or somewhere else along the vertex normal of that vertex.
  • Use a modified cubic subdivision scheme (that keeps boundaries intact) to form the vmesh.

This works OK in the general case, but people have more expectations for the special case profile parameters.

Profile = 1
I think there needs to be special case code, totally different from the above algorithm. What I imagine is:

  • For each triangle formed by a two successive boundary vertices and the original vertex:
    • Complete the parallelogram by adding a 4th vertex in the shared face.
    • Rule the parallelogram with parallel rule lines, as per the number of segments. The intersections of those rule lines are the internal vertices of the vmesh.
    • When the number of segments is odd, you have to have "straddling" faces across the beveled edges, unfortunately.

Profile = 0
This case isn't even implemented at all yet, because the current code would build a vmesh that collapses to lines, and we don't want to build all of those 0-area faces and overlapping vertices. So this also needs special case code, pretty analogous to the profile=1 case.

Profile = 0.25
Here the users expect the vmesh to all lie on a perfectly flat plane. The general algorithm doesn't guarantee that. Now it won't even be possible to get them all on a flat plane -- the boundary vertices may not all be coplanar. But if they are, one approach to making this case better would be to project the generated vmesh onto the shared plane of the boundary vertices, as a postprocessing step.

Ok, so having pictures could help to see the goals.

Profile = 1, right now we have this.

http://pitiwazou.com/screenshots/blender_2016-06-02_09-42-27.jpg

The goal would be to have a perfect result with the same space between each point for the width.

http://pitiwazou.com/screenshots/blender_2016-06-02_09-46-32.jpg

Profile = 0.5, Much better than before, but still deformed.

http://pitiwazou.com/screenshots/2016-06-03_19-12-09.gif

A "Harden Normals" Option

Currently, after a bevel, the way vertex normals are calculated in Blender by default gives tilted vertex normals at the boundaries between the new polygons made along the beveled edges, and the original faces adjacent to those edges (I call those the "reconstructed polygons", because they get reconstructed using some new vertices created as a result of the bevel).

See:

If you use smooth shading on this model, then when hardbody modeling, an artist would usually desire that the original faces of something like a cube would be shaded flat after a bevel - the smooth shading should only affect the beveled edges and corners. Yet in the default case, we get shading artifacts due to the bent vertex normals and the way the faces are triangulated before shading:

Now that Blender has the ability to have split custom normals at vertices, we can adjust the vertex normals if we like. One possible adjustment would be to simply ignore the edge polygons when calculating custom vertex normals at vertices involved in reconstructed polygons. There is an addon, Y.A.V.N.E. (yet another vertex normal editor) -- https://github.com/fedackb/yavne -- which can be used to see what this would look like. With that addon, one can set the "strength" of a face to one of weak, medium, and strong. And then it sets custom vertex normals that only use faces in the maximum strength set found around a given vertex. Using that to set the edge and corner polygons to weak, we get these normals (magenta are the new custom normals; blue are the original ones).

And shaded it looks like:

Notice that this fixes the artifacts on the big flat faces, but the beveled edges don't shade all that well (triangle artifacts still visible). However, if the bevel is smaller and/or has more segments, the result looks pretty good:

Design

I think this should be an option, not something that happens every time, because it requires that the mesh be autosmoothed (a prerequisite for having custom split normals), and it adds a data layer to the object. And the result may not always be better.

A big choice in the design is which of these two things to do:

  1. Do the normal adjustment as a last step of bevel, if some (to-be-added) option flag is set.
  2. Add a new custom data layer in the mesh to keep track of which faces are the bevel's 'edge', 'vertex', and 'reconstructed' faces. Then provide a separate tool and modifier that will "harden bevel normals", reading that custom layer to find out where the reconstructed faces are and which adjacent faces were made by bevel. A variant of 2, call it '2b', would be to just implement the YAVNE code in C as a core part of Blender, and have bevel use YAVNE's existing 'face strength' custom data layer to tag the different kinds of bevel polygons.

The advantage of 1 is ease and discoverability. Artists will naturally see the option and decide whether or not to use it during the course of doing a bevel. And workflow is as easy as ticking a box. Whereas method 2 requires artists to remember to run another tool or apply another modifier after doing a bevel. Another advantage of 1 is that it doesn't require the storage of a new custom data layer in the mesh. For very large meshes, this can be an issue. A final advantage is just that 1 simpler to implement so could be developed more quickly.

The advantage of 2 is that it might survive more topological changes (in the modifier case). That is: the split custom normals, after having been set, may go wrong later if certain topological changes happen around the bevel. Then one might need something like YAVNE to repair. An advantage of 2b would be that the YAVNE tool is generally useful and perhaps deserves to be put into core Blender. A disadvantage of 2 is that it requires more storage, for the additional custom data layer. And if you do this as a modifier, it is hard to make that custom data layer go away if you remove the modifier (because: who knows whether that was the only reason the layer was added?), so the additional storage may linger after one wishes it were gone.

For now I propose doing method 1 -- just doing the adjustment as part of the bevel operation. But let's hear opposing views on this design task.

I propose adding a new option to the bevel tool, "Adjust Normals":

What should it do if activated and the mesh doesn't have autosmoothed enabled? The two choices are (A) enable it for the user; or (B) print an error message telling the user to enable it and do nothing. The YAVNE editor does A, the Normal Editor modifier does B. I think I will emulate the Normal Editor modifier and print an error message, as that is less likely to surprise users with a hidden state change on their model.

There is a third option :

The option is grayed out until auto smooth is enabled and the info about it could be in the tooltip: Available only if Auto Smooth is enabled for the object.

It can be achieved with a Poll Operator check for auto smooth or activating the checkbox only if it the precondition is met (with .active = condition).

Since it's bevel related, could it be possible to add the profile in the modal of the bevel ?
Right now, we can change offset, segments etc but not the profile.

Cédric: do you have a suggestion for how to control the profile during modal? I guess maybe some hotkey to hold down to make the mouse movement affect the profile rather than the offset? Any suggestion for which key, if so?

Ctrl or P for profile.

Ctrl is easier to reach fast and we could use Ctrl + Shift to decrease the speed.

Cédric: OK, I commited (with commit rBc8e9e6dda0f9) a change to have the P key toggle in and out of 'adjust profile' mode. I decided to use P rather the Ctrl since Ctrl-B enters bevel and maybe people could continue to hold Ctrl. (Maybe not. At any rate, the P key works and has a good mnemonic meaning.) The Shift key decreases the speed, as suggested (and as it does for decreasing speed of offset adjustment, in normal modal use).

Regarding the design, we'd optimally want to have both solutions - to have the checkbox method, but also have a button next to it that creates the custom data layer. I realize this is the most work of course. YAVNE's functionality is generally very useful and shouldn't IMO be relegated to an obscure addon.

Cédric: yes, it is possible. The 4th bullet point of this design task "more options ..." is intended to explore this. In particular, the "with setbacks" part of that statement would address what you want here, I think.

Right now I am working on the harden normals task, which is likely to take a week or so. But will start designing the "with setbacks" task after harden normals, I think.

Ok, just tested the new build, this is nice, thx a lot ;)

After changing the profile, we press P to change the width, can you restore the previous width value to not have to reduce a lot the actual width.

An example :

http://pitiwazou.com/screenshots/2016-06-08_16-50-28.mp4

On speedflow we keep the width, like that we can change other settings and comeback easilly with the previous width.

Ah, good point about maintaining the existing width even if the mouse moves to a different place during profile adjustment. I will fix this.

Cool thx !

Could it be possible to do the same for segments with S ?

Right now, we can only use the mouse or + and -, if we press S we could change the segments with the mouse deplacement or a number.
S exit this mode and we are in width mode.

Like that we could easilly change the settings for pen and mouse.

Good idea. I will do that too, I think.

With commit rB520691e5912d2eec you can now control segments with mouse after S toggle. And I fixed the problem with resuming changing offset at the last point you left off, after changing segments or profile with the mouse. And I added the ability to set the segments or profile with numeric input when you are in the P or S mode, respectively.

Yeah ! Well done, that will be really easy to use, thx ;)

Another feature request: see T49173. The desire is to get inward curving profiles for vertex bevels on convex corners. E.g.

Another feature request (from bf-funboard mailing list): a different number of segments for preview vs render.

To start, I love the new shortcuts added,(p and s)

One of the features I'd like to see added is the ability to quickly locate the vertices that are triggering the clamp overlap response for the modifier.
I usually join models together for texture baking and often once they are joined, the bevel radius for every component is reduced because somewhere there are two or more vertices that are too close together. Finding them can be difficult and time consuming.
It would be nice if those vertices could be added to the edit mode selection so they can be zoomed in on without having to search.


Currently(at least for default) there is a corner-cap triangle created for three edges that come together at 90 degree corners. A real-world machinist carving 3 beveled edges would end up something more like the following image, I think that would be a nice option to have. (a cube with multiple boolean operations and a picture from a counter-top manufacturer)

Here is a link to the counter-top website because it brings me to my next thought. :) Custom profile edges for the bevel modifier, they could be made using curves similar to how curves are used to create profiles for curves. http://granite.filesmonster.co/1239/granite-countertop-edges-pictures


The ability to easily taper bevels using Vertices Data->Mean Bevel Weights should eliminate the jagged pattern created by Edges Data->Mean Bevel Weights in conjunction with the Modifier set to Weight (I don't think we have that option unless I'm missing something...)


The End, and thanks Howard for being thoughtful and friendly :)

Thanks for the thoughtful suggestions.

I'm afraid I don't understand what you are getting at with the "taper bevels using Vertices Data->Mean Bevel Weights". Could you expand on this and/or provide a picture of what you mean?

Howdy Howard :)

Sorry, that last idea was confusing. ;)

See image below:

(Vertices Data->Mean Bevel Weights) is highlighted with red.

(Edges Data->Mean Bevel Weights) is highlighted with green.

For the bottom object, I wrote "Truncated when per/edge" what I mean by that is that when an edge is set to 0.0, then the bevel stops there at the beginning of that edge, instead of transitioning to zero near the very end of the object as it could with per-vertex weights.

Another requested bevel clamping change. See T50994. Requester would like clamp to apply to edges individually rather than globally. Could be consider as breaking backward compatibility for 2.8. Or an option (but we dislike adding too many options).

I think what I'd like to see is a threshold that prevents close vertices from overlapping without blocking the movement of vertices that are far from each other. I suppose something like a weighting that diminishes the bevel effect for close vertices.
Something like in the following which shows how Edge-Slide has less impact on close vertices but a large influence on vertices with larger distances. I think this would have to be an option though since it would best suit organic or choppy shapes like rocks. It would likely be inappropriate for machined surfaces.

I think I once requested something before about tagging vertices that overlap so they can be easily found and adjusted. Sometimes finding the problem overlaps can be difficult and time-consuming. Maybe they can be automatically added to a specially created and specifically named vertex group.

Someone else requested something similar to what you suggest -- just that when some vertices get blocked, they stay there and the unblocked ones continue to move. Maybe this should be the default, but I'd like to get some kind of consensus from artists before changing. As you say, it could be an option, but there is a lot of pushback on Blender devs from Ton not to add too many options to tools, but rather make them smart enough to "do the right thing" without options.

The idea of somehow identifying overlapping vertices to the user is a possibility, but I'd prefer another solution that I'm working on (albeit slowly): putting in the capability to automatically merge and continue beveling (similarly, insetting, for that command) when overlaps/collisions happen. The reason not to do your "identify the overlapping vertices" solution before then is that getting that precisely right is harder to code than one might think.

Edge group for bevel could be better than vertex group

Example.

http://imgur.com/131ZTN9

@Howard Trickey (howardt) Hi Howard, I've been running into some trouble with the bevel modifier over the last week as I move more towards VFX. I am using the Bevel modifier to produce my control loops for Subd modelling and UV as I go, ensuring that the bevel modifier has an even number of segments so that any seams I have defined will remain. But the seams don't remain when the modifier is applied. I have written up a post about this on rightclickselect to argue for a change in behaviour but have since realised I would be much better off voicing my thoughts here.
Regardless here is the post: https://rightclickselect.com/p/general/Xvbbbc/preserve-uv-seams-when-applying-a-bevel-modifier-with-an-even-number-of-segments

Essentially when you UV a model and then apply a bevel modifier the bevel modifier will split edges in the UVs causing unwanted tears and artefacts. In addition the edges marks as seams will split and change the seam location in a way that could never be useful to the user. Be sure to check out the link I posted as it shows some examples of the issue in more detail.

Thanks for your suggestion, Jac. And thanks for the clear examples in your rightclickselect post. While it seems strange to me to have a different treatment of seams for odd and even numbers of segments, I can understand your argument. What about other edge attributes (e.g., smoothness; bevel weight; ...). In your opinion, which edge attributes should go exclusively to the middle edge, which should go to all of the edges, and which should go to the outer edges of a beveled edge?

As for the 'tears': I've spent a lot of time (much more than I ever expected to have to) on trying to make the UV maps behave well after bevel; it seems a hard problem to get perfect. But I'll look at your examples and see if I can figure out if/how they could be improved.

Glad to see this being discussed here. I agree with @Jac Rossiter (Jakro) that you'd want UV seams in the middle of the bevel whenever possible. Now ofcourse that's not the case with an odd number of edges, but it's still an ideal to strive for in my opinion.
As for other edge attributes, it seems to me that hard edges & bevel weight make sense being on the outside of the bevel, so as to avoid compromising the bevel's curvature (either by bevel the middle of it, or by having a sudden gap in normal continuity there).

Maybe it could be usefull to clean bevel weight when applying the bevel modifier to avoid this kind of result ?

And I agree, the seam should stay at the center if possible to avoid this kind of result.

Of course having the right number of segments is better.

Jac Rossiter (Jakro) added a comment.EditedSep 13 2017, 2:02 PM

@Howard Trickey (howardt) Thanks for such a quick reply! I agree with @michael knubben (michaelknubben). The only thing that really needs to be as much centre as possible is the edge seam, as that way it would be really easy to just reunwrap the mesh and avoid any issues with those unwanted tears. The ideal would be that the UVs wouldn't tear in the first place but it's not a big deal to just reunwrap the mesh with the new seams at the centre of the bevels. I wonder if it would at all be possible to have an option within the modifier on how it would handle edge data. That would be perfect act avoid any worries about being consistent with how edge data is treated. Just let the user decide whether edge seam is split or center. Perhaps add an offset option so that if the bevel has a segment of 1 the user could offset which side the seam would move to. Just an idea, in reality I would just be very happy with just a change that put seams in the centre.

I want to drop a few cents here about the related proposal I don't see mentioned here.
I remember cédric's proposal in rightclickselect for adding Bevel Segments value for Edges Data. It could be s great feature for non-destructive modeling with a better bevel modifier.
https://rightclickselect.com/p/modeling/hqbbbc/add-a-value-for-segments-in-bevel-modifier

To add to what Yury included above, if the models use Weight Paint Groups to determine the values for width and segments then multiple objects with different settings can be joined together.

Currently, If two models with different modifier settings are joined, the settings for one would be lost. BTW. This could be done for sub-surf as well. Weight of zero = subsurf level 0, weight = .1 = subsurf level 1, etc...