加入混合抗锯齿线时浸渍

时间:2012-09-16 12:58:13

标签: algorithm graphics drawing antialiasing raster-graphics

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

0.5+0.5erf(-x)

所以,当两条线相交时,一条线一条接一条,你会得到一个下降,两条线的关节下降到它应该达到的强度的75%,因为在那一点上50%的背景被保留了第一行然后50%的50%保留在第二行之后,当剩下0%时:

1 - (0.5erfc(-x) * 0.5erfc(x))

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

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

4 个答案:

答案 0 :(得分:1)

如果您将它们视为段,那么通常无法实现由混合段组成的漂亮的连续线 - 如果您只考虑具有一条线然后在相同的位置绘制下一段的情况角度然后是90度角。 一行的像素颜色取决于它与下一行连接的角度

然后你需要考虑的是具有倾斜结束的片段。

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

答案 1 :(得分:0)

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

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

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

或者你只是不加重线。它们可以按像素开启或关闭。然后你让超级采样照顾其余部分。这就是像flash或svg那样的软件矢量渲染器。

答案 2 :(得分:0)

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

但事实并非如此。问题是,您首先将一条线与您的目标曲面进行Alpha混合,然后在该曲面上对第二条线进行alpha混合,该曲线已经有一条线“已烧入”。最终的结果是在拐角处有一个更胖的斑点,两个半透明的像素互相咬合(如果您尝试在Gimp中绘制连接线段,您可以在实际中观察到这种效果)。

我认为这不能在这个设置上使用这种简单的一行一线方法(所以你需要使用折线算法或超级采样来指向其他答案提出的方向)。但是,根据您的目标,您可能有一个可行的解决方案。

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

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

如果你只需要渲染到一些平坦的(单色)目标,你可以解决这个问题:那么你根本不需要执行正确的alpha混合,并且可以在适当的位置进行组合alpha计算。如果背景是容易计算的(例如坐标网格),这个解决方案可能是可行的,因此总体上当您可以轻松获得背景的原始像素值时,您可以与之相结合(真的,这也可以工作)如果你保留你在一个单独的表面上渲染的背景,但是你再次在内存中有另一个表面,那么可能没什么可赢的。)

如果您的问题属于其他性质,如果您将这些渲染的单独曲面保持在周围,那么它也可能是可行的,这基本上是您预先渲染线条的对象,后来只将它们用作纹理或图块。

答案 3 :(得分:0)

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

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

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

我可以:

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

这是通过使用每个深度级括号的值数组来替换单个像素值的使用来完成的,所以在这种情况下v[0]你有来自{{1}的像素},然后你从0 image开始并添加每一行,当添加所有行时,括号的关闭会使v[1]混合到v[1]并且正确的结果像素值就在那里。

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