我想制作一个可以生成点对点渐变的应用程序(就像 Photoshop 一样)。我熟悉如何生成从上到下的渐变,但不是点对点。这在概念上是如何完成的。
谢谢
我不能说这是否正是Photoshop 的做法,或者说这是最佳的做法,但这应该是基本原则。
将这两点视为定义一个向量。您可以为此找到一个法线向量,它将垂直于原始向量(因为这是法线向量的定义)。
对于线上的每个离散点(像素),计算渐变颜色,就像计算与向量长度相同的上下(或左右)渐变。然后绘制一条选定颜色的线,使其穿过当前选定的点并与法向量平行。
它实际上与您用于上下渐变的方法非常相似,只是它是旋转的。
基于迈克尔·马德森的回答——
对于要填充的区域中的每个点,计算线段上的最近点。(你必须用谷歌搜索,但有很多例子。)在计算最近点的某个时刻,计算出的值的范围从起点的 0 到终点的 1。将其插入到您的渐变函数中。
该算法的概述基本上是......
pc = # the point you are coloring now
p0 = # start point
p1 = # end point
v = p1 - p0
d = Length(v)
v = Normalize(v) # or Scale(v, 1/d)
v0 = pc - p0
t = Dot(v0, v)
t = Clamp(t/d, 0, 1)
color = (start_color * t) + (end_color * (1 - t))
如果您将 v 缩放 1/d^2 而不是 1/d,您实际上可能会失去 make t/d just t。但无论如何......我认为这会让你到达那里。也许很明显,前半部分是“静态的”,所以你只需要遍历最后四行。
此例程为图像中的每个点调用您的函子,并使用适当的值。使用该值作为颜色查找表的索引,您将获得混合。Functor 有这个原型:void (int x, int y, int value)。
/** Produce a linear gradient.
This implementation uses float values.
*/
struct Linearf
{
template <class Functor>
void operator() (
int rows,
int cols,
int x0, int y0,
int x1, int y1,
int const scale,
Functor f)
{
if (x0 != x1)
{
// 1/m'
float const m = float (y1 - y0) / (x0 - x1);
for (int y = 0; y < rows; ++y)
{
float const p0 = m * (y - y0) + x0;
float const p1 = m * (y - y1) + x1;
float const d = (scale + 0.9999f) / (p1 - p0);
for (int x = 0; x < cols; ++x)
{
if (x < p0)
{
f (x, y, 0);
}
else if (x >= p1)
{
f (x, y, scale);
}
else
{
f (x, y, d * (x - p0));
}
}
}
}
else
{
// Special case for horizontal lines.
}
}