TileSet/TileMap: Decompose solid non-convex polygons into convexes. Real fix for #24003
This commit is contained in:
parent
3aff78f532
commit
078b869d9a
6 changed files with 90 additions and 40 deletions
|
@ -31,6 +31,7 @@
|
|||
#include "geometry.h"
|
||||
|
||||
#include "core/print_string.h"
|
||||
#include "thirdparty/misc/triangulator.h"
|
||||
|
||||
/* this implementation is very inefficient, commenting unless bugs happen. See the other one.
|
||||
bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) {
|
||||
|
@ -737,6 +738,40 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e
|
|||
return wrapped_faces;
|
||||
}
|
||||
|
||||
Vector<Vector<Vector2> > Geometry::decompose_polygon_in_convex(Vector<Point2> polygon) {
|
||||
Vector<Vector<Vector2> > decomp;
|
||||
List<TriangulatorPoly> in_poly, out_poly;
|
||||
|
||||
TriangulatorPoly inp;
|
||||
inp.Init(polygon.size());
|
||||
for (int i = 0; i < polygon.size(); i++) {
|
||||
inp.GetPoint(i) = polygon[i];
|
||||
}
|
||||
inp.SetOrientation(TRIANGULATOR_CCW);
|
||||
in_poly.push_back(inp);
|
||||
TriangulatorPartition tpart;
|
||||
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
|
||||
ERR_PRINT("Convex decomposing failed!");
|
||||
return decomp;
|
||||
}
|
||||
|
||||
decomp.resize(out_poly.size());
|
||||
int idx = 0;
|
||||
for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
|
||||
TriangulatorPoly &tp = I->get();
|
||||
|
||||
decomp.write[idx].resize(tp.GetNumPoints());
|
||||
|
||||
for (int i = 0; i < tp.GetNumPoints(); i++) {
|
||||
decomp.write[idx].write[i] = tp.GetPoint(i);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return decomp;
|
||||
}
|
||||
|
||||
Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes) {
|
||||
|
||||
MeshData mesh;
|
||||
|
|
|
@ -950,6 +950,8 @@ public:
|
|||
return H;
|
||||
}
|
||||
|
||||
static Vector<Vector<Vector2> > decompose_polygon_in_convex(Vector<Point2> polygon);
|
||||
|
||||
static MeshData build_convex_mesh(const PoolVector<Plane> &p_planes);
|
||||
static PoolVector<Plane> build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis = Vector3::AXIS_Z);
|
||||
static PoolVector<Plane> build_box_planes(const Vector3 &p_extents);
|
||||
|
|
|
@ -78,40 +78,7 @@ void CollisionPolygon2D::_build_polygon() {
|
|||
}
|
||||
|
||||
Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
|
||||
|
||||
Vector<Vector<Vector2> > decomp;
|
||||
List<TriangulatorPoly> in_poly, out_poly;
|
||||
|
||||
TriangulatorPoly inp;
|
||||
inp.Init(polygon.size());
|
||||
for (int i = 0; i < polygon.size(); i++) {
|
||||
inp.GetPoint(i) = polygon[i];
|
||||
}
|
||||
inp.SetOrientation(TRIANGULATOR_CCW);
|
||||
in_poly.push_back(inp);
|
||||
TriangulatorPartition tpart;
|
||||
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
|
||||
ERR_PRINT("Convex decomposing failed!");
|
||||
return decomp;
|
||||
}
|
||||
|
||||
decomp.resize(out_poly.size());
|
||||
int idx = 0;
|
||||
|
||||
for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
|
||||
|
||||
TriangulatorPoly &tp = I->get();
|
||||
|
||||
decomp.write[idx].resize(tp.GetNumPoints());
|
||||
|
||||
for (int i = 0; i < tp.GetNumPoints(); i++) {
|
||||
|
||||
decomp.write[idx].write[i] = tp.GetPoint(i);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(polygon);
|
||||
return decomp;
|
||||
}
|
||||
|
||||
|
|
|
@ -479,10 +479,28 @@ void TileMap::update_dirty_quadrants() {
|
|||
vs->canvas_item_add_set_transform(debug_canvas_item, xform);
|
||||
shape->draw(debug_canvas_item, debug_collision_color);
|
||||
}
|
||||
ps->body_add_shape(q.body, shape->get_rid(), xform);
|
||||
ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
|
||||
ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin);
|
||||
shape_idx++;
|
||||
|
||||
if (shape->has_meta("decomposed")) {
|
||||
Array _shapes = shape->get_meta("decomposed");
|
||||
for (int k = 0; k < _shapes.size(); k++) {
|
||||
Ref<ConvexPolygonShape2D> convex = _shapes[k];
|
||||
if (convex.is_valid()) {
|
||||
ps->body_add_shape(q.body, convex->get_rid(), xform);
|
||||
ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
|
||||
ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin);
|
||||
shape_idx++;
|
||||
#ifdef DEBUG_ENABLED
|
||||
} else {
|
||||
print_error("The TileSet asigned to the TileMap " + get_name() + " has an invalid convex shape.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ps->body_add_shape(q.body, shape->get_rid(), xform);
|
||||
ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
|
||||
ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin);
|
||||
shape_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "tile_set.h"
|
||||
#include "core/array.h"
|
||||
#include "core/engine.h"
|
||||
|
||||
bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
|
||||
|
||||
|
@ -662,6 +663,7 @@ void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_sha
|
|||
if (tile_map[p_id].shapes_data.size() <= p_shape_id)
|
||||
tile_map[p_id].shapes_data.resize(p_shape_id + 1);
|
||||
tile_map[p_id].shapes_data.write[p_shape_id].shape = p_shape;
|
||||
_decompose_convex_shape(p_shape);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
|
@ -844,6 +846,9 @@ void TileSet::tile_set_shapes(int p_id, const Vector<ShapeData> &p_shapes) {
|
|||
|
||||
ERR_FAIL_COND(!tile_map.has(p_id));
|
||||
tile_map[p_id].shapes_data = p_shapes;
|
||||
for (int i = 0; i < p_shapes.size(); i++) {
|
||||
_decompose_convex_shape(p_shapes[i].shape);
|
||||
}
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
|
@ -888,9 +893,10 @@ void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) {
|
|||
} else if (p_shapes[i].get_type() == Variant::DICTIONARY) {
|
||||
Dictionary d = p_shapes[i];
|
||||
|
||||
if (d.has("shape") && d["shape"].get_type() == Variant::OBJECT)
|
||||
if (d.has("shape") && d["shape"].get_type() == Variant::OBJECT) {
|
||||
s.shape = d["shape"];
|
||||
else
|
||||
_decompose_convex_shape(s.shape);
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (d.has("shape_transform") && d["shape_transform"].get_type() == Variant::TRANSFORM2D)
|
||||
|
@ -956,6 +962,26 @@ Array TileSet::_get_tiles_ids() const {
|
|||
return arr;
|
||||
}
|
||||
|
||||
void TileSet::_decompose_convex_shape(Ref<Shape2D> p_shape) {
|
||||
if (Engine::get_singleton()->is_editor_hint())
|
||||
return;
|
||||
Ref<ConvexPolygonShape2D> convex = p_shape;
|
||||
if (!convex.is_valid())
|
||||
return;
|
||||
Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(convex->get_points());
|
||||
if (decomp.size() > 1) {
|
||||
Array sub_shapes;
|
||||
for (int i = 0; i < decomp.size(); i++) {
|
||||
Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D);
|
||||
_convex->set_points(decomp[i]);
|
||||
sub_shapes.append(_convex);
|
||||
}
|
||||
convex->set_meta("decomposed", sub_shapes);
|
||||
} else {
|
||||
convex->set_meta("decomposed", Variant());
|
||||
}
|
||||
}
|
||||
|
||||
void TileSet::get_tile_list(List<int> *p_tiles) const {
|
||||
|
||||
for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "core/resource.h"
|
||||
#include "scene/2d/light_occluder_2d.h"
|
||||
#include "scene/2d/navigation_polygon.h"
|
||||
#include "scene/resources/convex_polygon_shape_2d.h"
|
||||
#include "scene/resources/shape_2d.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
|
@ -134,6 +135,7 @@ protected:
|
|||
void _tile_set_shapes(int p_id, const Array &p_shapes);
|
||||
Array _tile_get_shapes(int p_id) const;
|
||||
Array _get_tiles_ids() const;
|
||||
void _decompose_convex_shape(Ref<Shape2D> p_shape);
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
|
|
Loading…
Reference in a new issue