While debugging I looked at the lerp and it was calculating into a negative number at the start. So I added in checks for to low or high a value, and that seems to have fixed it. I'll answer the question myself unless someone can find a way to fix the formula that calculates the lerp, since that seems to be the culprit. My fix was this:

double lerp = (start - here) / (start - end);

if (lerp < 0d)
    lerp = 0d;
if (lerp > 1d)
    lerp = 1d;

Original Question
I'm applying a gradient to a texture per the answer in this topic: Code to generate a color gradient within a texture using a diagonal line

My code is referenced below. The code was seeming to work fine. I was using a two-color gradient: green to purple. However, when I changed it to two colors that blended well into a 3rd color, I could instantly see that something was wrong.

For example, blue to purple was producing a red element outside of the gradient area. If you also look closely, the blue itself is also enhanced on the outer edges. It's almost as if the two colors are mixing outside of the gradient area, when they should be the original colors.

Bad Gradient Example

Calling Code

This is applying to the center of an area 80x25.

Color[] colors = new Color[] { Color.Blue, Color.Purple };
float[] colorStops = new float[] { 0f, 1f };

Algorithms.GradientFill(new Point(40, 12), 3, 33, new Rectangle(0, 0, CellData.Width, CellData.Height), colors, colorStops);

Gradient Calculation Code

public static void GradientFill(Point position, int strength, int angle, Rectangle area, Color[] colors, float[] colorStops)
    double radians = angle * Math.PI / 180; // = Math.Atan2(x1 - x2, y1 - y2);

    Vector2 angleVector = new Vector2((float)(Math.Sin(radians) * strength), (float)(Math.Cos(radians) * strength)) / 2;
    Vector2 location = new Vector2(position.X, position.Y);

    Vector2 endingPoint = location + angleVector;
    Vector2 startingPoint = location - angleVector;

    double x1 = (startingPoint.X / (double)area.Width) * 2.0f - 1.0f;
    double y1 = (startingPoint.Y / (double)area.Height) * 2.0f - 1.0f;
    double x2 = (endingPoint.X / (double)area.Width) * 2.0f - 1.0f;
    double y2 = (endingPoint.Y / (double)area.Height) * 2.0f - 1.0f;

    double start = x1 * angleVector.X + y1 * angleVector.Y;
    double end = x2 * angleVector.X + y2 * angleVector.Y;

    for (int x = area.X; x < area.Width; x++)
        for (int y = area.Y; y < area.Height; y++)
            // but we need vectors from (-1, -1) to (1, 1)
            // instead of pixels from (0, 0) to (width, height)
            double u = (x / (double)area.Width) * 2.0f - 1.0f;
            double v = (y / (double)area.Height) * 2.0f - 1.0f;

            double here = u * angleVector.X + v * angleVector.Y;

            double lerp = (start - here) / (start - end);

            float newLerp;
            int counter;
            for (counter = 0; counter < colorStops.Length && colorStops[counter] < (float)lerp; counter++) ;

            counter = Math.Max(counter, 0);
            counter = Math.Min(counter, colorStops.Length - 2);

            newLerp = (colorStops[counter] - (float)lerp) / (colorStops[counter] - colorStops[counter + 1]);

            SetPixel(x, y, color);

The answer is that the amount to use during the lerp method was going below 0 or above 1. This will fix it:

lerp = MathHelper.Clamp((float)lerp, 0f, 1.0f);
  • \$\begingroup\$ Yeah, basically, the area which you are filling is not bound within your start and end position. \$\endgroup\$ – wolfdawn Jan 27 '14 at 20:37

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.