Friday, August 7, 2015

xna - Creating a gradient for a texture - Why is the color becoming dark on one side?


Updated
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--;
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);
}
}
}

Answer



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);

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...