使用libGDX绘制填充多边形

9
我希望使用libGDX绘制一些填充多边形。不需要使用图像/纹理进行填充。我只有该多边形(闭合路径)的顶点,并尝试使用网格可视化,但在某些情况下,我认为这不是最佳解决方案。
我的矩形代码如下:
private Mesh mesh;

@Override
public void create() {
    if (mesh == null) {
        mesh = new Mesh(
            true, 4, 0, 
            new VertexAttribute(Usage.Position, 3, "a_position")
        );
        mesh.setVertices(new float[] { 
            -0.5f, -0.5f, 0
            0.5f, -0.5f, 0,
            -0.5f, 0.5f, 0,
            0.5f, 0.5f, 0 
        });     
    }
}

// ...

@Override
public void render() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
    mesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4);
}

有没有一种更简单的方法来绘制填充多边形的函数或其他东西?

我在libgdx中找到了Polygon类,但我不知道如何将它们添加到我的场景中... - vtni
为什么如果我运行这段代码,我看不到任何东西? - Boldijar Paul
7个回答

27

由于LibGDX的最新更新,@Rus的回答正在使用被弃用的函数。然而,我要为他/她在下面提供的更新版本给予赞扬:

PolygonSprite poly;
PolygonSpriteBatch polyBatch = new PolygonSpriteBatch(); // To assign at the beginning
Texture textureSolid;

// Creating the color filling (but textures would work the same way)
Pixmap pix = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pix.setColor(0xDEADBEFF); // DE is red, AD is green and BE is blue.
pix.fill();
textureSolid = new Texture(pix);
PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid),
  new float[] {      // Four vertices
    0, 0,            // Vertex 0         3--2
    100, 0,          // Vertex 1         | /|
    100, 100,        // Vertex 2         |/ |
    0, 100           // Vertex 3         0--1
}, new short[] {
    0, 1, 2,         // Two triangles using vertex indices.
    0, 2, 3          // Take care of the counter-clockwise direction. 
});
poly = new PolygonSprite(polyReg);
poly.setOrigin(a, b);
polyBatch = new PolygonSpriteBatch();

如果您的多边形不是凸多边形,建议使用Toussaint(1991)提出的近似线性剖耳法进行良好的三角剖分算法。

简单多边形的高效三角剖分,Godfried Toussaint,1991


7
LibGDX实现了剪耳算法:https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/EarClippingTriangulator.html - DeejUK
我希望早些知道你的链接。谢谢! - Mikaël Mayer
有没有办法用渐变填充多边形?或者甚至用渐变填充一些三角形? - Dmitry Stril
请单独提出您的问题。 - Mikaël Mayer
@MikaëlMayer 非常感谢,就是这样。 - iibrahimbakr

10

这是一个使用libGDX绘制2D凹多边形的示例。

PolygonSpritePolygonSpriteBatch定义类成员。

PolygonSprite poly;
PolygonSpriteBatch polyBatch;
Texture textureSolid;

创建实例,使用红色像素作为解决方法的1x1大小纹理。 使用坐标数组(x,y)对多边形进行初始化。

ctor() {
    textureSolid = makeTextureBox(1, 0xFFFF0000, 0, 0); 
    float a = 100;
    float b = 100;
    PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid),
      new float[] {
        a*0, b*0,
        a*0, b*2,
        a*3, b*2,
        a*3, b*0,
        a*2, b*0,
        a*2, b*1,
        a*1, b*1,
        a*1, b*0,
    });
    poly = new PolygonSprite(polyReg);
    poly.setOrigin(a, b);
    polyBatch = new PolygonSpriteBatch();
}

绘制并旋转多边形

void draw() {
    super.draw();
    polyBatch.begin();
    poly.draw(polyBatch);
    polyBatch.end();
    poly.rotate(1.1f);
}

这个已经不再适用了 - 请参考Mikael在下面的回答:https://dev59.com/8XDXa4cB1Zd3GeqP_VkH#25702670 - DeejUK

3

7
目前(至少在Libgdx 1.3.1版本中),ShapeRenderer.polygon()方法不能用于绘制填充多边形。 - nmw

1

我希望与您分享我的相关解决方案,即用scene2d实现和绘制步行区。我基本上需要整合其他帖子中不同的建议:

1)步行区:

import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.EarClippingTriangulator;
import com.badlogic.gdx.math.Polygon;
import com.mygdx.game.MyGame;

public class WalkZone extends Polygon {
private PolygonRegion polygonRegion = null;
public WalkZone(float[] vertices) {
    super(vertices);
    if (MyGame.DEBUG) {
        Pixmap pix = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
        pix.setColor(0x00FF00AA);
        pix.fill();
        polygonRegion = new PolygonRegion(new TextureRegion(new Texture(pix)),
                vertices, new EarClippingTriangulator().computeTriangles(vertices).toArray());
        }
    }

    public PolygonRegion getPolygonRegion() {
        return polygonRegion;
    }
}

2) 屏幕(Screen):

接下来,您可以在所需的Stage中添加监听器:

myStage.addListener(new InputListener() {
        @Override
        public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
            if (walkZone.contains(x, y)) player.walkTo(x, y);
            // or even directly: player.addAction(moveTo ...
            return super.touchDown(event, x, y, pointer, button);
        }
    });

3) 实现:

传递给WZ构造函数的数组是一组x,y,x,y...点。如果您将它们放置在逆时针方向上,它就可以工作(我没有检查另一种方式,也不知道它如何工作); 例如,这将生成一个100x100的正方形:

yourScreen.walkZone = new WalkZone(new int[]{0, 0, 100, 0, 100, 100, 0, 100});

在我的项目中,它的表现非常出色,即使是非常复杂的多边形也能处理得很好。希望这能有所帮助!

1

3
LibGDX实现了耳戳剖分算法:https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/EarClippingTriangulator.html - DeejUK
非常好用,我已经使用这个建议发布了我的实现。 - fr_andres

1
你可以使用 ShapeRenderer API在Libgdx中绘制简单的纯色形状。
你提供的代码也是绘制纯色多边形的一种合理方式。它比ShapeRenderer更灵活,但也更复杂。您需要使用glColor4f来设置颜色,或者将Usage.Color属性添加到每个顶点。有关第一种方法的更多详细信息,请参见 SubMeshColorTest示例,有关第二种方法的详细信息,请参见 MeshColorTexture示例
另一个需要考虑的选项是使用精灵纹理。如果你只对简单的纯色对象感兴趣,你可以使用非常简单的单色1x1纹理,并让系统将其拉伸到精灵上。Libgdx和底层硬件大部分都针对纹理渲染进行了优化,因此即使你没有真正利用纹理内容,你可能会发现它更容易使用。(你甚至可以使用一个1x1的白色纹理,然后使用SpriteBatchsetColordraw()来轻松绘制不同颜色的矩形。)

你也可以混合使用不同的方法。


谢谢您的回答,那是一个选项。但我之前使用过three.js,并认为还有一种选项可以绘制仅具有单色填充的多边形而不需要纹理。例如,我能否使用并可视化Polygon类?我认为这将是最好的方法。 - vtni
Libgdx的Polygon不能直接绘制。对于任意多边形,我认为使用Mesh是Libgdx提供的最好支持。 - P.T.
我想使用 Mesh,但是我不知道在上面的示例中应该设置什么变量来代替 GL10.GL_TRIANGLE_STRIP 来渲染多边形... 我只能渲染三角形和正方形,但无法渲染超过4个角的图形。 - vtni
听起来像是一个新问题需要问。这个OpenGL教程涵盖了选项http://www.naturewizard.com/tutorial0104.html(尽管OpenGL ES摆脱了其中一些,因此并非所有选项都可以通过Libgdx使用)。 - P.T.
不幸的是,在 mesh.render(...); 中没有可用的 GL_POLYGON 变量,只有 GL_POLYGON_OFFSET_FILLGL_POLYGON_SMOOTH_HINT,但如果我使用其中一个,它将无法显示任何内容。 - vtni

0
大多数答案都建议使用三角测量,这很好,但您也可以使用模板缓冲区来完成。它处理凸多边形和凹多边形。如果您的多边形经常更改,那么这可能是更好的解决方案,否则您每帧都需要进行三角测量。此外,此解决方案正确处理自相交多边形,而EarClippingTriangulator则不行。
FloatArray vertices = ... // The polygon x,y pairs.
Color color = ... // The color to draw the polygon.

ShapeRenderer shapes = ...
ImmediateModeRenderer renderer = shapes.getRenderer();

Gdx.gl.glClearStencil(0);
Gdx.gl.glClear(GL20.GL_STENCIL_BUFFER_BIT);
Gdx.gl.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl.glStencilFunc(GL20.GL_NEVER, 0, 1);
Gdx.gl.glStencilOp(GL20.GL_INVERT, GL20.GL_INVERT, GL20.GL_INVERT);
Gdx.gl.glColorMask(false, false, false, false);

renderer.begin(shapes.getProjectionMatrix(), GL20.GL_TRIANGLE_FAN);
renderer.vertex(vertices.get(0), vertices.get(1), 0);
for (int i = 2, n = vertices.size; i < n; i += 2)
    renderer.vertex(vertices.get(i), vertices.get(i + 1), 0);
renderer.end();

Gdx.gl.glColorMask(true, true, true, true);
Gdx.gl.glStencilOp(GL20.GL_ZERO, GL20.GL_ZERO, GL20.GL_ZERO);
Gdx.gl.glStencilFunc(GL20.GL_EQUAL, 1, 1);

Gdx.gl.glEnable(GL20.GL_BLEND);
shapes.setColor(color);
shapes.begin(ShapeType.Filled);
shapes.rect(-9999999, -9999999, 9999999 * 2, 9999999 * 2);
shapes.end();

Gdx.gl.glDisable(GL20.GL_STENCIL_TEST);

要使用模板缓冲区,您必须在应用程序启动时指定模板缓冲区的位数。例如,以下是使用LWJGL2后端执行此操作的方法:

    LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
    config.stencil = 8;
    new LwjglApplication(new YourApp(), config);

有关此技术的更多信息,请尝试以下链接之一:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接