Light and shade…

Starting to get close to a look I’m happy with for the game so I figured I’d share a few notes on my setup. I’m aiming for a non-realistic, illustrative look, I want nice, distinct areas of flat colour, similar to watercolour washes or vector art, for this I’m using toon shaders and a ramp with no interpolation, i.e. solid bands of colour. Instead of the built-in shaders I’m using Toony Colors Pro and a great little tool called Ramps! which allows you to generate and adjust ramp textures right in the Unity editor, very handy for tweaking the look of things as you go…

I’m using the Normal/Multiple Lights/Basic variation of the above shader, with one small but important addition – the fullforwardshadows parameter. Adding this to the shader code just after the lightModel enables shadows on both point and spot lights and allows more than one light to cast shadows simultaneously. Unsurprisingly, this technique comes with pretty serious performance implications so that has to be considered when weighing up your options. Multiple shadow casters are pretty important to the look I’m after, light spilling out of doorways into a moonlit street is surprisingly tricky to achieve otherwise, and as of yet I haven’t found a way to get lightmapping to work successfully in a style I’m happy with (if I could isolate just the hard shadows that could be another option though!) For the majority of content I’m using a single, tiny grid of colours for the texture and adding details with TK2d sprites, so I’m hoping to claw a fair bit of performance back through batching. Also, graphic adventures aren’t overly reliant on high FPS anyway, atmosphere is much more important and, so far, scenes are still running at a more than adequate speed and that’s before any real attempt at optimising.

A couple of issues I have encountered are objects appearing back-lit or seeming to glow from within, this usually occurs if the darkest portion of your ramp isn’t completely black and the area in question isn’t completely in shadow:

I’m not a fan of 100% black, cast shadows, I like to use them more to add in a little extra detail and think they look best around 50%. In the above image, though, I want the exterior of the train to be dark until I add in directional moonlight, so we have to remove that “spill” somehow. I guess it helps to consider shadows and areas without light as separate issues to deal with? One solution is to ensure that your ramp has enough black at the end to compensate:

Using ramps with a lot of black can, however, result in “dead spots” occuring on flat surfaces with lights close by (floors/interior walls etc.) My solution at the moment is having several variants of my base shader, one for flat things, one for solid objects and another for self-illuminated stuff like strip lights and signs. Even with just these limited options though, I’ve been able to avoid issues in most scenarios, the Ramps! tool is super useful here, sometimes just a nudge in either direction is enough to fix huge swathes of “shadow acne”!

As always, I am far from an authority on this stuff, I’m mostly edging forward by feel alone, all crits, corrections and comments are therefore more than welcome…

Nick

3D-artist and fledgling Unity Dev. Currently working on a wordless point-and-click adventure game...

  • Rui Mota

    Looking very good. Thanks for the insight on the tools and workflow.

  • Thanks Rui! Glad you found it useful!

  • Bramlet

    So good, reminds me ‘Kentucky Route Zero’

  • Thanks! I take that as high praise indeed! 😀

  • hyperdynamic

    I really like the light and shading technique you are using. I am trying to do something similar with a game I am working on.

    I have a questions: where do you add the fullforwardshadows parameter in the shader code? I cant see a #pragma surface directive that is usually found in shaders.

  • Hi there, I found shader code a bit beyond my ability to be honest, even just editing pre-existing stuff can get pretty confusing. I’ve started using Shader Forge for shader fiddling now, everything has a check box! 🙂

    To answer your question though, I think it depends on the shader. Easiest place to start is download the default shaders for your version of Unity here: https://unity3d.com/unity/download/archive Open up the basic, Illumin-Diffuse.shader from the DefaultResourcesExtra folder in MonoDevelop, you can see the surface parameters mentioned above just under CGPROGRAM. Edit that and save with a different name and see what happens, it can be very temperamental though!

  • hyperdynamic

    Thanks for the help man. I got shadows working in Forward rendering! (but I see what you mean about temperamental :P) They’re bit blocky, but at least they work.

    I’m interested in your workflow – do you model everything and then do an automatic UV layout? If you are applying a gradient ramp as the texture, doesnt it look a bit funny?

  • If your shadows are super blocky I’ve found it’s usually to do with the settings for cascades and distance.

    I do very quick UV projections and then split them up into sections depending on colours, so, for example, the hands, ankles and face would all be laid out together, I only use a texture briefly then for baking in vertex colours. You could avoid unwrapping altogether and just paint the verts manually.

    The setup in Shader Forge looks a bit like this: https://i.imgur.com/PEKHtiD.png Only I’m not using the posterize node any more. The dot product of those two angles at the bottom, plugged into the UVs gives you the equivalent of an “incidence” node in Softimage or the “facing ratio” node in Maya, the ramp texture then is only used to create a flat light falloff, the colours come from the verts.

    That make any kind of sense?

  • hyperdynamic

    Thanks for explaining. I am used to working with shaders in Maya so I understand what you mean about the facing ratio node.

    Just one more question: Have you done any testing of you game on android devices? I cant get the shadows to work in forward rendering or deferred lighting.

  • I haven’t tested on Android at all yet I’m afraid!