在平面C#中绘制厚度可变的厚羽毛线

时间:2016-03-06 20:35:11

标签: c# algorithm unity3d spline heightmap

我正在创建一个高度贴图绘画工具,它使用样条线来绘制高度贴图,其值为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;
        }
    }
}

到目前为止一切顺利!然而,当样条曲线上的一个点具有与其他点不同的尺寸时,问题就出现了。由于此算法不绘制抗锯齿线,因此绘制的形状开始看起来很锯齿。这是因为我为较大点的垂直线的每个像素绘制一条线,并将它们的端点映射到较小点的垂直线。所以基本上线条开始在更狭窄的点附近相互重叠。 我试图绘制图形来可视化问题: http://i.imgur.com/Us5flFf.jpg

所以我的最终结果如下: 2

你可以看到羽状部分是如何锯齿状的。

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

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

2 个答案:

答案 0 :(得分:1)

听起来,如果有多行正在绘制特定点,则需要为每一行添加“less”。绘制到特定点的线越多,每条线的“更少”应该影响它。

像......(未编译的例子)

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为零) - 应该给出一个稍微不同,可能更一致的效果,但显然会更慢。

答案 1 :(得分:0)

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

在我的问题中,我解释说该算法为点的垂直线的每个像素绘制一条直线,指向下一个点垂直线的映射出的像素(基于百分比)。这导致了透支,所以Glurth建议我保留一系列我已经吸引的点。这种方法实际上引起了更多的晃动,因为线条并不总是向正确的像素绘制正确的值(因为映射 - 它是一个浮点百分比,必须舍入才能从下一条垂直线获得像素)。

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

Project pixel onto center line

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

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

希望这很有用。如果有人决定尝试我的方法,我建议他们马上跳到三角测量而不是使用画线。我开始绘制线条所以我使用了它,但在我看来它并不是最优的。