The following files have been attached to this tutorial:
This tutorial hasn't been translated.
This tutorial is licensed under CC BY 4.0. Please refer to the license text if you wish to reuse, share or remix the content contained within this tutorial.
The ShadowLight plugin is able to do some cool shadow-casting effects. However when you add two lights, it can become difficult to get working correctly. By default ShadowLight only draws shadows. So when you get shadows overlapping other lights it looks wrong, like this:
Both lights are in each other's shadows. However if they were a true light source, they would light up the shadowed area by the lights to be light again. If you keep adding lights then eventually everything is dark, because everywhere is in the shadow of one of the lights!
Using a combinaiton of techniques, it's possible to solve this. It's also common to want lights which fade out over a distance, and lights which can be colored. Let's look at an interesting technique to be able to cover all of this.
The fundamental technique is this: start with darkness (an entirely black screen), then add in each light on top of that. Using the "additive" blend mode lights correctly blend by adding the light intensity at every pixel, so a light in another light's shadow still increases the brightness.
Once you have this "light map", you can multiply blend it with the background, and it applies the combined lighting.
Let's start with one opaque black layer, which gives us complete darkness. Then we add the "mask". This is a white circle with the alpha fading to transparent around the edges. Here's the image so you can copy it, but it's not easy to see against a light background!:
Now we position this spot at the ShadowLight object, and in the Z order, put the ShadowLight on top. This is an essential point: it means the shadows are drawn over the white spot. This gives us the "light map" of a single light, which both fades to darkness over a distance, and has shadows cutting darkness in to the light. It looks like this:
Notice we've done something interesting here: we've converted ShadowLight from only drawing darkness, to drawing an area of lightness. However this light map occupies an entire layer. So the next light has to go on a new layer.
Now we add a new layer on top for the next light. Note the bottom layer is opaque, but this layer should be transparent. We use the same technique: a white circle sprite, with a second ShadowLight over the top of it. This layer (over a black background) looks similar, but with the light in a new position:
The key to combining these lights is to use Additive blend for the whole second layer. This means it renders the area of lightness, then adds this to the light map beneath it. This allows light to lighten areas of darkness in shadows underneath, and combines areas with weak lighting in to a stronger light. The combined light map looks like this:
Now you can start to see how the lights are combining! There are some shadow casters in the middle which cast a shadow a short way, but then it reaches the next light and becomes light again. Where shadows cross, it correctly takes in to account both lights.
We can keep adding lights this way. Do the same process again: add a third transparent layer with additive blend, put a white circle mask sprite under a ShadowLight, and that is combined as well:
Here's our background with the shadow casters.
We have a problem: we can't correctly put all these lighting layers on top of the background without needing nested layers, which Construct 2 does not support. What we want to do is multiply-blend (using a WebGL shader) the entire combined light map with the background.
Luckily, there's a great hack we can do. Multiply is associative: a x b is the same as b x a. In terms of layers, this means the result of multiply-blending one layer with another is identical regardless of which layer is on top. So - we can put the background on top, and multiply blend the background with the light map! In other words, we render all the lights to the black background, put the background on top, and multiply that against the light map underneath it. It looks the same as if we'd rendered all the light layers to a single layer, then multiply-blended the result over the background. So our layers look like this:
Light1 (opaque, normal blend)
Here is the result:
Behold, multiple lights casting shadows!
Colored lights are really easy to do with this system. Using a WebGL tint shader, change the color of the white circle mask sprites under the ShadowLights. This makes the light add an area of (for example) red lightness only. These even combine correctly with other light colors, so red, green and blue lights all shining in the same area re-combine to white!
And there you have it - multiple different-colored lights casting shadows.
One difficult aspect of this is because there is no support for nested layers right now, you can only apply this kind of lighting to a single background layer. Other layers on top cannot have this lighting applied, since by the time they are rendered the background already has the light map applied. It's sort of "baked in" to the image by then, and you can only multiply with the final result, which isn't very useful. Arguably however it is useful that now you can put new content on top without it being affected by lighting, e.g. the HUD. You'll note the shadows also darken the shadow caster objects themselves. If you want them to show without lighting, you may need to have duplicate objects at the same position on one of these above layers. The underneath object exists solely to cast the shadow, then the object on top is for appearance.
You also need a layer per light. This makes it hard to add loads of lights. Lots of layers also means you'll use a lot of GPU fillrate, so be sure to set any of the layers you're not using to be invisible, otherwise you'll consume fillrate adding empty layers (which consumes the same resources as drawing content, it doesn't matter if it's transparent).
With some careful use of layers, blending, and Z ordering, you can make Shadow Light objects render lightness instead of darkness, and combine multiple lights together. The multiply-on-top trick lets you combine the resulting map from multiple lighting layers with a single background layer. This can be done with the existing features in C2 - no need for anything new!
An example showing the final result with 3 moving colored lights is attached to this tutorial. Try making every layer initially invisible, then make each layer visible one at a time - you can see what each layer renders individually, and how they combine at the end. Have fun playing with the lighting effects!