[Contribution] NPR nodes in EEVEE

With Blender Internal being gone, there is a bit of panic in the NPR community, especially in Japan. Currently there is no proper way to do cel shading with EEVEE nodes. I am working on a solution right now and would like to contribute it to upstream Blender when it is done.

My solution will bring back the functionality that everyone relied on to make toon shaders in BI. I do this with three new nodes:

Split Shader
(shown above) This is the most important one. In BI you can plug the output of any material into any shader node. With Cycles-style node trees Shader closures cannot be plugged into other nodes. This node takes the most used technique of plugging materials into ramp nodes and packages up into a Mix Shader-type node.

Half Lambert
In toon shading it’s often important to be able to split across the dark part of a mesh, which is usually completely black with regular diffuse. A Half Lambert extends the range of luminance to the dark parts. Since you cannot plug in the output of shader closures to regular math nodes it is necessary to hard code this as a separate node.

Shader to Color
Shader input -> Color and Alpha output
The above two nodes sidestepped the strict socket types, whereas this one kinda breaks the design a little bit. It would however allow for the entire range of flexibility that BI nodes had.

I’m not sure how any of these apply to Cycles, but I’ve been having great results in EEVEE. I guess it will be EEVEE-only at least in the beginning.

Any thoughts? I will post more details as I inplement the last two nodes.


Contributions to make Eevee work for NPR are definitely welcome!

If you have a Shader to Color node that could cover the Split Shader case as well, so perhaps both will not be needed in the end? At least if it’s possible to have multiple Shader to Color nodes with outputs like color / shading / shadow, it should be possible to achieve the same result.

Progressive rendering as used by Eevee and Cycles is somewhat incompatible with NPR, because applying a ramp to individual very noisy samples does not give good results. For example there may be samples with values 0 and 1 at a soft shadow border that get averaged to a grayscale value, and applying a ramp to those sample will only ever use the two colors at the ends of the ramp, nothing in between.

In practice the samples that you care about might not have that much noise in Eevee. In Cycles it would be more problematic, but getting NPR to work only in Eevee to begin with would make a lot of people happy I think.

I wonder if it’s technically possible to implement a node similar to this mockup in Eevee:


Basically it would compute basic lambert diffuse using only direct light (possibly even considering only Lamps is enough to be useful), but in return allow restricting the light and shadow casting object sets (this is possible in BI), and output the result as color for use in further math. Together with a constant falloff for lamps, this basically allows obtaining the normal dot product that is needed for cel shading. An additional option that I think may be useful is combining multiple lights with max instead of add.

Edit: As I personally understand the problem, what NPR really needs is some quite basic features from the renderer core, like normal dot product with shadow check, but with the ability to then process that data with arbitrary color math etc, and preferrably with flexible controls about what lights and shadow casters matter for each situation. Complicated physically realistic things like bounce light, subsurface scattering and so on on the other hand are quite irrelevant. Thus maybe providing those basic inputs directly as a special node is cleaner than trying to hack in multiple ways to plug into the normal PBR rendering pipeline.

@brecht You’re right, Shader to Color would indeed cover the use case of the other two nodes, but Split Shader actually improves the workflow a little bit over the ramp node technique. Changing colours on the ramp was a bit cumbersome because you had to go into the node editor, and it isn’t easily animatable. Whereas Split Shader + Emission BSDF shows up in the sidebar. It also lets you plug in anything you want in the other two shader slots so people might find a creative use for things other than NPR.

The noise from Cycles might make it difficult to use with NPR, as you mention. I was just a bit worried because it seems the new design for Blender rendering is to have one unified shader node tree between Cycles and EEVEE? So having some nodes that only show up in EEVEE might be breaking that design… but if it’s OK then I guess we don’t have to make it work in Cycles also.

EEVEE with no noisy indirect lighting or reflections works very well for NPR so far, testing the Split Shader node. Even plugging other things into Lighting, like Glass BSDF or even Glossy BSDF gives a pleasant toon look. Maybe PBR and NPR can work together :slight_smile:

If you have lighting data as color, can’t you replace the ramp with Mix Shader + Math: Greater Than as threshold or something similar? I.e. does that Split Shader do anything that can’t be replicated with Shader To Color + Mix Shader + math nodes?

@angavrilov I need to look into Light Groups a little more because I didn’t know them until now. It’s true, in NPR it’s often needed to have only specific lights affect the geometry. Does EEVEE work with Light Groups already? It might be cleaner to use the existing fucntionality than bake it into a special node. This is also why I tried to create only a few basic nodes that work with the existing PBR pipeline. I find often toon shading solutions do not support all of a renderer’s features even though it can, by only applying a ramp at the end.

Maybe once BEER gets rolling we can have a separate engine/node tree for NPR :wink:

Good question. Technically yes, if you have the Shader to Color conversion node you can replicate the first two nodes’ functions with other nodes. But it is much more convenient to have it in it’s own node. Sure you can make a group node and such, but I think the Split Shader is more user-friendly. Also, the Split Shader node will also have options for making smooth splits with interpolation, like the ramp node. Sure you can replicate it with Math: Greater Than and Mix Color but that’s too annoying to do each time.

From what I heard, EEVEE does not support limiting lights by groups, and it would be difficult to support performance wise. This is understandable if you consider indirect lighting effects: all the data will probably have to be computed for every light group in use. This is why I’m suggesting a special NPR-directed node that only sees lamps and only does the shadow check and very basic shading computations, so that it would maybe be easier to implement.

In BI it was possible to limit lights seen by a material using a group, and limit per lamp which objects shadow its light, so I feel that without this Eevee won’t become its fully featured replacement.

1 Like

I see now. So EEVEE will not be supporting light groups? Does Cycles support it? Seems that it’s a basic feature that lighters use all the time. Like Light Linking in Maya. I will look more into it, thank you for mentioning it!

The maker of Eevee said in IRC that it’s not supported and would negatively affect performance, but he may look into it some day, or something like that. Cycles doesn’t support it either.

Light hacks aren’t physically realistic, so it’s kinda understandable that engines that aim for PBR won’t put supporting it as any kind of priority.

About Split Shader, I think it’s fine to have a convenient NPR shader with various features builtin, like we have Principled BSDF and Principled Volume. But then I think it should be usable as a single shader node, if you have to manually plug in Diffuse BSDF and Emission it’s quite low level and then you might as well start using shader node groups.

Also what is available in the properties editor is not really a good reason to choose a design, that can always be improved.

I see what you mean but in this case I have to disagree. Uber shaders are not flexible enough. You are limited by the implementation. What I aim for is to bring back what is possible in BI, which is make-your-own toon shader. Sometimes lower-level is best (but not so low level you have to plug in math nodes and do dot product).

Case in point, nobody used the built-in Toon shading in BI. Standard practice was to use ramps and roll your own. Toon BSDF in Cycles is also very very limited.

How would you propose an uber Toon shader would work? How would you specify the amount of slices? I don’t think Blender nodes can dynamically chamge number of socket. Not to mention NPR is broad enough that having, say, a Principled Cel Shader would be limiting what’s possible.

@angavrilov That’s a little unfortunate that light groups won’t be supported. Lighters doing realistic renders use them all the time, even if it’s realistic. Sometimes you need to cheat a little (^^)

Uber shaders are good for PBR precisely because there’s only one ideal physically realistic result and all shaders are aiming at it.

One problem with Toon shaders in both Cycles and BI is that they add up lights like usual, and moreover do that after the slicing, so you can’t use multiple lights to fill in lighted areas without destroying the proper look. What you likely need there is max of dot product for all of the lights, then slice; hence the Use Maximum option in my node mockup.

Another developer just submitted a patch for a “Shader to Color” type node:

@brecht I’ve finished the implementation for this proposal. Should I submit a new patch or update the one Kinouti made?


It’s best to submit a new patch.

Nice render tests!

1 Like

So here’s an update. The Shader to RGB node was accepted into trunk after working with Clement to fix it up, but it was suggested that I implement the other two nodes as node groups and submit them as an add-on. This is now done, but I am wondering about what the best way to make an add-on that makes node groups available would be. As far as I know, node groups are usually distributed in .blend files.

I suppose I could make an add-on that appends them into the scene upon opening a scene, but that seems like to mutch of a messy hack. Any ideas?

Thank you for all the hard work you’ve done! Fair winds for the rest, too!

I don’t know the details but I was under the impression that part of 2.8 development is “Amber” an asset management system for Blender. (Or I guess part of 2.8 is creating the infrastructure for asset management and Amber is the proof-of-concept asset manager?)
Either case wouldn’t custom nodes make perfect sense as “assets”?
Though, looking at it I haven’t heard of Amber in awhile and it seems like Amber isn’t meant to be end all asset management system for Blender… So I guess even if that would be eventually the best solution at the moment it isn’t really helpful :confused:
Between that and making an add-on that appends them in I can’t really think of anything better, though u _u