Рисование заполненного многоугольника с помощью libgdx
Я хотел нарисовать несколько (заполненных) полигонов с libgdx для игры для android. он не должен быть заполнен графикой / текстурой. у меня только вершины многоугольника (замкнутый путь) и пытался визуализировать с сетки, но в какой-то момент это не лучшее решение, я думаю.
мой код для прямоугольника:
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);
}
есть ли функция или что-то, чтобы рисовать заполненные полигоны более простым способом?
7 ответов
вот пример LIBGDX, который рисует 2D вогнутый poly.
/ / определите члены класса для PolygonSprite PolygonSpriteBatch
PolygonSprite poly;
PolygonSpriteBatch polyBatch;
Texture textureSolid;
/ / создайте экземпляры, текстуру размера 1x1, используемую с красным пикселем в качестве обходного пути, (x, y) массив координат, используемых для инициализации 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();
}
// нарисуйте и поверните poly
void draw() {
super.draw();
polyBatch.begin();
poly.draw(polyBatch);
polyBatch.end();
poly.rotate(1.1f);
}
начиная с последних обновлений LibGDX, @Rus answer использует устаревшие функции. Тем не менее, я даю ему/ей кредиты для новой обновленной версии ниже:
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();
для хороших алгоритмов триангуляции, если ваш многоугольник не выпуклый, см. почти линейный алгоритм earclipping из Toussaint (1991)
эффективная триангуляция простых полигонов, Годфрид Туссен, 1991
можно использовать на ShapeRenderer
API рисовать простые, одноцветные фигуры с помощью Libgdx.
код, который вы дали, является разумным способом рисования сплошных цветных полигонов. Его гораздо более гибким, чем ShapeRenderer
, но это немного сложнее. Вам нужно будет использовать glColor4f
установить цвет, или добавить Usage.Color
атрибут для каждой вершины. См.пример SubMeshColorTest подробнее о Первый подход и в MeshColorTexture пример подробнее о втором подходе.
другой вариант, о котором стоит подумать, - это использование текстур спрайтов. Если вас интересуют только простые объекты сплошных цветов, вы можете использовать очень простые текстуры 1x1 одного цвета и позволить системе растянуть это через спрайт. Большая часть Libgdx и базового оборудования действительно оптимизированы для рендеринга текстур, поэтому вы можете найти его проще в использовании, даже если вы на самом деле не пользуетесь содержимым текстуры. (Вы даже можете используйте белую текстуру 1x1, а затем используйте SpriteBatch
С setColor
и draw()
рисовать прямоугольники другого цвета легко.)
вы также можете смешивать и сопоставлять различные подходы.
используйте алгоритм триангуляции, а затем нарисуйте все треугольники как GL_TRIANGLE_STRIP http://www.personal.psu.edu/cxc11/AERSP560/DELAUNEY/13_Two_algorithms_Delauney.pdf
просто хотел поделиться своим связанным решением с вами, а именно для реализация и рисование walkZone с scene2d. Мне в основном пришлось собрать различные предложения других сообщений:
1) 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) :
затем вы можете добавить слушателя в желаемом 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) реализация:
массив прошел для te WZ конструктор представляет собой набор x, y,x, y... точки. Если вы ставите их против часовой стрелки, это работает (я не проверял другой способ, и не знаю, как это точно работает); например, это генерирует квадрат 100x100:
yourScreen.walkZone = new WalkZone(new int[]{0, 0, 100, 0, 100, 100, 0, 100});
в моем проекте он работает как шарм, даже с очень сложными полигонами. Надеюсь, это поможет!!
большинство ответов предлагают триангуляцию, что нормально, но вы также можете сделать это с помощью буфера трафарета. Он обрабатывает как выпуклые, так и вогнутые многоугольники. Это может быть лучшее решение, если ваш полигон сильно меняется, так как в противном случае вам придется делать триангуляцию каждого кадра. Кроме того, это решение правильно обрабатывает самопересекающиеся полигоны, которые 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 backend:
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.stencil = 8;
new LwjglApplication(new YourApp(), config);
для получения дополнительной информации об этой технике попробуйте один из следующих ссылки: