【问题标题】:Dip when joining blended antialiased lines加入混合抗锯齿线时下降
【发布时间】:2012-09-16 12:58:13
【问题描述】:

我在使用混合模式时加入两条抗锯齿线时遇到问题,我在它们加入的点处有所下降。通过混合模式,我的意思是我通过计算线条颜色与背景颜色的比率来绘制抗锯齿线条,因此当像素的比率为例如 70% 时,新像素为 0.7*线条颜色 + 0.3*背景颜色。我的线条抗锯齿功能基本上是由错误函数制成的(尽管我认为大多数抗锯齿功能都会出现同样的问题),如下所示:

所以当两条线相遇时,一条接一条地绘制,你会得到一个下降,两条线的连接处下降到它应该处于的强度的 75%,因为在那个点上,50% 的背景被保留为第一行,然后在绘制第二行后剩下 50% 的 50%,此时应该留下 0%:

我只能假设这是绘制带有连接线的抗锯齿光栅图形的常见问题,因此它必须有一个通用的解决方案,但我不知道这是什么。谢谢!

另外:为了清楚线条是如何绘制的,线条的宽度是使用高斯函数 (e^-x*x) 绘制的,并且两端使用凸起的误差进行四舍五入职能。您可以通过在 WolframAlpha 中输入 '0.5erfc(-x-5) * 0.5erfc(x-5) * e^(-y*y)' 来查看 10 px 长水平线的示例。

【问题讨论】:

  • 通常的方法是有一个绘制折线的算法,这样线之间的连接就不会像端点一样被绘制。
  • 好的,那么绘制折线的算法与单线算法有何不同?我考虑过从一条线到另一条线的尖锐截止点,主要问题是关节会是有角度的,这与我的高斯抗锯齿应该产生的结果不一致(关节应该是圆形的)。
  • 抱歉,我没有更多详细信息,否则我会留下答案而不是评论。多年前遇到同样的问题时,我只是使用过采样和过滤。
  • 折线算法有关于如何绘制关节和端点的特定规则(您通常可以选择样式——例如,圆形或方形)。您实际上最终得到了某种明确定义的边界 - 这就是您的抗锯齿然后模糊的内容。
  • 您是否查看了预组合的 Alpha 版和这个? lukepalmer.wordpress.com/2010/02/05/associative-alpha-blending

标签: algorithm graphics drawing antialiasing raster-graphics


【解决方案1】:

如果您将混合线段视为线段,则通常无法制作由混合线段组成的好看的连续线 - 如果您只是想到有一条线然后同时绘制下一条线段的情况角度,然后以 90 度角。 一行的像素颜色取决于它与下一行连接的角度

然后您需要考虑的是末端有角度的线段。

要绘制它,请查找有关斜角线连接斜接的文献(斜接可能更容易)。

【讨论】:

    【解决方案2】:

    如果你用混合来绘制相邻的线,这是一个非常不可能的问题。

    考虑这一点的一个好方法是理想形状的距离函数。像素强度映射(通过某些函数)到形状的距离。有两条完美的线条,这只是最低限度。

    不幸的是,这意味着您需要与可能影响像素的每条线的距离。这就是一些文本光栅化器所做的。

    或者你只是不加重线条。它们按像素打开或关闭。然后你让超级采样处理剩下的事情。这就是像 flash 或 svg 这样的软件矢量渲染器所做的。

    【讨论】:

      【解决方案3】:

      thang 的想法可能是一个很好的起点:简而言之,控制“画笔”的中心而不是边缘。理想情况下,如果使用漂亮的圆形端点,您会通过这种方法看到漂亮的圆角。

      然而事实并非如此美好。问题是您首先将一条线 alpha 混合到您的目标曲面,然后您 alpha 混合该曲面上已经有一条线“烧入”的第二条线。最终结果将是在两个半透明像素相互重叠的角落处出现更胖的斑点(例如,如果您尝试在 Gimp 中绘制连接线段,您可能会在实际中观察到这种效果)。

      我认为在此设置上使用这种简单的一次一行的方法无法解决此问题(因此您需要按照其他答案提出的方向,使用折线算法或超级采样)。但是,根据您的目标,您可能有一个可行的解决方案。

      这是将您的图形对象预渲染到具有 alpha 的单独表面。在此,您可以组合各个线的 alpha(例如从目标像素和绘制的像素中获取最大的),这将为您提供预期的结果(角落上没有脂肪斑点)。

      缺点是您需要一个单独的表面,当对象完成时您必须在目标上进行 blit:这需要额外的内存和处理时间。

      如果您只需要渲染到某个平面(单色)目标,您可以解决此问题:那么您根本不需要执行适当的 alpha 混合,并且可以在适当的位置进行组合 alpha 计算。如果背景很容易计算(例如坐标网格),则此解决方案可能是可行的,因此总的来说,当您可以轻松获得背景的原始像素值时,您可以结合它(确实这也可以如果你将渲染的背景保留在一个单独的表面中,但你又在内存中有另一个表面,所以可能没有任何结果。

      如果您的问题是其他性质的,如果您将这些渲染的单独表面保留在周围,这也可能是可行的,这实际上是您预渲染线条对象,然后仅将它们用作纹理或图块。

      【讨论】:

        【解决方案4】:

        最终我找到了这个问题的答案。直接在主图像上直接绘制一条线,这是没有明智的方法的,因为您不希望将线条混合在一起,而是希望将它们加在一起然后得到线条总和的结果融合到主图像中。

        但是,如果您必须将所有这些线绘制到一个单独的缓冲区,然后将整个缓冲区混合到主缓冲区中,那将是不实用的,这是我在提出这个问题之前认为并认为不合适的内容。值得庆幸的是,从那以后我完全改变了我的方法,而不是使用一个缓冲区来绘制一个又一个元素,而是使用逐像素方法,其中每个像素都是通过遍历要绘制的元素列表直接计算的,为了并行化(使用 OpenCL)。因此,不必使用额外的缓冲区,我只需要一个可以容纳一些额外像素值的小数组,并且在要绘制的元素列表中,我有用作括号的元素,例如,而不是:

        image => (blend) line1 => (blend) line2 => (blend) line3

        我可以:

        image => (blend) [0 => (add) line1 => (add) line2 => (add) line3]

        这是通过为括号的每个深度级别设置一个值数组来替换单个像素值的使用来完成的,因此在这种情况下,v[0] 您将拥有来自image 的像素,那么您将从 0 处的 v[1] 开始并向其中添加每一行,当添加所有行时,括号的关闭将使 v[1] 混合到 v[0] 中,并且正确的结果像素值将在那里。

        就是这样,它很简单,如果你不允许自己在 Photoshop 中使用相当于一组图层,这只是一个问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-29
          • 1970-01-01
          • 1970-01-01
          • 2014-02-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多