2
\$\begingroup\$

How can I generate a linear gradient along a vector?

Here is the function I'm looking for:

function CreateGradient(x,y, x1,y1,x2,y2) {
    // x and y are the point in our image we are looking to create the  color for in grayscale
    // x1,y1,x2,y2 is the vector in which the linear gradient should run
    // Can be in any language
}

What I have so far (that doesn't work):

var width = 2.0;
var offset = 0;

var convX = ((x / RES) * width - width/2) - offset;
var convY = ((y / RES) * width - width/2) - offset;

var angle = Math.atan(y1-y2, x1-x2);


var rx = Math.cos(angle);
var ry = Math.sin(angle);

var here = convX * rx + convY * ry;
var start = x1 * rx + y1 * ry;
var end = x2 * rx + y2 * ry;

var lerpValue = (start - here) / (start - end);

var val = lerp(0,255,clamp(lerpValue,0.0,1.0));

RES is the total resolution of the picture. val in the value (0-255) which represents the R G and B values of the pixel.

Edit: I have it now thanks code for the future:

var x1 = 0;
var y1 = 0;
var x2 = 255;
var y2 = 255;

var dx = x2-x1;
var dy = y2-y1;

var rx = x-x1;
var ry = y-y1;

var t = ((rx*dx) +(ry*dy)) / ((dx*dx) + (dy*dy));


return lerp(0,255,t);
\$\endgroup\$
2
  • \$\begingroup\$ Ok I'll make it easier then how to you generate a linear gradient between two points (x1,y1,x2,y2) \$\endgroup\$
    – Dave3of5
    Jul 9, 2016 at 16:12
  • \$\begingroup\$ Ok I've updated is this clearer ? \$\endgroup\$
    – Dave3of5
    Jul 9, 2016 at 16:20

2 Answers 2

4
\$\begingroup\$

It looks an introduction to linear algebra is in order, or more precisely the dot product:

dot(a, b) = |a| |b| cos(Theta)

Why is it helpful? Because of its relation to the scalar/vector projection, the length of projection of vector a onto vector b is

lenPA = |a| cos(theta)

or more practically, derived from dot product definition:

lenPA = (a . b) / |b|

and when you know how far the current coordinate is projected onto the line between gradient's step1 and step2, all you have to do is to normalize it:

t = lenPA / |b|
color = lerp(color1, color2, t)

where a is relative position of fragment xy to the gradient step1 and b is non-normalized gradient (direction) going from step1 to step2.
copy/paste code (for shadertoy):

vec2 step1 = vec2(200, 200);
vec2 step2 = vec2(400, 400);

vec4 color1 = vec4(0.0,0.5,1.0,1.0);
vec4 color2 = vec4(1.0,5.0,0.0,1.0);

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    //----constant, can pre compute------
    vec2 gDrirection = step2 - step1;
    float lenSq = dot(gDrirection, gDrirection);//len(gDrirection)^2
    //-----------------------------------
    vec2 relCoords = fragCoord - step1;
    float t = dot (relCoords, gDrirection) /  lenSq;
    fragColor = mix(color1, color2, t); //mix = lerp
}
\$\endgroup\$
2
  • \$\begingroup\$ Hey thanks, I don't understand those wikipedia articles fully. But this is what I'm looking for I just needed to know how to project a point onto a 2d vector I think I can take it from here thanks. \$\endgroup\$
    – Dave3of5
    Jul 9, 2016 at 18:28
  • \$\begingroup\$ @Dave3of5 Just read the glsl code - dot the relative coordinates to first gradient point coords - step1 and the gradient direction step2 - step1 and than divide it by squared length of latter vector: float t = dot (relCoords, gDrirection) / lenSq; <- thats all relevat code. Or are you not sure how do vector operations like subtracting or dot product? Dot product is member-wise (x to x, y to y etc.) multiplication of which products you sum to single number. \$\endgroup\$
    – wondra
    Jul 9, 2016 at 18:41
2
\$\begingroup\$

is this what you want ?

    float endPercent = curLength / totalLength;                                                         // Calculates the percent of colour at the ending point of the line to be used in current pixel 
    float startPercent = 1 - (curLength / totalLength);                                                 // Calculates the percent of colour at the starting point of the line to be used in current pixel 

    float a = Math.abs(end.getColour().getAInInt() * endPercent + start.getColour().getAInInt() * startPercent);    //Interpolating alpha
    float r = Math.abs(end.getColour().getRInInt() * endPercent + start.getColour().getRInInt() * startPercent);    //Interpolating red 
    float g = Math.abs(end.getColour().getGInInt() * endPercent + start.getColour().getGInInt() * startPercent);    //Interpolating green 
    float b = Math.abs(end.getColour().getBInInt() * endPercent + start.getColour().getBInInt() * startPercent);    //Interpolating blue 

    return new PixelData(a, b, g, r);                                                                   // returing the intepolated value 

enter image description here

\$\endgroup\$
2
  • \$\begingroup\$ hey not quite but thanks so much for responding. \$\endgroup\$
    – Dave3of5
    Jul 9, 2016 at 19:50
  • \$\begingroup\$ @Dave3of5 sorry i could not help much. :) \$\endgroup\$
    – user82860
    Jul 9, 2016 at 22:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .