【问题标题】:LibGdx PolygonSpriteBatch not drawing all polygonsLibGdx PolygonSpriteBatch 未绘制所有多边形
【发布时间】:2015-07-20 12:13:42
【问题描述】:

我正在尝试使用 libGdx 中的 PolygonSpriteBatch 渲染一个简单的 2D 风景轮廓,以在屏幕上绘制填充的多边形。我不知道为什么,但代码似乎只是在渲染每个其他多边形,从而导致屏幕上出现条纹图案(见下面的屏幕截图 - 背景是红色的,风景是绿色的)。

我用来绘制风景的代码如下所示。这将遍历世界坐标中的一组相邻点(使用landarray.getOnScreen() 检索),计算屏幕坐标,为每个段创建一个PolygonRegion 并绘制它们。我使用的纹理只是一个 100x100 像素的纯白色方块。我没有使用任何相机或视图,只是将世界坐标动态转换为屏幕坐标并直接绘制到图形屏幕。

请注意,我正在从使用 Slick2D 的工作版本重新编写此游戏(因此在此阶段不使用相机),并且下面的代码或多或少没有改变(除了翻转 y 轴高度计算)工作版本,它绘制了一个连续的景观。

public void drawPoly() {
    System.out.println("Mountains - drawShape()");
    // Calculate screen bottom-edge Y taking into account values = bHEIGHT
    int scrBtmY = scrTopY - Gdx.graphics.getHeight();
    if (FastMath.abs(scrBtmY) == bHEIGHT) {         // Wrap-around bug at y == bHEIGHT
        scrBtmY = 0;
    }

    // Draw the land masses on-screen that are in the results list
    polyBatch.begin();
    polyBatch.setColor(landColour);
    ArrayList<Landmass> masses = landarray.getOnScreen(scrLeftX, scrTopY, scrBtmY);
    for (Landmass lm : masses) {
        /* Calculate the on-screen start and end x and y values taking into account
           wrapping in 'buffer space'
           Wrap around - low negative numbers (> -25) are 'just off screen' start or
           end points, large ones are wrap-around points
         */
        int sx = (int) lm.start.x - scrLeftX;
        if (sx < -Settings.Physics.LANDSITEWIDTH) {
            sx = sx + bWIDTH;
        }

        int sy = (int) lm.start.y - scrBtmY;

        int ex = (int) lm.end.x - scrLeftX;
        if (ex < -Settings.Physics.LANDSITEWIDTH) {     // Wrap around
            ex = ex + bWIDTH;          
        }

        int ey = (int) lm.end.y - scrBtmY;
        ex = ex - 1;        // In case over-lapping regions is causing stripes

        System.out.format("start (%d, %d)\t end (%d, %d)%n", sx, sy, ex, ey);

        // Construct and draw the polygon
        float[] vertices = new float[8];
        vertices[0] = sx;
        vertices[1] = 0;
        vertices[2] = ex;
        vertices[3] = 0;
        vertices[4] = ex;
        vertices[5] = ey;
        vertices[6] = sx;
        vertices[7] = sy;
        short[] triangles = new short[] {0, 1, 2, 0, 2, 3};
        PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid), vertices, triangles);
        polyBatch.draw(polyReg, sx, 0);
    }
    polyBatch.end();
}

我已经包含了一个调试行来打印各个多边形(陆地段)的屏幕坐标,并且一次 drawPoly() 迭代的输出如下所示。这显示了应该在屏幕上绘制的每个段的开始 (x, y) 和结束 (x, y) 坐标。从输出来看,绘制的多边形看起来彼此相邻,因此它们之间不应有间隙。

Mountains - drawShape()
start (53, 265)  end (77, 358)
start (78, 358)  end (102, 376)
start (103, 376)     end (127, 406)
start (128, 406)     end (152, 371)
start (153, 371)     end (177, 429)
start (178, 429)     end (202, 447)
start (203, 447)     end (227, 433)
start (228, 433)     end (252, 415)
start (253, 415)     end (277, 478)
start (278, 478)     end (302, 490)
start (303, 490)     end (327, 524)
start (328, 524)     end (352, 519)
start (353, 519)     end (377, 551)
start (378, 551)     end (402, 556)
start (403, 556)     end (427, 543)
start (428, 543)     end (452, 470)
start (453, 470)     end (477, 505)
start (478, 505)     end (502, 482)
start (503, 482)     end (527, 513)
start (528, 513)     end (552, 476)
start (553, 476)     end (577, 479)
start (578, 479)     end (602, 460)
start (603, 460)     end (627, 475)
start (628, 475)     end (652, 426)
start (653, 426)     end (677, 453)
start (-22, 449)     end (2, 406)
start (3, 406)   end (27, 357)
start (28, 357)  end (52, 265)

我在这个网站上搜索了一系列帖子,这些帖子帮助我获得了上面的代码,但没有看到任何有这个特定问题的帖子。

请注意,我仅将其作为桌面版本运行,并为此启用了 Java 8。使用 libGdx 1.5.6 和 1.6.0 进行测试,结果相同。

我已经制作了一个独立版本的代码来复制问题,以防有人想在家尝试。这使用 libGdx 1.6.0 和(我假设)Java 6,并显示了上述问题(至少在我的 PC 上)。这些文件可以在这里找到:java sourcepng imagewhole project 压缩文件。

有人知道为什么我会在屏幕上出现条纹效果吗?

【问题讨论】:

  • 我开发了一种解决方法,使用带有 ShapeType.Filled 的 ShapeRenderer 并使用我计算的顶点为每个段绘制两个三角形。但是,这并不能回答上述问题。

标签: java libgdx


【解决方案1】:

PolygonRegion 顶点坐标应该是相对于多边形的 TextureRegion 原点的偏移量,而不应该是绝对屏幕坐标,这是我认为你在输出中所做的(因为你'重新创建具有未修改坐标的顶点)。

我建议你修改你的顶点坐标变成长度。

我遇到了同样的问题,这是 Google 上唯一的结果。我想我会分享我的解决方案。

编辑:

为了清楚起见,这是我自己的解决方案。

vertices = new float[] { 0, 0,
                        lTX-lBX, lTY-lBY,
                        rTX-lBX, rTY-lBY,
                        rBX-lBX, rBY-lBY};

抛开我糟糕的命名方案不谈,上面根据 UV 坐标定义了一个四边形多边形。 lBX (left base x) 和 lBY (left base y) 是我的多边形在屏幕坐标中的起始位置。它们直接位于 TextureRegion 的原点,因此偏移 0,0。 lTX(左上x)和lTY(左上y)是下一个位置。同样,我通过从 lBX 和 lBY 中减去两者来找到到原点的距离。对于我的其余坐标,依此类推。

【讨论】:

  • 好的,谢谢。是的,我使用屏幕坐标作为我的顶点。我从 libgdx PolygonRegion javadoc 中获取了这个:“vertices - 包含相对于源区域的 2D 多边形坐标,以像素为单位”。您能否阐明您对“源区域”的含义的理解。我已经更改了我的测试应用程序,以便每个 PolygonRegion 的第一个坐标对是屏幕坐标中的原点(将其作为“源”),其余 3 对是距此的距离,但它仍然给出错误结果。我想我误解了“源区域”在这种情况下的含义。
  • 一个 libgdx PolygonRegion 必须有一个关联的 TextureRegion。引用文档:“在纹理区域顶部定义多边形形状以避免绘制透明像素。”这是您的源区域。原点是您的 TextureRegion 的左下角(或我不完全确定的右上角)。 (编辑:意外按下回车)如果您的 TextureRegion 是整个纹理并且不是精灵表(例如),那么您的原点应定义为 (0,0)。
  • 如果您有兴趣查看我的实现,我已经在上面编辑了我的答案。
  • 完美。谢谢你,谢谢你,谢谢你。 :) 那是一种享受。我刚刚注意到,当我绘制区域时,PolygonSpriteBatch.draw() 方法采用 x 和 y 参数,因此 TextureRegion 不需要任何坐标设置。一切都是相对于 PolygonRegion 中的 (0, 0) 设置的,然后您告诉 PolygonSpriteBatch 在屏幕上的哪个位置绘制它,如下所示:PolygonSpriteBatch.draw(PolygonRegion, int x, int y); 我将上传我的测试应用程序以供将来参考,以便其他人可以看到它是如何工作的。
【解决方案2】:

正如所承诺的,这是我使用 PolygonSpriteBatch 的工作测试程序:

/* PolygonSpriteBatch test using libgdx 
    Author: Twelve1110
    Date: 6 June 2015
*/
package test;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
import java.util.ArrayList;

public class TestPolygonSpriteBatch extends ApplicationAdapter {

    PolygonSpriteBatch polyBatch;
    SpriteBatch batch;
    Texture img;                                
    ArrayList<Landmass> masses;
    TextureRegion texRegion;

    @Override
    public void create() {
        Gdx.graphics.setDisplayMode(600, 480, false);
        polyBatch = new PolygonSpriteBatch();
        masses = this.buildLandmass();
        img = new Texture(Gdx.files.internal("land.png"));  // 100 by 100 pixel plain white jpg
        texRegion = new TextureRegion(img);                 // Create new texture region with base image
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // Calculate screen left-edge X and bottom-edge Y (normally done in a game with moving screen)
        int scrBtmY = 0;
        int scrLeftX = 0;

        // Draw the landscape on-screen
        polyBatch.begin();
        polyBatch.setColor(Color.GREEN);
        for (Landmass lm : masses) {
            // Calculate start and end x and y values taking into account wrapping in 'buffer space'
            int sx = (int) lm.start.x - scrLeftX;
            int sy = (int) lm.start.y - scrBtmY;

            int ex = (int) lm.end.x - scrLeftX;
            int ey = (int) lm.end.y - scrBtmY;

            // Create polygon vertices
            float[] vertices = new float[8];                // Create polygon with bottom-left corner = (0, 0)
            vertices[0] = 0;                                // Bottom-left
            vertices[1] = 0;
            vertices[2] = (ex - sx) + 1;                    // Bottom-right; all points are lengths away from (0, 0); 
            vertices[3] = 0;
            vertices[4] = (ex - sx) + 1;                    // Top-right
            vertices[5] = ey;
            vertices[6] = 0;                                // Top-left
            vertices[7] = sy;

            // Define how to divide polygon into trianlges, create region and draw...
            short[] triangles = new short[]{0, 1, 2, 0, 2, 3};  // Define points of polygons to be used in triangles (could be done in 'create' method
            PolygonRegion polyReg = new PolygonRegion(texRegion, vertices, triangles);
            polyBatch.draw(polyReg, sx, 0);                 // Pass screen co-ordinates here to draw PolygonRegion in correct place on screen
        }
        polyBatch.end();
    }

    public ArrayList<Landmass> buildLandmass() {
        ArrayList<Landmass> list = new ArrayList();
        int[] coordinates = new int[]{                      // Set of polygons to be drawn in screen co-ordinates
            -22, 449, 2, 406, 3, 406, 27, 357, 
            28, 357, 52, 265, 53, 265, 77, 358, 
            78, 358, 102, 376, 103, 376, 127, 406, 
            128, 406, 152, 371, 153, 371, 177, 429, 
            178, 429, 202, 447, 203, 447, 227, 433, 
            228, 433, 252, 415, 253, 415, 277, 478, 
            278, 478, 302, 490, 303, 490, 327, 524, 
            328, 524, 352, 519, 353, 519, 377, 551, 
            378, 551, 402, 556, 403, 556, 427, 543, 
            428, 543, 452, 470, 453, 470, 477, 505, 
            478, 505, 502, 482, 503, 482, 527, 513,
            528, 513, 552, 476, 553, 476, 577, 479, 
            578, 479, 602, 460, 603, 460, 627, 475, 
            628, 475, 652, 426, 653, 426, 677, 453};

        for (int i = 0; i < 28; i++) {                      // Create landmass array of polygons
            Landmass lm = new Landmass();
            int pt = i * 4;
            lm.start.x = coordinates[pt];
            lm.start.y = coordinates[pt + 1];
            lm.end.x = coordinates[pt + 2];
            lm.end.y = coordinates[pt + 3];
            list.add(lm);
        }
        return list;
    }

    public class Landmass {
        public Vector2 start;
        public Vector2 end;

        Landmass() {
            start = new Vector2();
            end = new Vector2();
        }       
    }

}

【讨论】:

    猜你喜欢
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    • 2020-02-09
    • 1970-01-01
    • 2021-12-28
    相关资源
    最近更新 更多