Drawing filled polygon with libgdx

China☆狼群 提交于 2019-11-29 10:28:34

问题


i wanted to draw some (filled) polygons with libgdx for an android game. it shoudn't be filled with a graphic/texture. i have only the vertices of the polygon (closed path) and tried to visualize with meshes but at some point this is not the best solution, i think.

my code for an rectangle is:

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);
}

is there a function or something to draw filled polygons in an easier way?


回答1:


Here is a LIBGDX example which draws 2D concave poly.

// define class members for PolygonSprite PolygonSpriteBatch

PolygonSprite poly;
PolygonSpriteBatch polyBatch;
Texture textureSolid;

// create instances, 1x1 size texture used with red pixel as workaround, (x,y) array of coords used for initialization of poly

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();
}

// draw and rotate poly

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



回答2:


Since recent updates of LibGDX, @Rus answer is using deprecated functions. However, I give him/her credits for the new updated version below:

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();

For good triangulating algorithms if your polygon is not convex, see the almost-linear earclipping algorithm from Toussaint (1991)

Efficient triangulation of simple polygons, Godfried Toussaint, 1991




回答3:


I believe the ShapeRenderer class now has a polygon method for vertex defined polygons:

ShapeRenderer.polygon()




回答4:


You can use the ShapeRenderer API to draw simple, solid-color shapes with Libgdx.

The code you've given is a reasonable way to draw solid color polygons too. Its much more flexible than ShapeRenderer, but is a good bit more complicated. You'll need to use glColor4f to set the color, or add a Usage.Color attribute to each vertex. See the SubMeshColorTest example for more details on the first approach and the MeshColorTexture example for details on the second approach.

Another option to think about is using sprite textures. If you're only interested in simple solid colors objects, you can use very simple 1x1 textures of a single color and let the system stretch that across the sprite. Much of Libgdx and the underlying hardware are really optimized for rendering textures, so you may find it easier to use even if you're not really taking advantage of the texture contents. (You can even use a 1x1 white texture, and then use a SpriteBatch with setColor and draw() to draw different color rectangles easily.)

You can also mix and match the various approaches, too.




回答5:


Use triangulation algorithm and then draw all triangles as GL_TRIANGLE_STRIP http://www.personal.psu.edu/cxc11/AERSP560/DELAUNEY/13_Two_algorithms_Delauney.pdf




回答6:


just wanted to share my related solution with you, namely for implementing and drawing a walkZone with scene2d. I basically had to put together the different suggestions of the others' posts:

1) The WalkZone:

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) The Screen:

you can then add a listener in the desired 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) The implementation:

The array passed to te WZ constructor is a set of x,y,x,y... points. If you put them counter-clockwise, it works (I didn't check the other way, nor know how it exactly works); for example this generates a 100x100 square:

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

In my project it works like a charm, even with very intricated polygons. Hope it helps!!




回答7:


Most answers suggest triangulation, which is fine, but you can also do it using the stencil buffer. It handles both convex and concave polygons. This may be a better solution if your polygon changes a lot, since otherwise you'd have to do triangulation every frame. Also, this solution properly handles self intersecting polygons, which EarClippingTriangulator does not.

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);

To use the stencil buffer, you must specify the number of bits for the stencil buffer when your app starts. For example, here is how to do that using the LWJGL2 backend:

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

For more information on this technique, try one of these links:

  • http://commaexcess.com/articles/7/concave-polygon-triangulation-shortcut
  • http://glprogramming.com/red/chapter14.html#name13
  • http://what-when-how.com/opengl-programming-guide/drawing-filled-concave-polygons-using-the-stencil-buffer-opengl-programming/


来源:https://stackoverflow.com/questions/15733442/drawing-filled-polygon-with-libgdx

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!