Lighting the Unlit
You might not realise but the characters in Röki receive no lighting in the traditional CG sense. They use unlit shaders, which means that whatever colour values we assign in the textures are left unfettered by any scene lighting and they are rendered flatly without any 3D lighting information. It's this lack of lighting that give the clean graphical look you can see in our characters and environments.
If what I'm saying makes no sense to you whatsoever you can see a comparison between a shaded/lit and a flat shaded/unlit sphere in the example below:
As well as being a pleasing aesthetic there are also some neat perks for working in this style. It means that we can be super confident that whatever we define in concept art/Photoshop will be very representative of the the visuals in game as there are no extra layers just pure colour choice from the concepts.
Now this is all well and good but there is quite a significant issue that if undressed would look terrible. That issue is bedding the characters into the scene.
We want to have a strong vibrant use of colours in our locations but this means that if the characters maintain their original texture colours exactly then they will simply look 'stuck-on', like they are not in the same location as the scene and simply pasted on afterwards. See the example below:
We've touched upon our solution to this in previous blog-posts but thought I'd take some time to explain what we're doing to solve this issue...and that would be Unlit Lights™ (not really a trademark).
Now, I cannot stress that this is actually a VERY simple system so don't be expecting any fancy rendering algorithms or SIGGRAPH paper-worthy techniques Saying that, it is effective and does what we need it to do so I'm guessing it's as complicated as it needs to be!
An Unlit Light
Essentially an 'Unlit Light' is placed in our scenes to 'Light' the character. The Unlit Light has three components that you can set:
- Tint Colour
The 'light' itself is the simplest thing in the world. Just a Unity group with a colour and two sliders. What we've done is create custom unlit Unity shaders to allow these 'lights' to influence the flat/unlit colours of our characters. Essentially rather than just displaying the pure texture colour we 'tint' the texture using the light's colour and allow ourselves to adjust brightness and contrast (much as you might do in Photoshop!). I'm not going to delve into the shader code but rest assured it's pretty simple stuff. You can see a breakdown of what the first two elements do in the GIF below:
The Tint Colour and Brightness are the key ingredients used to bed the character into a scene, allowing use to match the characters to the lighting in our backgrounds. The contrast was an interesting addition we added whilst we were messing around writing the shader. I wasn't sure what it would bring to the table, but as I was there I thought I'd add the functionality in.
It's actually really good for 'fogging' the player. If you look at the example below, you'll see as you drop the contrast Tove looks like she is behind some atmospherics or in a misty scene, a happy accident and one we'll gladly take!
You seen the above example on Tove in isolation but below you can see the difference this makes when bedding the characters to sit in the scene in the example below. The example on the left shows Tove's pure texture colours, notice how she looks 'stuck-on', the left example has been 'lit', with the pure colours tinted and the brightness and contrast adjusted to bed her into the scene.
The above example goes a long way to sorting out our issue of bedding in the characters, and in many scenes it might be that simple, however, we have a few more things to play with! We can have multiple 'Unlit Lights' (each with an independent tint colour, brightness and contrast) in a scene and depending on the character's position within a location it will determine how much 'influence' to take from each 'light'. This means we can darken the characters as they walk under objects or lighten them as they walk under a lamp or. Not only that but as we are dealing with tint colours we can avoid 'muddy' grey lighting, our dark areas can tint the character's rich midnight blue or whatever colour we choose!
Now this is in no way an accurate real-world lighting system, really, no way near, not even close. It is however an artistic one and allows us to take liberties to get the results we want AND work very quickly.
We can also turn the 'Unlit Lights' on and off at real-time. The sytem will update the scenes lighting array and the lighting on the characters will update automatically. We've not used this in anger yet apart from when we switch scenes, but I imagine it will come in handy for exciting stuff like flashes of lighting, magical emerald witch-fire or the strobing lights of a German techno nightclub (the last example may not make it into the game).
Shadows & Shadow Tint
Shadows are really important to bed a character into a scene. The shadow is a connection between the character and the environment, showing you visually that the two parts are occupying the same space. A contact shadow helps you judge the characters spatial relationship with the world around them, when jumping for example it helps reinforce visually that the character has left the floor.
By default Unity's unlit shaders do not receive real-time shadows (makes sense, I'm sure by default most people don't want this functionality, but we did) . This was the first thing we added back into our custom unlit shaders.
Next we found that as our scenes can be quite bright and colourful we didn't want boring grey drab shadows. So we added the ability to colour the shadows any colour we liked! Again, this isn't accurate to the real world but we're not making a real-world game so we're good with taking control of the colours back...IN THE NAME OF ART!
More to do?
There is still a few bits and pieces we can add into our system and I'm sure we'll be tweaking it as we go.In fact, to show the speed of development, during the course of writing this blog post one of them has already been solved!
One key element that I was key to avoid was 'double shadowing'. We have our environment shadows but into the geometry to keep them super crisp, but our characters cast real-time shadows. This can lead to charaters casting realtime shadow onto scene areas that are already in shadow casuing a weird 'double shadowing' effect. It's not the most offensive thing in the world but does look a bit off.
I had this on my to-do list to remedy this in the shader but then Tom solved it with a simple and eloquent solution. As the areas of the background that are in shaodw are 'cut-in' to the geometry we split off the environment shadow areas to be a different mesh and then simple un-check 'receive shadows' on this new mesh and it works like a dream, no double-shadows! Nice one Tom!
That's it, hope you've found this foray into the world of the Unlit Light an interesting one.
Until next time,
Alex & Tom