【问题标题】:Point to point linear gradient?点对点线性渐变?
【发布时间】:2010-05-19 22:03:48
【问题描述】:

我想制作一个可以生成点对点渐变的应用程序(就像 Photoshop 一样)。我熟悉如何生成从上到下的渐变,但不是点对点。这在概念上是如何完成的。

谢谢

【问题讨论】:

  • 也许可以看看 GIMP 源代码。虽然您可能找不到有关该概念的描述,但它可能会有所帮助。

标签: c++ c algorithm graphics gradient


【解决方案1】:

我不能说这是完全 Photoshop 是如何做到的,或者说这是最优化的方法,但这应该是基本原则。

将这两点视为定义一个向量。您可以为此找到一个法线向量,它将垂直于原始向量(因为这是法线向量的定义)。

对于线上的每个离散点(像素),计算渐变颜色,就像计算与向量长度相同的上下(或左右)渐变。然后画一条选定颜色的线,使其通过当前选定的点并与法向量平行。

它实际上与您用于上下渐变的方法非常相似,只是它是旋转的。

【讨论】:

  • 我认为你是对的,这不是 Photoshop 的确切方式,也不是最佳方式,但你很接近。你真正想做的是从左到右、从上到下扫描填充的图像。由于线性渐变的切割是线性的,因此对于每条扫描线,您可以计算开始和结束颜色,然后在它们之间快速插值(最好使用 Bresenham 算法)。您正在执行与绘制斜线相同的计算量,但您正在以缓存友好的方式访问内存。
【解决方案2】:

以迈克尔·马德森的回答为基础-

对于您要填充的区域中的每个点,计算线段上的最近点。 (你必须用谷歌搜索,但有很多例子。)在计算最近点的某个时刻,计算出的值的范围从起点的 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。但无论如何......我认为这会让你到达那里。也许很明显,前半部分是“静态的”,所以你只需要循环最后四行。

【讨论】:

  • 我确信绘制垂直线会更快,fwiw。 :)
  • 绘制垂直线很可能会更快,但如果渐变不是轴对齐的,也可能会引入很多锯齿。在这种情况下,逐点工作很可能(理论上)给出更好看的结果。
  • 太慢了,你没有利用线性渐变中的“线性”。计算每条扫描线的开始和结束颜色,插值。
  • 嗨,我不确定你(dash-tom-bang)是否会看到这个,但我想知道你是否知道与此类似的算法,但对于围绕半径运行的渐变(径向渐变)谢谢!
  • 当然-只需使用距离指向。在 d=0 使用“开始”颜色(设置 t=0),在 d>=endDist 使用“结束”(t=1)颜色,在上面最后一行中使用 d/endDist 作为您的 t 值.
【解决方案3】:

此例程为图像中的每个点调用您的仿函数,并使用适当的值。使用该值作为颜色查找表的索引,您将获得混合。 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.
    }
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-30
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多