Have you ever wonder how to implement the lighting in the cloudy and raining day?
For me, the answer is “yes”. By jump across directly to 3d world would be a bit of difficulty, so I decide to do it in 2d first.
The behavior of the lighting in natural is complex and unpredictable, we always try to simulate those behavior in the term of graphics programing. By using the recurrsive routine to help out, we can achieve at least the close one.
Only 2 main parts to implement this thing.
First is LineDrawer, and Second is Algorithm to simulate the lighting.
Why bother do the line drawer system, isn’t it exist already in xna framework? No.
Actually the pixel drawer in XNA also doesn’t exist, but we can work around this which I will explain how to do it next.
For pixel drawer in XNA, you have to create the 1 x 1 pixel texture of white in order to be used as the texture to draw on screen. Of course, the white choosed is important, as we can tint it with other color. Thus giving us ability to draw 1 pixel color on screen.
But for line, how can we do that?
We also use the concept of pixel drawing.
Imagine you want to draw line, thus we have to put those pixels (thus 1×1 texture) in sequence from (say) point A to point B on screen. That’s it, we just iterate the process and draw each loop with that 1×1 texture.
But with this approach we need to calculate the position for each of the texture being drawed, and lots of textures too, nonetheless it gives the most accurate of line (we may not see the different).
So what we will use instead is that, we will use only 1×1 texture for each pair of point defined the line.
We will stretch it along the x-axis for the magnitude after we know the distance between two points, and we will stretch along the y-axis for our variable line-thickness. Also we will rotate the texture too, in the case if two points are not on the same horizontal.
You can see all of this in PrimitiveLine.cs file. (The download link is below, thanks for the author for this great and very useful line drawer, I’m sorry that I can’t remember the name because it’s very long ago.)
The most notable part is here.
///
/// /// Renders the primtive line object.
/// ///
/// ///The sprite batch to use to render the primitive line object.
public void Render(SpriteBatch spriteBatch)
{
if (vectors.Count < 2)
return;
for (int i = 1; i < vectors.Count; i++)
{
Vector2 vector1 = (Vector2)vectors[i-1];
Vector2 vector2 = (Vector2)vectors[i];
//check for boundary
//we dont draw anything if both vertexes are out of range
if ((vector1.X < 0 && vector2.X < 0) ||
(vector1.X > width && vector2.X > width))
return;
// calculate the distance between the two vectors
float distance = Vector2.Distance(vector1, vector2);
// calculate the angle between the two vectors
float angle = (float)Math.Atan2((double)(vector2.Y - vector1.Y),
(double)(vector2.X - vector1.X));
// stretch the pixel between the two vectors
spriteBatch.Draw(pixel,
Position + vector1,
null,
Colour,
angle,
Vector2.Zero,
new Vector2(distance, Thickness),
SpriteEffects.None,
Depth);
}
}
Okay, let’s we move to the algorithm itself to simulate the lighting.

Two points defined a line
We will use the recurrsive approach here, as you see from the image above, two points defined a line.
Then if we find its middle-point, and offset its position at random for a little, and repeat this step until the length between the end point to mid point is small enough, then we will get the simulated lighting.
See it here (in Game.cs),
///
/// Add the vertices to the lighting between the two end points a, and b.
///
///
///
///
private void AddLightingVertices(Vector2 a, Vector2 b, float displacement, int lindex)
{
if (displacement < CURR_DETAIL)
{
//add the two end points
lineDrawer[lindex].AddVector(a);
lineDrawer[lindex].AddVector(b);
}
else
{
//calculate the midpoint between point a, and b
float mid_x = (a.X + b.X) / 2.0f;
float mid_y = (a.Y + b.Y) / 2.0f;
//displace it a little
mid_x += ((float)random.NextDouble() - 0.5f) * displacement;
mid_y += ((float)random.NextDouble() - 0.5f) * displacement;
Vector2 midPoint = new Vector2(mid_x, mid_y);
//draw the line from two end points to the mid point
AddLightingVertices(a, midPoint, displacement / 2, lindex);
AddLightingVertices(midPoint, b, displacement / 2, lindex);
}
}
After this finishes you will get all the vertices ready to be drawed by line drawer.
Notice that I want the code for drawing to be clean as possible (like drawing the point at the leftmost to the rightmost), so each two end-points of lighting requires one PrimitiveLine to handle it.
Thus if you increase the number of bolt, then you need to increase the PrimitiveLine too.
Now you are ready to draw it,
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
//early start of the spritebatch (to get the benefit of only one traversing of loop)
spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
//loop through all the line of the lighting
for (int i = 0; i < NUM_BOLT; i++)
{
lineDrawer[i].ClearVectors();
//add the point to the lighting
AddLightingVertices(a, b, DISPLACEMENT, i);
//render the lighting
lineDrawer[i].Render(spriteBatch);
}
spriteBatch.End();
//Draw the info text
DrawInfoText(gameTime);
base.Draw(gameTime);
}
I just want to use each loop efficiently so after I add the vertices for each pair of bolt then I draw it immediately as you see above.
You’re done for this, note that you can add more settings for this app, like the number of bolt, the threshold length (to stop the recurrsive, note that for this I named it “Detail”), the displacement for the midpoint to be offset away from the line, thickness of the line.
Here is the result,
(Sorry for my quite mess post, it’s very late now, and I should go to sleep, sorry for that folks.)
-
-
Two points defined a line
-
-
Simulation starts
-
-
Low number of bolts
-
-
High number of bolts with thick line
-
-
High number of bolts!
Lighting 2D: Download