summaryrefslogtreecommitdiff
path: root/modules/csg
diff options
context:
space:
mode:
Diffstat (limited to 'modules/csg')
-rw-r--r--modules/csg/csg.cpp57
-rw-r--r--modules/csg/csg_gizmos.cpp8
-rw-r--r--modules/csg/csg_gizmos.h20
-rw-r--r--modules/csg/csg_shape.cpp22
-rw-r--r--modules/csg/csg_shape.h22
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml4
6 files changed, 70 insertions, 63 deletions
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index df798623f9..47982d519a 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -30,7 +30,7 @@
#include "csg.h"
-#include "core/math/geometry.h"
+#include "core/math/geometry_2d.h"
#include "core/math/math_funcs.h"
#include "core/sort_array.h"
@@ -154,6 +154,14 @@ inline bool is_point_in_triangle(const Vector3 &p_point, const Vector3 p_vertice
return true;
}
+inline static bool is_triangle_degenerate(const Vector2 p_vertices[3], real_t p_vertex_snap2) {
+ real_t det = p_vertices[0].x * p_vertices[1].y - p_vertices[0].x * p_vertices[2].y +
+ p_vertices[0].y * p_vertices[2].x - p_vertices[0].y * p_vertices[1].x +
+ p_vertices[1].x * p_vertices[2].y - p_vertices[1].y * p_vertices[2].x;
+
+ return det < p_vertex_snap2;
+}
+
inline static bool are_segements_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) {
Vector2 segment1 = p_segment1_points[1] - p_segment1_points[0];
Vector2 segment2 = p_segment2_points[1] - p_segment2_points[0];
@@ -523,7 +531,7 @@ void CSGBrushOperation::MeshMerge::_add_distance(List<real_t> &r_intersectionsA,
// Check if distance exists.
for (const List<real_t>::Element *E = intersections.front(); E; E = E->next()) {
- if (Math::abs(**E - p_distance) < vertex_snap) {
+ if (Math::is_equal_approx(**E, p_distance)) {
return;
}
}
@@ -583,8 +591,8 @@ bool CSGBrushOperation::MeshMerge::_bvh_inside(FaceBVH *facebvhptr, int p_max_de
// Check if faces are co-planar.
if ((current_normal - face_normal).length_squared() < CMP_EPSILON2 &&
is_point_in_triangle(face_center, current_points)) {
- // Only add an intersection if checking a B face.
- if (face.from_b) {
+ // Only add an intersection if not a B face.
+ if (!face.from_b) {
_add_distance(intersectionsA, intersectionsB, current_face.from_b, 0);
}
} else if (ray_intersects_triangle(face_center, face_normal, current_points, CMP_EPSILON, intersection_point)) {
@@ -904,8 +912,12 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
vertices[p_segment_indices[closest_idx]].point
};
if (are_segements_parallel(edge1, edge2, vertex_snap2)) {
- degenerate_points.push_back(outer_edge_idx[0]);
- degenerate_points.push_back(outer_edge_idx[1]);
+ if (!degenerate_points.find(outer_edge_idx[0])) {
+ degenerate_points.push_back(outer_edge_idx[0]);
+ }
+ if (!degenerate_points.find(outer_edge_idx[1])) {
+ degenerate_points.push_back(outer_edge_idx[1]);
+ }
continue;
}
@@ -964,7 +976,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
face_points[face_edge_idx],
face_points[(face_edge_idx + 1) % 3]
};
- Vector2 closest_point = Geometry::get_closest_point_to_segment_2d(point_2D, edge_points);
+ Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point_2D, edge_points);
if ((closest_point - point_2D).length_squared() < vertex_snap2) {
int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3];
@@ -1028,7 +1040,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
// First check if the ends of the segment are on the edge.
bool on_edge = false;
for (int edge_point_idx = 0; edge_point_idx < 2; ++edge_point_idx) {
- intersection_point = Geometry::get_closest_point_to_segment_2d(p_segment_points[edge_point_idx], edge_points);
+ intersection_point = Geometry2D::get_closest_point_to_segment(p_segment_points[edge_point_idx], edge_points);
if ((intersection_point - p_segment_points[edge_point_idx]).length_squared() < vertex_snap2) {
on_edge = true;
break;
@@ -1036,7 +1048,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
}
// Else check if the segment intersects the edge.
- if (on_edge || Geometry::segment_intersects_segment_2d(p_segment_points[0], p_segment_points[1], edge_points[0], edge_points[1], &intersection_point)) {
+ if (on_edge || Geometry2D::segment_intersects_segment(p_segment_points[0], p_segment_points[1], edge_points[0], edge_points[1], &intersection_point)) {
// Check if intersection point is an edge point.
if ((intersection_point - edge_points[0]).length_squared() < vertex_snap2 ||
(intersection_point - edge_points[1]).length_squared() < vertex_snap2) {
@@ -1064,17 +1076,8 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
break;
}
- // Don't create degenerate triangles.
- Vector2 split_edge1[2] = { vertices[new_vertex_idx].point, edge_points[0] };
- Vector2 split_edge2[2] = { vertices[new_vertex_idx].point, edge_points[1] };
- Vector2 new_edge[2] = { vertices[new_vertex_idx].point, vertices[opposite_vertex_idx].point };
- if (are_segements_parallel(split_edge1, new_edge, vertex_snap2) &&
- are_segements_parallel(split_edge2, new_edge, vertex_snap2)) {
- break;
- }
-
// If opposite point is on the segemnt, add its index to segment indices too.
- Vector2 closest_point = Geometry::get_closest_point_to_segment_2d(vertices[opposite_vertex_idx].point, p_segment_points);
+ Vector2 closest_point = Geometry2D::get_closest_point_to_segment(vertices[opposite_vertex_idx].point, p_segment_points);
if ((closest_point - vertices[opposite_vertex_idx].point).length_squared() < vertex_snap2) {
_add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx);
}
@@ -1122,6 +1125,11 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
face_vertices[2].uv
};
+ // Skip degenerate triangles.
+ if (is_triangle_degenerate(points, vertex_snap2)) {
+ continue;
+ }
+
// Check if point is existing face vertex.
for (int i = 0; i < 3; ++i) {
if ((p_point - face_vertices[i].point).length_squared() < vertex_snap2) {
@@ -1141,7 +1149,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
uvs[(face_edge_idx + 1) % 3]
};
- Vector2 closest_point = Geometry::get_closest_point_to_segment_2d(p_point, edge_points);
+ Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, edge_points);
if ((closest_point - p_point).length_squared() < vertex_snap2) {
on_edge = true;
@@ -1192,7 +1200,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
}
// If not on an edge, check if the point is inside the face.
- if (!on_edge && Geometry::is_point_in_triangle(p_point, face_vertices[0].point, face_vertices[1].point, face_vertices[2].point)) {
+ if (!on_edge && Geometry2D::is_point_in_triangle(p_point, face_vertices[0].point, face_vertices[1].point, face_vertices[2].point)) {
// Add the point as a new vertex.
Vertex2D new_vertex;
new_vertex.point = p_point;
@@ -1203,11 +1211,8 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
// The new vertex is the last vertex.
for (int i = 0; i < 3; ++i) {
// Don't create degenerate triangles.
- Vector2 edge[2] = { points[i], points[(i + 1) % 3] };
- Vector2 new_edge1[2] = { vertices[new_vertex_idx].point, points[i] };
- Vector2 new_edge2[2] = { vertices[new_vertex_idx].point, points[(i + 1) % 3] };
- if (are_segements_parallel(edge, new_edge1, vertex_snap2) &&
- are_segements_parallel(edge, new_edge2, vertex_snap2)) {
+ Vector2 new_points[3] = { points[i], points[(i + 1) % 3], vertices[new_vertex_idx].point };
+ if (is_triangle_degenerate(new_points, vertex_snap2)) {
continue;
}
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index 9fa7dc1340..cce72770f5 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -120,7 +120,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
+ Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
float d = ra.x;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
@@ -139,7 +139,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Vector3 axis;
axis[p_idx] = 1.0;
Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = ra[p_idx];
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
@@ -168,7 +168,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Vector3 axis;
axis[p_idx == 0 ? 0 : 1] = 1.0;
Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
@@ -191,7 +191,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Vector3 axis;
axis[0] = 1.0;
Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 48a414d9c7..83ee847caf 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -39,16 +39,16 @@ class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CSGShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
- bool has_gizmo(Node3D *p_spatial);
- String get_name() const;
- int get_priority() const;
- bool is_selectable_when_hidden() const;
- void redraw(EditorNode3DGizmo *p_gizmo);
-
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
- void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_name() const override;
+ int get_priority() const override;
+ bool is_selectable_when_hidden() const override;
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const override;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const override;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) override;
CSGShape3DGizmoPlugin();
};
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 7df65b04c4..8f2ebc7232 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "csg_shape.h"
+#include "core/math/geometry_2d.h"
#include "scene/3d/path_3d.h"
void CSGShape3D::set_use_collision(bool p_enable) {
@@ -131,18 +132,13 @@ void CSGShape3D::_make_dirty() {
return;
}
- if (dirty) {
- return;
- }
-
- dirty = true;
-
if (parent) {
parent->_make_dirty();
- } else {
- //only parent will do
+ } else if (!dirty) {
call_deferred("_update_shape");
}
+
+ dirty = true;
}
CSGBrush *CSGShape3D::_get_brush() {
@@ -510,6 +506,12 @@ void CSGShape3D::_notification(int p_what) {
_make_dirty();
}
+ if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+ if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
+ PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
+ }
+ }
+
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (parent) {
parent->_make_dirty();
@@ -645,7 +647,7 @@ CSGShape3D::~CSGShape3D() {
//////////////////////////////////
CSGBrush *CSGCombiner3D::_build_brush() {
- return nullptr; //does not build anything
+ return memnew(CSGBrush); //does not build anything
}
CSGCombiner3D::CSGCombiner3D() {
@@ -1728,7 +1730,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
final_polygon.invert();
}
- Vector<int> triangles = Geometry::triangulate_polygon(final_polygon);
+ Vector<int> triangles = Geometry2D::triangulate_polygon(final_polygon);
if (triangles.size() < 3) {
return nullptr;
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 7e95d685c5..d93693f145 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -114,7 +114,7 @@ protected:
friend class CSGCombiner3D;
CSGBrush *_get_brush();
- virtual void _validate_property(PropertyInfo &property) const;
+ virtual void _validate_property(PropertyInfo &property) const override;
public:
Array get_meshes() const;
@@ -124,8 +124,8 @@ public:
virtual Vector<Vector3> get_brush_faces();
- virtual AABB get_aabb() const;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+ virtual AABB get_aabb() const override;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
void set_use_collision(bool p_enable);
bool is_using_collision() const;
@@ -159,7 +159,7 @@ class CSGCombiner3D : public CSGShape3D {
GDCLASS(CSGCombiner3D, CSGShape3D);
private:
- virtual CSGBrush *_build_brush();
+ virtual CSGBrush *_build_brush() override;
public:
CSGCombiner3D();
@@ -185,7 +185,7 @@ public:
class CSGMesh3D : public CSGPrimitive3D {
GDCLASS(CSGMesh3D, CSGPrimitive3D);
- virtual CSGBrush *_build_brush();
+ virtual CSGBrush *_build_brush() override;
Ref<Mesh> mesh;
Ref<Material> material;
@@ -205,7 +205,7 @@ public:
class CSGSphere3D : public CSGPrimitive3D {
GDCLASS(CSGSphere3D, CSGPrimitive3D);
- virtual CSGBrush *_build_brush();
+ virtual CSGBrush *_build_brush() override;
Ref<Material> material;
bool smooth_faces;
@@ -237,7 +237,7 @@ public:
class CSGBox3D : public CSGPrimitive3D {
GDCLASS(CSGBox3D, CSGPrimitive3D);
- virtual CSGBrush *_build_brush();
+ virtual CSGBrush *_build_brush() override;
Ref<Material> material;
float width;
@@ -265,7 +265,7 @@ public:
class CSGCylinder3D : public CSGPrimitive3D {
GDCLASS(CSGCylinder3D, CSGPrimitive3D);
- virtual CSGBrush *_build_brush();
+ virtual CSGBrush *_build_brush() override;
Ref<Material> material;
float radius;
@@ -301,7 +301,7 @@ public:
class CSGTorus3D : public CSGPrimitive3D {
GDCLASS(CSGTorus3D, CSGPrimitive3D);
- virtual CSGBrush *_build_brush();
+ virtual CSGBrush *_build_brush() override;
Ref<Material> material;
float inner_radius;
@@ -352,7 +352,7 @@ public:
};
private:
- virtual CSGBrush *_build_brush();
+ virtual CSGBrush *_build_brush() override;
Vector<Vector2> polygon;
Ref<Material> material;
@@ -383,7 +383,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const;
+ virtual void _validate_property(PropertyInfo &property) const override;
void _notification(int p_what);
public:
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index 43ce988c30..dac556c7f1 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -71,10 +71,10 @@
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this area is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this CSG shape scans for collisions.
+ The physics layers this CSG shape scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0">
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.