[英]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;
}
预期的结果是填充这个形状。(它是使用多边形网格创建的):
使用 FilledPolygon 网格的实际结果:
您的代码似乎有几个问题,我不会专注于此。
基于绘制轮廓然后填充“内部”运行的方法在一般情况下不起作用,因为轮廓在顶点和交叉点处连接,并且交替外部边缘内部边缘外部以不可恢复的方式被破坏(你不能只看一行就知道要填充哪个段)。
你最好使用标准的多边形填充算法。 您会在 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.