I was working on a game with 2.5D style like Octopath Traveller, using a custom that does sprite tiling and offset depending on camera position and object forward on the GPU, which I talk about in this article, but when switching to a lit node instead of an unlit node for my quad, there were some glaring lighting issues:
We can see 2 main problems:
The quad is self-shadowing
Computed lighting is incorrect, backface lighting and front face lighting are reversed
This shader fixes the self-shadowing issue, but it seems it mirrors vertices position, so our quad gets reversed. A quick fix is to then mirror the UVs afterwards (One minus UV should fix it).
Finally, we need to fix our object normals. There are two simple solutions:
If you want constant illumination on both sides, you can set the normals as pointing towards the sky, so a vector3 equals to (0, 1, 0). This is a common solution for grass. See bgolus’s answer in this thread.
Set another constant value, or expose a property to point towards a specific object.
In my case, I just set the normals direction in the Vertex shader as equals to the world to object transform of the (0f, 0.25f, -0.75f) vector since I’m expecting the camera to always be in the same position and I wanted my normals to point towards it.
The result is pretty nice in my opinion. Check it out:
We can clearly see the effect of the light rotating, and that the front face becomes darker when the light moves behind the quad (sprite becomes red because of my current post processing settings).
To note: you need to set your shader, and your other quads, as two-sided to ensure shadows are projected when the light goes behind the quad.
Now let’s try some realtime shadows:
Looks like the quad does get shadowed properly by the object in front. With this, we seem to have fixed our lighting and shadowing issues for our billboard shader. Good job!
On another note, I’m thinking of adding a ramp texture for the albedo based on light intensity to get a better control which, among other things, should help prevent the sprite becoming fully dark when the light moves behind the sprite. Stay tuned!