Cycles: add bevel shader, for raytrace based rounded edges.
Needs ReviewPublic

Authored by Brecht Van Lommel (brecht) on Aug 20 2017, 1:41 AM.
Tags
None
Tokens
"Like" token, awarded by johnroper100."Like" token, awarded by Leukbaars."Dat Boi" token, awarded by Stromberg.

Details

Reviewers
None
Group Reviewers
Cycles
Summary

The algorithm averages normals from nearby surfaces. It uses the same
sampling strategy as BSSRDFs, casting rays along the normal and two
orthogonal axes, and combining the samples with MIS. Needs some code
cleanup still to untangle it from the BSSRDF code.

The main concern here is that we are introducing raytracing inside
shader evaluation, which could be quite bad for GPU performance and
stack memory usage. A similar issue exists if we want to add an AO
node that can output values instead of closures.

For CUDA with a GTX 1080, stack memory usage goes from 23408 to 24560
bytes, and render time on benchmark scenes seems unchanged. For AMD
OpenCL I did not test yet. Adaptive compilation there means it does not
affect scenes not using the bevel shader, but it's still a concern if
one small object with a bevel shader slows down an entire scene.

Moving the ray tracing outside of the shader evaluation is difficult,
that would make linking parameters or having multiple nodes with
different parameters impossible, since splitting up shader evaluation
into multiple kernels seems impractical.

Diff Detail

Repository
rB Blender
Branch
bevel
Build Status
Buildable 772
Build 772: arc lint + arc unit

Here's some test renders. As might be expected, this is not exactly fast. For small radius about 2-4 samples looks ok, but for best quality results when zoomed in you need more samples.

No Bevel
99s
Radius 0.1, Samples 4
131s
Radius 0.1, Samples 16
225s
Radius 0.25, Samples 4
132s
Radius 0.25, Samples 16
237s
  • Specify radius in object space instead of world space
  • Fix incorrect double normal transform in MIS computation
  • Fix pixel correlation in baking

How would render time compare between mesh with and without bevel shader? Shall we run some pre-processing to bake bevel to normal map, similarly to pointiness? This will allow having constant time overhead no matter of amount of AA samples used. Might need to implement something smarter than baking to vertex color, but implementing that smartness will also help in the case of pointiness.

Surely there's fully opposite idea: if we accept such ray-tracing effects, shall we then also implement "true pointiness" shader as well?

I want to avoid a slow baking preprocess, that's bad for viewport rendering. If we can quickly compute mesh attributes I wouldn't mind, but I'm not aware of a fast algorithm that works well for pointiness or bevel with arbitrary mesh topology. Things get complicated quickly when you try to handle all the corner cases. Making it work with adaptive subdivision will also be difficult, especially if out of core subdivision gets added at some point.

I think it would be good to have a node that can output AO as a color anyway, and pointiness could also fit in there. Still it does bother me that we would have these nodes that are really useful but then also maybe would not suggest to use them much if you want to render efficiently. On the other hand these effects are really useful for baking to a texture that you might then paint further, and just for that purpose we can justify having them.

One optimization would be to disable bevel when the path roughness exceeds some threshold. Another idea would be to have attributes to cache raytraced AO / pointiness / bevel at render time, and then adaptive subdivision could get you more accuracy.

@Brecht Van Lommel (brecht), surely having fast viewport render is good (fast as in time until first pixel). However, slow baking process you're reffering to will mean:

  • Render times in complex production files will not be optimal at all. We used pointiness all over the place there, and with the amount of AA samples (combined with surface samples due to BPT) it will be a huge overhead doing render-time pointiness. With AO and bevel shaders it will be similar story i'm afraid.
  • Manual baking would surely bring render times back to normal, however this introduces extra work for artists to keep all the textures up to date. Not even saying that sometimes you'll want to have animated texture (obviously AO changes for animated characters, so if you'll want to bake something you'll need to do it across whole framerange).

So saving time in one place means someone would need to spend more time on another place..

Disabling some raytraces effects after rough bounce will surely make things faster. Caching i'm not sure could happen efficiently: guess would need to add some locks to avoid threading conflicts. Perhaps we can do some sort of automatic baking to a texture, similarly to background MIS for some object's attributes before rendering (do it for final render only)?

Can we do the following:

  • Implement heuristic to disable bevel after rough bounce.
  • Replace pointiness with bevel in agent file (render result wouldn't match 1:1, but we are interested in time comparison and that should be quite accurate).
  • Compare render time against original file.

Maybe it wouldn't be that much of overhead and all my fears are pointless. Then we can just commit this, and aim for pointiness/AO to be added in a similar way.

It might be useful to add an option for skipping the beveling when the position is more than one radius away from any edge.
Doing so would remove bevels between objects, but probably give a significant speed boost for small bevels on hard surfaces, which is the main use case for this node I guess.

In fact, even without the speedup an option for limiting bevels to the same object might be useful.

I think that there is a big opportunity here with this bevel, and more importantly a design change allowing for at least the option of real pointiness and "usable" AO for the painting and baking workflow of Blender to be taken to the next level. There currently, as far as I'm aware, doesn't exist an open source, or even free painting solution with a suite of powerful procedurals/render-time effects like that. While it may be slower for final renders, it opens up a lot of doors for anyone authoring content for baking in a PBR workflow. With the addition of a few paintable masks and a local material repository, alongside the changes proposed in this discussion, Blender suddenly begins approaching feature parity with Quixel or Substance Painter/Designer. Worst case scenario, we can retain the old behavior(s) for pointiness for example, with a user option for a higher quality sampled version.

  • Disable bevel for glossy indirect rays, gives about a 40% reduction of bevel overhead.
  • Make radius world space again, works better when beveling between objects with different scale.
  • Render times in complex production files will not be optimal at all. We used pointiness all over the place there, and with the amount of AA samples (combined with surface samples due to BPT) it will be a huge overhead doing render-time pointiness. With AO and bevel shaders it will be similar story i'm afraid.

Agreed this is the main concern.

  • Manual baking would surely bring render times back to normal, however this introduces extra work for artists to keep all the textures up to date. Not even saying that sometimes you'll want to have animated texture (obviously AO changes for animated characters, so if you'll want to bake something you'll need to do it across whole framerange).

Mainly thinking about baking for game engines since that's where the request for this shader comes from originally. Requiring uses to bake texture when using Cycles for final rendering is indeed not a workflow we want at all. I don't think you wanted an animated textures here though, as I understand it AO or pointiness is typically used for weathering / aging / ... a fixed texture, not lighting.

Can we do the following:

  • Implement heuristic to disable bevel after rough bounce.
  • Replace pointiness with bevel in agent file (render result wouldn't match 1:1, but we are interested in time comparison and that should be quite accurate).
  • Compare render time against original file.

Heuristic implemented now, I'll run some tests with agent files.

It might be useful to add an option for skipping the beveling when the position is more than one radius away from any edge.
Doing so would remove bevels between objects, but probably give a significant speed boost for small bevels on hard surfaces, which is the main use case for this node I guess.

The issue here I think is that it's not always about different objects but rather disconnected mesh components inside the same object. In that case we would get artifacts.

An optimization we could do is share part of BVH traversal between the multiple short rays that we need to trace. We can compute the bounding box of the rays, and find the deepest BVH node that still contains it entirely. Potentially we can then also reliably detect when there is only a single triangle within the radius. This kind of optimization could also be useful for brute force SSS if we ever implement that.

Hm, yes, there are many cases where packet traversal algorithms could be beneficial - Bevel and SSS of course, but also possibly shadow rays with Sample All and the first bounce with branched path tracing.

Definitely worth investigating, but it can always be added later as well.

What I'm thinking of is not exactly packet traversal, rather it's taking advantage of the fact that the rays are short relative to the size of the mesh (which is not the case for e.g. shadow rays). We can compute the bounding box of the rays before we even taken any samples, and get a different BVH node index to replace the root index. For brute force SSS we wouldn't be able to know the bounding box before sampling the subsurface path exactly, but we do know that there's a high probability that the subsurface path will be short.

Anyway, this indeed wouldn't be part of the initial commit if we decide to accept raytraced bevel.

I have tested the new diff and it improve the render time from 97 to 72, from a original 23 base render.

From a videogame artist pov, the bevel shader is basically a tool to bake. But from a render artist, the mainly uses is for object designs, ads, mechanical, archviz,... Not big productions or scenes. It's really usefull in that user cases, it slows the render, but it's better duplicate the render time instead of work in the model 2-3 hours more. In the other hand, the bevel shader appear to affect to time render depending of the screen space and to little objects it's really a good solution for some cases.

About the object space, world space,... It's true that it confuse some users the object space, but it's a good way to have differente bevel sizes with the same material. It's not important, but it's a comment.

Some users could ask about activate only concave or convex and if it's possilble to quit "back faces" from calc to erase some "dark contour". From my pov it's secondary and it's better have this shader working instead to have a complete perfect solution a lot of time after, but I don't know, maybe this help to optimice the shader, or maybe not. Like I told a artist can search ways to solve it.

About the patch. Will be great see this in master soon (experimental or whatever) and a good key feature to show to artists. Some partners are really impressed about it and the "panel" workflow that the bevel created.

From a videogame artist pov, the bevel shader is basically a tool to bake. But from a render artist, the mainly uses is for object designs, ads, mechanical, archviz,... Not big productions or scenes. It's really usefull in that user cases, it slows the render, but it's better duplicate the render time instead of work in the model 2-3 hours more.

I agree.

It's true that it confuse some users the object space, but it's a good way to have differente bevel sizes with the same material. It's not important, but it's a comment.

Also agree. Concerning about something might confuse users is unnecessary. As long as the terminologies are used correctly, people/user should be able to go and learn the concepts in order to un-confuse themselves.

Some users could ask about activate only concave or convex and if it's possilble to quit "back faces" from calc to erase some "dark contour". From my pov it's secondary and it's better have this shader working instead to have a complete perfect solution a lot of time after.

Again, I agree. Having something working is very important.

If I have one thing in particular that I want as part of the workflow, I want the bevel shader to have the ability to know where the bevel is wanted or not. Example, only apply the bevel shading effect around the mesh edges that are marked Sharp or Seam. A threshold based on face angle hardly works for all scenario. As it's how MODO decides where the bevel should be shaded(Maybe it has other options, too).

Update for latest master and some fixes.

Welcome back Brecht :)
Regarding performance on split kernel, using a RX VEGA 64 on power save mode (to prevent throttling and get stable results):

  • Applying latest revision on latest master and adding an invisible cube with bevel at 4 samples to just get the code compiled in the Barcelona scene, global size fall from 1024 to 576 on x.
  • Render time increase from 430seconds to 478seconds (without synchronization time)

on simple scenes where the global size stays at or above 1024 on x, the speed impact is negligable. The default cube is even faster with 4spp bevel than without ... 14.05sec with and 15.36sec without. If you fill the camera FOV with cubes at 4spp, render time goes from 33sec without to 40sec with = about 21% slower. With 16spp, it goes up to 56sec = 70% slower

This mixed with a feature that as far as im aware no other tool has would be to bake the bevel normal map but have a conversion tool voxel driven that could take the hard edged original mesh mixed with the baked normal map to generate maybe through marching cubes an actual beveled real geometry version output. Would be very handy.

Also has anyone thought about using GLSL geomtry shaders here, raycasting in GLSL? That would give nice per object controls

The OSL shaders that were floating around BlenderArtists had an optimization to skip everything except camera rays. Obviously that won't work for baking, but for rendering it can work well. (might want to include singular rays as well?)

Also, an input normal like on the bump node may be useful in some cases?

Yes, I'm not sure why glossy indirect rays would be disabled but diffuse indirect rays aren't.

The problem with allowing a normal input is that you'd need to run shader evaluation for each of the bevel samples which makes it a lot slower. I guess the main application would be normal maps on top of the bevel, in which case it would be easier to add a normal input to the Normal Map node.

I re-purposed and updated to master one of Lukas old .diff Micro Jitter Scramble mixed with this and works well for speed up's:

All render with Correlated multi jitter and 756 render samples.

Bevel shader 128 samples with no micro jitter: 3 min 29 sec Opencl GPU:

Bevel shader 128 samples with Micro Jitter at 0.1: 3 mins 02 secs:

Thank you for this great feature!

The only issue that I am currently able to identify is that invisible objects (used by Boolean Modifier) are included when calculating bevels. This results in glitchy dark normals.

There are more tests in this thread:
https://blenderartists.org/forum/showthread.php?436279-V-ray-got-rounded-hard-edge-shader&p=3230436&viewfull=1#post3230436

This is fantastic! I'm getting great results out of it for normal map bakes.
A few problems I found with baking though which makes this a bit hard to use for actual production of game assets:

-does not seem to support custom vertex normals on your lowpoly mesh (is this a cycles limitation?)

-AO baking is VERY slow, the bevel node seems to slow AO baking with several orders of magnitude. I haven't been able to finish an AO bake using it.

again, fantastic work, this has a lot of implications for serious production work!

I ran some tests with this Agent 327 file, where almost all the building materials use a pointiness shader. This was done adding bevel in addition to pointiness, since just replacing it affected Russian roulette too much.
https://cloud.blender.org/p/agent-327/591abc5bbb3ea141675bbae7

It rendered about 7% slower with 4 samples, and 13% slower with 16 samples. That's too slow to recommend using for these kinds of shots instead of a bevel modifier I think. On the other hand I am not aware of good geometry based algorithms that can handle difficult mesh topology and non-connected components.

By the way, various meshes in this file have a subdivision surface modifier with simple subdivision, seemingly to get better pointiness results. If we imagine a future where adaptive subdivision is used for e.g. bricks, that wouldn't work so well anymore.

@YuanQing(Brent) Liu (TeaCrab131), varying the radius based on edge marked as sharp is possible in principle, though personally I have no interest in implementing that, someone else can do it.

@Jason Clarke (jtheninja), the path roughness optimization in this patch means bevel is only used for camera rays and sharp reflection/refraction. A normal input is possible, probably would just compute the difference with smooth normal and apply that back afterwards.

@mathieu menuet (bliblubli), thanks for testing, that's a pretty big impact, can't immediately think of possible tweaks to avoid that.

@juri (juri3d), ok, that can be fixed.

@Bram Eulaers (Leukbaars), not sure what you mean about not supporting custom vertex normals, custom split normals should work as far as I know. Not sure why AO baking would be so slow, unless you set bevel samples to a very high value like 128, it's really intended to work with much lower values. But regardless, raytraced based bevel is pretty slow.

Thank You Brecht for your continued interest and this feature.

  • I understand the speed concern regarding animation. For any type of stills(arch, CAD, posters/illustrative) and game work it's not an issue.
  • Improved Bevel modifier CAN be a viable solution and might even be preferable as this data can be exported to any application:

HARD MESH GIF

For that however Sharp/Bevel marked edges need to: a) regardless of topology be able to create a stable bevel gap (no spiking!) b) dissolve all faces in that gap c) reconstruct gap with Bridge and profile(e.g superellipse). Manual tests have shown this workflow to be very stable.
There are some good techniques discussed in this thread: https://blenderartists.org/forum/showthread.php?435274-Mesh-Fushion-Bevel-Boolean-fuse-%BFBlender-solution/page5

It is a highly desired feature. If wizards of Blender foundation can solve this, Blender will become the mecca of modelers.

  • Regardless, I am still very hopeful Bevel node is here to stay and some form of optimization or precaching can be found for animation. Please also take into consideration that in General DETECTION of EDGES (such as done for Beveling) and CAVITIES is backbone feature of modern texturing workflows(Substance painter/designer). With Pointiness you are limited to topology that needs to be consistent (reason bricks were subdivided). With true AO(raytraced*) you can create a masks for dust, dirt and much more without TOPOLOGICAL CONSTRAINT. With sharp edge detection you can do Edge Wear damages such as pealing paint. It's possible in Vray and is a very powerful feature: https://www.youtube.com/watch?v=ykdOVCqSPZc&feature=youtu.be&t=173

    To put this into perspective, to get such movie level renders in Blender, you would first have to retopologize him (very lengthy for such detail), then do perfect UVs, then send to Substance painter or designer, bake and texture, then send it back - a wasted WEEK with lower quality of geometry VS being it able to do it immediately by having access to Curvature/AO/Bevel nodes in Cycles. In my view any slowdown is acceptable as by the end of the day the user has a choice to enable/use these computationally expensive effects or not. Fundamentally being limited from doing these things is far worse.

@Bram Eulaers (Leukbaars), not sure what you mean about not supporting custom vertex normals, custom split normals should work as far as I know. Not sure why AO baking would be so slow, unless you set bevel samples to a very high value like 128, it's really intended to work with much lower values. But regardless, raytraced based bevel is pretty slow.

I was using custom vertex normals created using Y.A.V.N.E. (https://github.com/fedackb/yavne) to create cleaner normal bakes but it seems they are not being used when baking. I'll see if I can produce a good test case.
For AO, setting render samples very low (~10) and bevel node samples to something like 4 I can get reasonable bake times, but noisy results. I'll play a bit more with it to find the magic numbers that give a nice result. I'm probably a little impatient when it comes to bake times as well :)

I apologize for spamming this thread. I was curious if all of these effects(bevel, true pointiness, edgewear, cavities/ao) can be derived from Ambient Occlusion and INVERSE Ambient Occlusion?

Just as the Vray Video posted above (with vrayDirt), Cinema4D also has AO node usable with INVERSE option:

This results is excellent Edge detection that could be used as MASK for edge wear or potentially Bevel calculation.
As an example/proof of concept, I made a quick test in Substance Designer where Inverse AO is converted to Bevel:

@YuanQing(Brent) Liu (TeaCrab131), varying the radius based on edge marked as sharp is possible in principle, though personally I have no interest in implementing that, someone else can do it.

Not requesting any features, and I respect all the works done for this subject. I'm exploring all possible options.

Any thoughts about when that feature will be reviewed?