Pixels in angled gradient tool

Graphics related stuff,
just wondering if anyone has any idea on some tips for rendering a gradient (ex: color interpolating from yellow to orange from one side of the screen to another) when the direction of the blending isn't simply horizontal or vertical.

If it was simply horizontal, you'd only need to figure out one row and then repeat for every row.

But, in Photoshop for example, the interface has you drag your mouse to create a direction vector that decides at which angle the gradient goes.

When it's angled, drawing oblique lines could possibly miss some pixels. So how would this be prevented efficiently? Not looking for a complete solution just something to help me get started.

Edit:
It would still be nice to know how to do this with my own-made solution, but would this be a valid solution?
First make a texture as if the gradient was horizontal...
Then, given direction vector, find the angle, and then find the 4 uv points of the corners of the XY box? This would require using textures/GPU though, but I guess I don't have a problem with that.
Like http://i.cubeupload.com/E0qddD.png (colored box is actual screen/pixels, outside box is texture)?
Last edited on
Given a non-vertical straight line L1 with equation y = ax + b, y = -x/a is a straight line perpendicular to it.
Given a point P1 = (px, py), y = (px-x)/a + py is a straight line perpendicular to L1 that passes through P2. Therefore,
{ y = ax + b
{ y = (px-x)/a + py

ax + b = (px-x)/a + py
ax + b = px/a - x/a + py
(a + 1/a)x + b = px/a + py
(a + 1/a)x = px/a + py - b

x = (px/a + py - b) (a + 1/a)
y = ax + b
P2 = (x, y) is the point on L1 closest to P1, and the norm of P1-P2 is the distance of P1 to L1. By iteratively assigning the positions of every pixel in the image to P1 and determining whether the point is above or below L1, you can easily calculate the color each pixel should get.
Thank you helios!!!
Was busy with work, but I went through what you gave to re-derive it to understand it. I wouldn't have thought to set both y's equal to each other like that, but it makes sense to get the intersection like that.

Great explanation.
1
2
3
4
5
6
7
8
9
10
for each x, y pixel:
{
    double x2 = (x / a + y - b) / (a + 1.0 / a);
    double y2 = a * x2 + b;

    double d = distance(vec(x, y), vec(x2, y2)); // involves sqrt(...)

    double t = d / stroke_length;
    Color c = color_interpolation(Color::White, Color::Black, t);
    //  Write color to image pixel 


Here's the sexy picture I made: http://i.cubeupload.com/cc1Mdr.png
Making a = -1 / a changes the actual color gradient direction. (I wish it wasn't so easy to see the difference between, ex (64, 64, 64) and (65, 65, 65) in 8-bit component colors...)

I see it would require an if statement if we're going horizontal or vertical, but that's an easy check.

The most complex part of seems to be the sqrt() for distance() needed every iteration, but it works fine.
Last edited on
You can get rid of the sqrt() in the iteration by computing this constant factor only once: q = 1/cos(atan(a))
Then for each P1, instead of finding its distance to L1, you find its height h from L1, given by y in L1's equation when x = P1.x. The distance to L1 should be equivalent to h*q.

Explanation: a is how much y will change for a unit change in x, which is the same as saying that a = tan(alpha), therefore alpha = atan(a) = the angle of L1. Now, the angle of L1 to the horizontal is equal to the angle of a perpendicular of L1 to the vertical; in particular it's equal to the angle between the vertical and P1-P2. To project |P1-P2| onto the vertical you would need to do d2 = cos(alpha)*|P1-P2|. Therefore |P1-P2| = d2/cos(alpha) = d2/cos(atan(a))
Topic archived. No new replies allowed.