# 2D lighting causes black rings to appear

A year ago I implemented 2d lighting in XNA using sprites. The sprites I used were created by placing a soft white photoshop brush on a transparant background.

And this seemed right to me.

I returned to the subject this week to try replacing the sprites with a texture created with code and a formula:

As you can see, there is a black ring around every light.

This is the code I used for creating the textures:

int diameter = 250;
int radius = diameter / 2;

Color[] colors = new Color[diameter * diameter];

for (int y = 0; y < diameter; y++)
{
for (int x = 0; x < diameter; x++)
{
Vector2 l = new Vector2(radius, radius) - new Vector2(x, y);
float attenuation = MathHelper.Clamp(1 - Vector2.Dot(l / radius, l / radius), 0, 1);

colors[x + y * diameter] = Color.White;
colors[x + y * diameter].A = (byte)(attenuation * 255);
}
}

Texture2D texture = new Texture2D(device, diameter, diameter);
texture.SetData(colors);


I got the attenuation formula from here.

Aside from that I now create the textures using code, the rest of the code has remained the same.

Where do the black rings come from, and how do I prevent them from appearing?

• looks like a problem with the exponent of the brighness calculation in my opinion – Quonux Jan 16 '14 at 20:42
• My wild guess would be that you need to use a different blend mode (maybe with premultiplied alpha) for drawing the textures. But this is just a really wild guess. – amitp Jan 17 '14 at 2:36
• Yes, it's the blend mode. I just did this the other day, and while both the texture AND the blend mode need to specify non-premultiplied, there are some other settings that have to be adjusted. @Berry If you don't figure it out shortly, I'll write up an answer when I get off work. – jzx Jan 20 '14 at 23:35
• This may be optical illusion. Measure actual pixel brightness. Overlay it with something other to check if light effect is working. – Shadows In Rain Jan 21 '14 at 11:49
• You need multiple buffers. Either sum all the lights together, and then multiply that by the image being lit. Or else multiply the image to be lit by the current light, and add that result. One light should never have to multiply by a pre-lit image effected by another light. Also, you'll want to think about doing things in a linear color space. Physical lights add together linearly, but you are probably using sRGB images to be lit, and perception and displays are very nonlinear. – wrosecrans Jun 17 '16 at 20:08

Okay, here are the settings you'll want to use to additive blending, plus some extra info in case anyone else wants to do something similar.

I'm not sure how to get this to work with pre-multiplied alpha (or if that's even necessary, since I'm guessing you plan to do mask-based lighting), so you'll want to make sure that if you have any resource based "brushes" (also known as "cookies") that you set the pre-multiplied alpha property like so:

I altered your texture declaration a bit:

_texture = new Texture2D(device,
diameter,
diameter,
false,
SurfaceFormat.Color);


Here's the set up:

protected override void LoadContent()
{
// This is the texture we'll draw to,
//     and then we'll use this texture as our mask.
_canvas = new RenderTarget2D(GraphicsDevice,
GraphicsDevice.Viewport.Width,
GraphicsDevice.Viewport.Height,
false,
SurfaceFormat.Color,
DepthFormat.None,
0,
RenderTargetUsage.PreserveContents);
// This is a kind of additive blend.
// It will clamp to the max channel once that channel reaches full "brightness."
_addBlend = new BlendState
{
ColorSourceBlend = Blend.SourceAlpha,
AlphaSourceBlend = Blend.SourceAlpha,
ColorDestinationBlend = Blend.InverseSourceAlpha,

// SpriteSortMode is practically useless here.