Why is 2D light ray collision result getting inverted at specyfic angle

| | August 5, 2015

recently i’ve been working on 2D lighting for my game. I’ve created new little project, and I’ve encoutered a problem. The collision between light ray and the object is fine at angles 316-360 and 0-136 degrees. On the others, light gets inverted (it’s gone form the source to the object, and it’s present on the ‘dark side’.
I know the code isn’t efficient, it’s just my concept project, I would like you just to help me understand what is going on in here.

Here’s a function that checks for collision, for every single point in a light ray.

public Vector2 Intersects(Rectangle rectangle,SpriteBatch s)
{
    Point p0 = new Point((int)startPos.X, (int)startPos.Y);
    Point p1 = new Point((int)endPos.X, (int)endPos.Y);

    foreach (Point testPoint in BresenhamLine(p0, p1))
    {
        if (rectangle.Contains(testPoint))
        {
            s.Draw(this.texture, new Rectangle(testPoint.X, testPoint.Y, 3, 3), Color.Black);
            return new Vector2((float)testPoint.X, (float)testPoint.Y);
        }
        else
        {
            final = testPoint;
                s.Draw(this.texture, new Rectangle(testPoint.X, testPoint.Y, 3, 3), Color.Black);
        }
    }
    s.Draw(this.texture, new Rectangle(final.X, final.Y, 2, 2), Color.Black);
    return Vector2.Zero;
}

// Swap the values of A and B  

private void Swap<T>(ref T a, ref T b)
{
    T c = a;
    a = b;
    b = c;
}

// Returns the list of points from p0 to p1   

private List<Point> BresenhamLine(Point p0, Point p1)
{
    return BresenhamLine(p0.X, p0.Y, p1.X, p1.Y);
}

// Returns the list of points from (x0, y0) to (x1, y1)  

private List<Point> BresenhamLine(int x0, int y0, int x1, int y1)
{

    List<Point> result = new List<Point>();

    bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
    if (steep)
    {
        Swap(ref x0, ref y0);
        Swap(ref x1, ref y1);
    }
    if (x0 > x1)
    {
        Swap(ref x0, ref x1);
        Swap(ref y0, ref y1);
    }

    int deltax = x1 - x0;
    int deltay = Math.Abs(y1 - y0);
    int error = 0;
    int ystep;
    int y = y0;
    if (y0 < y1) ystep = 1; else ystep = -1;
    for (int x = x0; x <= x1; x++)
    {
        if (steep) result.Add(new Point(y, x));
        else result.Add(new Point(x, y));
        error += deltay;
        if (2 * error >= deltax)
        {
            y += ystep;
            error -= deltax;
        }
    }

    return result;
}

pictures representing a problem.

One Response to “Why is 2D light ray collision result getting inverted at specyfic angle”

  1. I believe it’s because you’re using the Bresenham line drawing, which swaps the start/end points sometimes. See the calls to Swap().

    I’d suggest instead using linear interpolation for line drawing, which would look something like this (untested):

    double lerp(double begin, double end, double t)
    {
        return begin + (end-begin) * t;
    }
    
    private List<Point> DrawLine(int x0, int y0, int x1, int y1)
    {
        List<Point> result = new List<Point>();
        int Nsteps = Math.max(Math.abs(x1 - x0), Math.abs(y1 - y0));
        for (int i = 0; i <= Nsteps; i++)
        {
            float t = 1.0 * i / Nsteps;
            result.Add(new Point(lerp(x0, x1, t), lerp(y0, y1, t)));
        }
        return result;
    }
    

    The code is much simpler too (and lerp is useful for all sorts of things other than line drawing).

Leave a Reply