【问题标题】:Draw thick, feathered line with variable thickness in plane C#在平面 C# 中绘制厚度可变的粗羽毛线
【发布时间】:2016-03-06 20:35:10
【问题描述】:

我正在创建一个高度图绘制工具,它使用样条线绘制高度图,其值从 0 到 1。样条线由几个点组成,每个点都有不同的厚度(大小/宽度),并且会被插值。该工具在高度图上绘制路径的投影,其厚度由用户指定,乘以每个点的大小和用户指定的羽化。到目前为止,我已经设法实现了一切,我的实现是这样的:

为了填充这些矩形,我使用 Bresenham 线算法的变体绘制了多条线:

public void drawLine(Point fromPoint, Point toPoint, float fromValue, float toValue, ref float[,] grid)
{
    int x0 = fromPoint.x, y0 = fromPoint.y, x1 = toPoint.x, y1 = toPoint.y;
    int dx = Mathf.Abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
    int dy = -Mathf.Abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
    int err = dx + dy, e2;
    int x = x0, y = y0;
    Vector2 target = new Vector2(x1 - x0, y1 - y0);
    while(true)
    {
        Vector2 current = new Vector2(x - x0, y - y0);
        float addValue = Mathf.Lerp(fromValue, toValue, current.magnitude / target.magnitude);

        plot(x, y, addValue, 1f, ref grid);
        if (sample) grid[x, y] = supersample(x, y, ref grid);

        if (x == x1 && y == y1) break;
        e2 = 2 * err;
        if (e2 > dy)
        {
            err += dy;
            x += sx;
        } else if (e2 < dx)
        {
            err += dx;
            y += sy;
        }
    }
}

到目前为止一切顺利!然而,当样条曲线上的一个点与其他点的大小不同时,就会出现问题。由于该算法不绘制抗锯齿线,因此绘制的形状开始看起来参差不齐。发生这种情况是因为我为较大点的垂线的每个像素画了一条线,并将它们的端点映射到较小点的垂线。所以基本上线开始在更窄的点周围相互重叠。 我试图绘制一个图形来可视化问题:

所以我的最终结果是这样的:

您可以看到羽毛部分非常锯齿。

我尝试使用 Xiaolin Wu 的线条算法来绘制线条,但导致像素之间出现间隙,并且填充变得不一致。 到目前为止,仅应用高斯模糊会使事情看起来更好,但它并不能完全解决问题而且它很重,所以我也放弃了这个选项。

我确实需要在不使用任何库的情况下实现这一点,因此非常欢迎任何有关如何解决此问题的建议。谢谢!

【问题讨论】:

  • 你的目标是什么:Winforms? WPF? ASP? ...?? 总是相应地标记您的问题!
  • @TaW 这是一个 Unity 项目。我正在将值写入 float[,] 数组。

标签: c# algorithm unity3d spline heightmap


【解决方案1】:

听起来,如果多条线绘制到特定点,您想为每条线添加“更少”。绘制到特定点的线越多,每条线对它的影响就越“少”。

类似...(未编译的示例)

int[,] gridDrawCount = new int[grid.GetLength(0),grid.GetLength(1)];

...

//inside the loop
gridDrawCount[x,y]++;
plot(x, y, addValue/gridDrawCount[x,y], 1f, ref grid);  //I added the divide by part

您可能希望,而不是如上所示在循环内进行除法,而是在循环之后遍历您的网格,然后每个值除以 gridDrawCount 值(注意 div 被零除)- 应该给出稍微不同,可能更一致的效果,但显然会更慢。

【讨论】:

  • 我昨天实际上采用了类似的方法:我没有预先定义线条的颜色,而是在线条算法绘制它时定义每个像素的颜色。我将像素的位置投影在连接点 i 和点 i+1 的中心线上,然后测量这些像素之间的距离以计算羽毛。我将绘制的像素添加到另一个数组中,因此如果下一行越过相同的像素,我不必再次进行这些计算,但即使没有该数组,它也不会过度绘制,因为它只会重新计算像素的相同值.可悲的是,像素仍然是锯齿状的。
  • 仍然锯齿状:我怀疑这是因为您在计算中没有进行任何抗锯齿处理。它现在是否至少沿长度正确显示了羽毛。 (使用单独的数组很好!)
  • 向下和肮脏的抗锯齿可以通过为每条“正常”线绘制第二条线来实现,半 alpha,并将线的源或目标偏移 1 个像素。 (或者将 alpha 除以 3,然后画两条额外的线,偏移量分别为 +1 和 -1 等...)
【解决方案2】:

我想出了解决问题的方法。这不是最理想的,但它现在对我有用。

在我的问题中,我解释说该算法为该点的垂直线的每个像素绘制一条线到下一个点的垂直线的映射像素(基于百分比)。这导致了过度绘制,因此 Glurth 建议我保留一组已绘制的点。该方法实际上导致了更多的锯齿,因为线条并不总是将正确的值绘制到正确的像素(因为映射 - 它是一个浮点百分比,必须四舍五入才能从下一条垂直线获取像素)。

所以我所做的是将当前绘图线中的每个像素投影到连接点的中心线上,并测量线像素与投影线之间的距离。在此基础上,我计算出羽毛。

当然,由于样条路径被投影到像素网格上,因此会出现锯齿,我的解决方案(目前)是在绘制的像素上使用半径为 1f 的高斯模糊来平滑结果。

整个事情并不算太慢,它给出了一个相当好的结果,这对于现在来说已经足够了。由于每两点的垂直线的末端形成一个多边形,我可以对其进行三角剖分(手动设置三角形,我不需要复杂的三角剖分算法)并像这样填充它,而不是绘制多条经常绘制在多次相同的像素。

希望这很有用。如果有人决定尝试我的方法,我建议他们立即跳到三角剖分而不使用画线。我从画线开始,所以我使用了它,但我认为它不是最佳的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-22
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    相关资源
    最近更新 更多