繁体   English   中英

java 中的扫描线多边形填充算法问题

[英]Problem with Scan-Line Polygon Filling algorithm in java

(请不要将此问题标记为不清楚,我花了很多时间发布它;))

好的,我正在尝试制作一个简单的 2d java 游戏引擎作为学习项目,其中一部分是将填充的多边形渲染为特征。 我正在自己创建这个算法,我真的不知道我做错了什么。 我的过程是这样的:遍历每一行,获取该行中的点数,然后获取该行中每个点的 X 位置,然后再次遍历该行,这次检查循环中的 x 是否为在点数组中的一条线内,如果是,请绘制它。

免责声明:Polygon class 是另一种类型的网格,它的 draw 方法返回一个 int 数组,其中包含通过每个顶点绘制的线。 免责声明 2:我尝试了其他人的解决方案,但没有一个真正帮助我,也没有一个真正正确地解释它(这不是学习项目的重点)。

绘制方法被称为每帧一个。
填充多边形:

@Override
    public int[] draw() {
        int[] pixels = new Polygon(verts).draw();
        int[] filled = new int[width * height];

        for (int y = 0; y < height; y++) {
            int count = 0;
            for (int x = 0; x < width; x++) {
                if (pixels[x + y * width] == 0xffffffff) {
                    count++;
                }
            }

            int[] points = new int[count];
            int current = 0;
            for (int x = 0; x < width; x++) {
                if (pixels[x + y * width] == 0xffffffff) {
                    points[current] = x;
                    current++;
                }
            }

            if (count >= 2) {
                int num = count;
                if (count % 2 != 0)
                    num--;

                for (int i = 0; i < num; i += 2) {
                    for (int x = points[i]; x < points[i+1]; x++) {
                        filled[x + y * width] = 0xffffffff;
                    }
                }
            }
        }

        return filled;
    }


Polygon class 只是使用了 Bresenham 的线算法,与问题无关。
游戏class:

@Override
    public void load() {
        obj = new EngineObject();
        obj.addComponent(new MeshRenderer(new FilledPolygon(new int[][] {
                {0,0},
                {60, 0},
                {0, 60},
                {80, 50}
        })));
        ((MeshRenderer)(obj.getComponent(MeshRenderer.class))).color = CYAN;
        obj.transform.position.Y = 100;
    }

预期的结果是填充这个形状。(它是使用多边形网格创建的):

图像1

使用 FilledPolygon 网格的实际结果:

img2

您的代码似乎有几个问题,我不会专注于此。

基于绘制轮廓然后填充“内部”运行的方法在一般情况下不起作用,因为轮廓在顶点和交叉点处连接,并且交替外部边缘内部边缘外部以不可恢复的方式被破坏(你不能只看一行就知道要填充哪个段)。

你最好使用标准的多边形填充算法。 您会在 Web 上找到许多描述。

对于一个简单但效率较低的解决方案,请按以下方式工作:

  • 处理最小和最大坐标之间的所有线; Y为当前纵坐标;

    • 在边缘循环;

    • 如果 y ≥ Y 或 y < Y ,则为每个顶点分配正号或负号(注意不对称;);

    • 每当边的端点有不同的符号时,计算边和线之间的交点;

    • 你会得到偶数个路口; 水平排序;

    • 在每个其他点之间绘制。

通过在所谓的“活动列表”中跟踪哪些边缘与当前行交叉,您可以获得更有效的解决方案。 检查称为“扫描线填充”的算法。

请注意,您暗示pixels[]width*height大小与filled[]相同。 基于损坏的 output,我想说它们是不一样的。

否则,如果您只想填充扫描线(假设一切都是凸的),那么该代码过于复杂,只需查找端点并在它们之间循环:

public int[] draw() {
    int[] pixels = new Polygon(verts).draw();
    int[] filled = new int[width * height];

    for (int y = 0; y < height; y++) {
        int left = -1;
        for (int x = 0; x < width; x++) {
            if (pixels[x + y * width] == 0xffffffff) {
                left = x;
                break;
            }
        }
        if (left >= 0) {
            int right = left;
            for (int x = width - 1; x > left; x--) {
                if (pixels[x + y * width] == 0xffffffff) {
                    right = x;
                    break;
                }
            }
            for (int x = left; x <= right; x++) {
                filled[x + y * width] = 0xffffffff;
            }
        }
    }

    return filled;
}

然而,这种方法依赖于在视图中包含整个多边形,这在现实生活中可能并不总是如此。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM