I have made a color, decent, recursive, fast tile lighting system in my game. It does everything I need except one thing: different colors are not blended at all:

Light Colors Not Blending

Here is my color blend code:

return (new Color(
       (byte)MathHelper.Clamp(color.R / factor, 0, 255),
       (byte)MathHelper.Clamp(color.G / factor, 0, 255),
       (byte)MathHelper.Clamp(color.B / factor, 0, 255)));

As you can see it does not take the already in place color into account. color is the color of the previous light, which is weakened by the above code by factor. If I wanted to blend using the color already in place, I would use the variable blend.

Here is an example of a blend that I tried that failed, using blend:

return (new Color(
       (byte)MathHelper.Clamp(((color.R + blend.R) / 2) / factor, 0, 255),
       (byte)MathHelper.Clamp(((color.G + blend.G) / 2) / factor, 0, 255),
       (byte)MathHelper.Clamp(((color.B + blend.B) / 2) / factor, 0, 255)));

This color blend produces inaccurate and strange results. I need a blend that is accurate, like the first example, that blends the two colors together.

What is the best way to do this?

Update: I noticed that the reason simply adding them together and the above isn't working is because the light was spreading onto itself and blending with itself. I am going to try and prevent this by writing the light spread onto one array, a temporary one, not using blend at all, only using the first method. After each light is finished with the recursion process I'll draw it to the main one using a custom pixel shader that will blend the light together properly. This may or may not solve my problem.


Your own idea isn't that far off. However, you'll have to multiply the final color, not the light color alone:

final_light = (color1 * factor1 + color2 * factor2) / 2;

To elaborate a bit more, both factor1 and factor2 are based on the distance to the light sources, their range, etc. I just picked multiplication over division - in your example, you could just replace them with divisions, if your factor fits that operation.

Let's assume the distance to the first light is big enough for it to be dimmed to 50% and the distance to the second light would result in something like 75% (it's brighter/stronger or just closer):

final_light = (color1 * .5 + color2 * .75) / 2;

Or - using your way of doing the math, using division:

final_light = (color1 / 2 + color2 / 1.33) / 2;
  • \$\begingroup\$ So what should be the value of factor2? And remember I'm dividing by factor not multiplying. \$\endgroup\$ – bpmw Jun 7 '14 at 16:46
  • \$\begingroup\$ It's just the proper factor based on the distance of your second light. It doesn't really matter whether you multiply or divide, it depends on your factor (you could also imagine that my factors are actually 1 / yourfactor). I just consider using multiplication to be more "natural" as it allows you to clearly/easily translate the factor to the result, like .5 dimming the color to half its initial value. \$\endgroup\$ – Mario Jun 8 '14 at 5:45
  • \$\begingroup\$ That's simply impossible with my lighting system as it does not store individual lighting positions, only an array with lights that is then spread. Also, I can have hundreds of lights onscreen at once. \$\endgroup\$ – bpmw Jun 8 '14 at 14:34
  • \$\begingroup\$ How do you get factor then? is it a value per tile? \$\endgroup\$ – Mario Jun 8 '14 at 15:13
  • \$\begingroup\$ The factor is simply what to divide the light by to dim it, it's constant the whole time. For solid tiles it's 1.8f, for empty tiles it's 1.2f. It's simply the blocking amount for the light. It's irrelevant to color blending. \$\endgroup\$ – bpmw Jun 8 '14 at 15:17

Check out the Blend modes article on Wikipedia. It's really useful for these kind of things.

For example, the "screen" blend mode might work in your case. I.e. something like:

newColorR = 1 - (1 - color1R) * (1 - color2R)
newColorG = 1 - (1 - color1G) * (1 - color2G)
newColorB = 1 - (1 - color1B) * (1 - color2B)

where all the variables are in the range 0…1 (and colorNX is the result after you've applied your factor).


Your Answer

