diff options
Diffstat (limited to 'modules/csg')
-rw-r--r-- | modules/csg/csg.cpp | 48 | ||||
-rw-r--r-- | modules/csg/csg_shape.cpp | 450 | ||||
-rw-r--r-- | modules/csg/csg_shape.h | 18 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGPolygon3D.xml | 15 |
4 files changed, 325 insertions, 206 deletions
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index cbe41a1310..53694035dc 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -37,16 +37,16 @@ // Static helper functions. inline static bool is_snapable(const Vector3 &p_point1, const Vector3 &p_point2, real_t p_distance) { - return (p_point1 - p_point2).length_squared() < p_distance * p_distance; + return p_point2.distance_squared_to(p_point1) < p_distance * p_distance; } -inline static Vector2 interpolate_segment_uv(const Vector2 p_segement_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) { - float segment_length = (p_segement_points[1] - p_segement_points[0]).length(); - if (p_segement_points[0].is_equal_approx(p_segement_points[1])) { +inline static Vector2 interpolate_segment_uv(const Vector2 p_segment_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) { + if (p_segment_points[0].is_equal_approx(p_segment_points[1])) { return p_uvs[0]; } - float distance = (p_interpolation_point - p_segement_points[0]).length(); + float segment_length = p_segment_points[0].distance_to(p_segment_points[1]); + float distance = p_segment_points[0].distance_to(p_interpolation_point); float fraction = distance / segment_length; return p_uvs[0].lerp(p_uvs[1], fraction); @@ -162,7 +162,7 @@ inline static bool is_triangle_degenerate(const Vector2 p_vertices[3], real_t p_ 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) { +inline static bool are_segments_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]; real_t segment1_length2 = segment1.dot(segment1); @@ -258,8 +258,8 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector< } materials.resize(material_map.size()); - for (Map<Ref<Material>, int>::Element *E = material_map.front(); E; E = E->next()) { - materials.write[E->get()] = E->key(); + for (const KeyValue<Ref<Material>, int> &E : material_map) { + materials.write[E.value] = E.key; } _regen_face_aabbs(); @@ -457,8 +457,8 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b // Update the list of materials. r_merged_brush.materials.resize(mesh_merge.materials.size()); - for (const Map<Ref<Material>, int>::Element *E = mesh_merge.materials.front(); E; E = E->next()) { - r_merged_brush.materials.write[E->get()] = E->key(); + for (const KeyValue<Ref<Material>, int> &E : mesh_merge.materials) { + r_merged_brush.materials.write[E.value] = E.key; } } @@ -596,7 +596,7 @@ bool CSGBrushOperation::MeshMerge::_bvh_inside(FaceBVH *facebvhptr, int p_max_de _add_distance(intersectionsA, intersectionsB, current_face.from_b, 0); } } else if (ray_intersects_triangle(face_center, face_normal, current_points, CMP_EPSILON, intersection_point)) { - real_t distance = (intersection_point - face_center).length(); + real_t distance = face_center.distance_to(intersection_point); _add_distance(intersectionsA, intersectionsB, current_face.from_b, distance); } } @@ -781,7 +781,7 @@ void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[], const Vect int CSGBrushOperation::Build2DFaces::_get_point_idx(const Vector2 &p_point) { for (int vertex_idx = 0; vertex_idx < vertices.size(); ++vertex_idx) { - if ((p_point - vertices[vertex_idx].point).length_squared() < vertex_snap2) { + if (vertices[vertex_idx].point.distance_squared_to(p_point) < vertex_snap2) { return vertex_idx; } } @@ -911,7 +911,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_ vertices[outer_edge_idx[1]].point, vertices[p_segment_indices[closest_idx]].point }; - if (are_segements_parallel(edge1, edge2, vertex_snap2)) { + if (are_segments_parallel(edge1, edge2, vertex_snap2)) { if (!degenerate_points.find(outer_edge_idx[0])) { degenerate_points.push_back(outer_edge_idx[0]); } @@ -961,7 +961,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_ // Check if point is existing face vertex. bool existing = false; for (int i = 0; i < 3; ++i) { - if ((point_2D - face_vertices[i].point).length_squared() < vertex_snap2) { + if (face_vertices[i].point.distance_squared_to(point_2D) < vertex_snap2) { existing = true; break; } @@ -978,7 +978,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_ }; Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point_2D, edge_points); - if ((closest_point - point_2D).length_squared() < vertex_snap2) { + if (point_2D.distance_squared_to(closest_point) < vertex_snap2) { int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3]; // If new vertex snaps to degenerate vertex, just delete this face. @@ -1041,7 +1041,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s bool on_edge = false; for (int edge_point_idx = 0; edge_point_idx < 2; ++edge_point_idx) { 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) { + if (p_segment_points[edge_point_idx].distance_squared_to(intersection_point) < vertex_snap2) { on_edge = true; break; } @@ -1050,13 +1050,13 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s // Else check if the segment intersects the edge. 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) { + if ((edge_points[0].distance_squared_to(intersection_point) < vertex_snap2) || + (edge_points[1].distance_squared_to(intersection_point) < vertex_snap2)) { continue; } // Check if edge exists, by checking if the intersecting segment is parallel to the edge. - if (are_segements_parallel(p_segment_points, edge_points, vertex_snap2)) { + if (are_segments_parallel(p_segment_points, edge_points, vertex_snap2)) { continue; } @@ -1078,7 +1078,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s // If opposite point is on the segment, add its index to segment indices too. 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) { + if (vertices[opposite_vertex_idx].point.distance_squared_to(closest_point) < vertex_snap2) { _add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx); } @@ -1132,7 +1132,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { // 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) { + if (face_vertices[i].point.distance_squared_to(p_point) < vertex_snap2) { return face.vertex_idx[i]; } } @@ -1150,7 +1150,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { }; Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, edge_points); - if ((closest_point - p_point).length_squared() < vertex_snap2) { + if (p_point.distance_squared_to(closest_point) < vertex_snap2) { on_edge = true; // Add the point as a new vertex. @@ -1172,8 +1172,8 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { 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)) { + if (are_segments_parallel(split_edge1, new_edge, vertex_snap2) && + are_segments_parallel(split_edge2, new_edge, vertex_snap2)) { break; } diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 452fb32d9d..e4297a593e 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -1732,6 +1732,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { int extrusion_face_count = shape_sides * 2; int end_count = 0; int shape_face_count = shape_faces.size() / 3; + real_t curve_length = 1.0; switch (mode) { case MODE_DEPTH: extrusions = 1; @@ -1744,7 +1745,12 @@ CSGBrush *CSGPolygon3D::_build_brush() { } break; case MODE_PATH: { - extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval); + curve_length = curve->get_baked_length(); + if (path_interval_type == PATH_INTERVAL_DISTANCE) { + extrusions = MAX(1, Math::ceil(curve_length / path_interval)) + 1; + } else { + extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval); + } if (!path_joined) { end_count = 2; extrusions -= 1; @@ -1767,212 +1773,245 @@ CSGBrush *CSGPolygon3D::_build_brush() { smooth.resize(face_count); materials.resize(face_count); invert.resize(face_count); + int faces_removed = 0; - Vector3 *facesw = faces.ptrw(); - Vector2 *uvsw = uvs.ptrw(); - bool *smoothw = smooth.ptrw(); - Ref<Material> *materialsw = materials.ptrw(); - bool *invertw = invert.ptrw(); - - int face = 0; - Transform3D base_xform; - Transform3D current_xform; - Transform3D previous_xform; - double u_step = 1.0 / extrusions; - double v_step = 1.0 / shape_sides; - double spin_step = Math::deg2rad(spin_degrees / spin_sides); - double extrusion_step = 1.0 / extrusions; - if (mode == MODE_PATH) { - if (path_joined) { - extrusion_step = 1.0 / (extrusions - 1); - } - extrusion_step *= curve->get_baked_length(); - } + { + Vector3 *facesw = faces.ptrw(); + Vector2 *uvsw = uvs.ptrw(); + bool *smoothw = smooth.ptrw(); + Ref<Material> *materialsw = materials.ptrw(); + bool *invertw = invert.ptrw(); - if (mode == MODE_PATH) { - if (!path_local) { - base_xform = path->get_global_transform(); + int face = 0; + Transform3D base_xform; + Transform3D current_xform; + Transform3D previous_xform; + Transform3D previous_previous_xform; + double u_step = 1.0 / extrusions; + if (path_u_distance > 0.0) { + u_step *= curve_length / path_u_distance; + } + double v_step = 1.0 / shape_sides; + double spin_step = Math::deg2rad(spin_degrees / spin_sides); + double extrusion_step = 1.0 / extrusions; + if (mode == MODE_PATH) { + if (path_joined) { + extrusion_step = 1.0 / (extrusions - 1); + } + extrusion_step *= curve_length; } - Vector3 current_point = curve->interpolate_baked(0); - Vector3 next_point = curve->interpolate_baked(extrusion_step); - Vector3 current_up = Vector3(0, 1, 0); - Vector3 direction = next_point - current_point; + if (mode == MODE_PATH) { + if (!path_local) { + base_xform = path->get_global_transform(); + } - if (path_joined) { - Vector3 last_point = curve->interpolate_baked(curve->get_baked_length()); - direction = next_point - last_point; - } + Vector3 current_point = curve->interpolate_baked(0); + Vector3 next_point = curve->interpolate_baked(extrusion_step); + Vector3 current_up = Vector3(0, 1, 0); + Vector3 direction = next_point - current_point; - switch (path_rotation) { - case PATH_ROTATION_POLYGON: - direction = Vector3(0, 0, -1); - break; - case PATH_ROTATION_PATH: - break; - case PATH_ROTATION_PATH_FOLLOW: - current_up = curve->interpolate_baked_up_vector(0); - break; + if (path_joined) { + Vector3 last_point = curve->interpolate_baked(curve->get_baked_length()); + direction = next_point - last_point; + } + + switch (path_rotation) { + case PATH_ROTATION_POLYGON: + direction = Vector3(0, 0, -1); + break; + case PATH_ROTATION_PATH: + break; + case PATH_ROTATION_PATH_FOLLOW: + current_up = curve->interpolate_baked_up_vector(0); + break; + } + + Transform3D facing = Transform3D().looking_at(direction, current_up); + current_xform = base_xform.translated(current_point) * facing; } - Transform3D facing = Transform3D().looking_at(direction, current_up); - current_xform = base_xform.translated(current_point) * facing; - } + // Create the mesh. + if (end_count > 0) { + // Add front end face. + for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { + for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { + // We need to reverse the rotation of the shape face vertices. + int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx]; + Point2 p = shape_polygon[index]; + Point2 uv = (p - shape_rect.position) / shape_rect.size; + + // Use the left side of the bottom half of the y-inverted texture. + uv.x = uv.x / 2; + uv.y = 1 - (uv.y / 2); + + facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); + uvsw[face * 3 + face_vertex_idx] = uv; + } - // Create the mesh. - if (end_count > 0) { - // Add front end face. - for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { - for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { - // We need to reverse the rotation of the shape face vertices. - int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx]; - Point2 p = shape_polygon[index]; - Point2 uv = (p - shape_rect.position) / shape_rect.size; - - // Use the left side of the bottom half of the y-inverted texture. - uv.x = uv.x / 2; - uv.y = 1 - (uv.y / 2); - - facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); - uvsw[face * 3 + face_vertex_idx] = uv; + smoothw[face] = false; + materialsw[face] = material; + invertw[face] = invert_faces; + face++; } - - smoothw[face] = false; - materialsw[face] = material; - invertw[face] = invert_faces; - face++; } - } - // Add extrusion faces. - for (int x0 = 0; x0 < extrusions; x0++) { - previous_xform = current_xform; - - switch (mode) { - case MODE_DEPTH: { - current_xform.translate(Vector3(0, 0, -depth)); - } break; - case MODE_SPIN: { - current_xform.rotate(Vector3(0, 1, 0), spin_step); - } break; - case MODE_PATH: { - double previous_offset = x0 * extrusion_step; - double current_offset = (x0 + 1) * extrusion_step; - double next_offset = (x0 + 2) * extrusion_step; - if (x0 == extrusions - 1) { - if (path_joined) { - current_offset = 0; - next_offset = extrusion_step; + real_t angle_simplify_dot = Math::cos(Math::deg2rad(path_simplify_angle)); + Vector3 previous_simplify_dir = Vector3(0, 0, 0); + int faces_combined = 0; + + // Add extrusion faces. + for (int x0 = 0; x0 < extrusions; x0++) { + previous_previous_xform = previous_xform; + previous_xform = current_xform; + + switch (mode) { + case MODE_DEPTH: { + current_xform.translate(Vector3(0, 0, -depth)); + } break; + case MODE_SPIN: { + current_xform.rotate(Vector3(0, 1, 0), spin_step); + } break; + case MODE_PATH: { + double previous_offset = x0 * extrusion_step; + double current_offset = (x0 + 1) * extrusion_step; + double next_offset = (x0 + 2) * extrusion_step; + if (x0 == extrusions - 1) { + if (path_joined) { + current_offset = 0; + next_offset = extrusion_step; + } else { + next_offset = current_offset; + } + } + + Vector3 previous_point = curve->interpolate_baked(previous_offset); + Vector3 current_point = curve->interpolate_baked(current_offset); + Vector3 next_point = curve->interpolate_baked(next_offset); + Vector3 current_up = Vector3(0, 1, 0); + Vector3 direction = next_point - previous_point; + Vector3 current_dir = (current_point - previous_point).normalized(); + + // If the angles are similar, remove the previous face and replace it with this one. + if (path_simplify_angle > 0.0 && x0 > 0 && previous_simplify_dir.dot(current_dir) > angle_simplify_dot) { + faces_combined += 1; + previous_xform = previous_previous_xform; + face -= extrusion_face_count; + faces_removed += extrusion_face_count; } else { - next_offset = current_offset; + faces_combined = 0; + previous_simplify_dir = current_dir; } - } - Vector3 previous_point = curve->interpolate_baked(previous_offset); - Vector3 current_point = curve->interpolate_baked(current_offset); - Vector3 next_point = curve->interpolate_baked(next_offset); - Vector3 current_up = Vector3(0, 1, 0); - Vector3 direction = next_point - previous_point; + switch (path_rotation) { + case PATH_ROTATION_POLYGON: + direction = Vector3(0, 0, -1); + break; + case PATH_ROTATION_PATH: + break; + case PATH_ROTATION_PATH_FOLLOW: + current_up = curve->interpolate_baked_up_vector(current_offset); + break; + } - switch (path_rotation) { - case PATH_ROTATION_POLYGON: - direction = Vector3(0, 0, -1); - break; - case PATH_ROTATION_PATH: - break; - case PATH_ROTATION_PATH_FOLLOW: - current_up = curve->interpolate_baked_up_vector(current_offset); - break; - } + Transform3D facing = Transform3D().looking_at(direction, current_up); + current_xform = base_xform.translated(current_point) * facing; + } break; + } - Transform3D facing = Transform3D().looking_at(direction, current_up); - current_xform = base_xform.translated(current_point) * facing; - } break; - } + double u0 = (x0 - faces_combined) * u_step; + double u1 = ((x0 + 1) * u_step); + if (mode == MODE_PATH && !path_continuous_u) { + u0 = 0.0; + u1 = 1.0; + } - double u0 = x0 * u_step; - double u1 = ((x0 + 1) * u_step); - if (mode == MODE_PATH && !path_continuous_u) { - u0 = 0.0; - u1 = 1.0; - } + for (int y0 = 0; y0 < shape_sides; y0++) { + int y1 = (y0 + 1) % shape_sides; + // Use the top half of the texture. + double v0 = (y0 * v_step) / 2; + double v1 = ((y0 + 1) * v_step) / 2; - for (int y0 = 0; y0 < shape_sides; y0++) { - int y1 = (y0 + 1) % shape_sides; - // Use the top half of the texture. - double v0 = (y0 * v_step) / 2; - double v1 = ((y0 + 1) * v_step) / 2; - - Vector3 v[4] = { - previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), - current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), - current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), - previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), - }; - - Vector2 u[4] = { - Vector2(u0, v0), - Vector2(u1, v0), - Vector2(u1, v1), - Vector2(u0, v1), - }; - - // Face 1 - facesw[face * 3 + 0] = v[0]; - facesw[face * 3 + 1] = v[1]; - facesw[face * 3 + 2] = v[2]; - - uvsw[face * 3 + 0] = u[0]; - uvsw[face * 3 + 1] = u[1]; - uvsw[face * 3 + 2] = u[2]; - - smoothw[face] = smooth_faces; - invertw[face] = invert_faces; - materialsw[face] = material; - - face++; - - // Face 2 - facesw[face * 3 + 0] = v[2]; - facesw[face * 3 + 1] = v[3]; - facesw[face * 3 + 2] = v[0]; - - uvsw[face * 3 + 0] = u[2]; - uvsw[face * 3 + 1] = u[3]; - uvsw[face * 3 + 2] = u[0]; - - smoothw[face] = smooth_faces; - invertw[face] = invert_faces; - materialsw[face] = material; - - face++; - } - } + Vector3 v[4] = { + previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), + current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)), + current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), + previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)), + }; - if (end_count > 1) { - // Add back end face. - for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { - for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { - int index = shape_faces[face_idx * 3 + face_vertex_idx]; - Point2 p = shape_polygon[index]; - Point2 uv = (p - shape_rect.position) / shape_rect.size; + Vector2 u[4] = { + Vector2(u0, v0), + Vector2(u1, v0), + Vector2(u1, v1), + Vector2(u0, v1), + }; - // Use the x-inverted ride side of the bottom half of the y-inverted texture. - uv.x = 1 - uv.x / 2; - uv.y = 1 - (uv.y / 2); + // Face 1 + facesw[face * 3 + 0] = v[0]; + facesw[face * 3 + 1] = v[1]; + facesw[face * 3 + 2] = v[2]; - facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); - uvsw[face * 3 + face_vertex_idx] = uv; + uvsw[face * 3 + 0] = u[0]; + uvsw[face * 3 + 1] = u[1]; + uvsw[face * 3 + 2] = u[2]; + + smoothw[face] = smooth_faces; + invertw[face] = invert_faces; + materialsw[face] = material; + + face++; + + // Face 2 + facesw[face * 3 + 0] = v[2]; + facesw[face * 3 + 1] = v[3]; + facesw[face * 3 + 2] = v[0]; + + uvsw[face * 3 + 0] = u[2]; + uvsw[face * 3 + 1] = u[3]; + uvsw[face * 3 + 2] = u[0]; + + smoothw[face] = smooth_faces; + invertw[face] = invert_faces; + materialsw[face] = material; + + face++; } + } + + if (end_count > 1) { + // Add back end face. + for (int face_idx = 0; face_idx < shape_face_count; face_idx++) { + for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) { + int index = shape_faces[face_idx * 3 + face_vertex_idx]; + Point2 p = shape_polygon[index]; + Point2 uv = (p - shape_rect.position) / shape_rect.size; - smoothw[face] = false; - materialsw[face] = material; - invertw[face] = invert_faces; - face++; + // Use the x-inverted ride side of the bottom half of the y-inverted texture. + uv.x = 1 - uv.x / 2; + uv.y = 1 - (uv.y / 2); + + facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); + uvsw[face * 3 + face_vertex_idx] = uv; + } + + smoothw[face] = false; + materialsw[face] = material; + invertw[face] = invert_faces; + face++; + } } + + face_count -= faces_removed; + ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly."); } - ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly."); + if (faces_removed > 0) { + faces.resize(face_count * 3); + uvs.resize(face_count * 3); + smooth.resize(face_count); + materials.resize(face_count); + invert.resize(face_count); + } brush->build_from_faces(faces, uvs, smooth, materials, invert); @@ -2031,9 +2070,15 @@ void CSGPolygon3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon3D::set_path_node); ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon3D::get_path_node); + ClassDB::bind_method(D_METHOD("set_path_interval_type", "interval_type"), &CSGPolygon3D::set_path_interval_type); + ClassDB::bind_method(D_METHOD("get_path_interval_type"), &CSGPolygon3D::get_path_interval_type); + ClassDB::bind_method(D_METHOD("set_path_interval", "interval"), &CSGPolygon3D::set_path_interval); ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon3D::get_path_interval); + ClassDB::bind_method(D_METHOD("set_path_simplify_angle", "degrees"), &CSGPolygon3D::set_path_simplify_angle); + ClassDB::bind_method(D_METHOD("get_path_simplify_angle"), &CSGPolygon3D::get_path_simplify_angle); + ClassDB::bind_method(D_METHOD("set_path_rotation", "path_rotation"), &CSGPolygon3D::set_path_rotation); ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon3D::get_path_rotation); @@ -2043,6 +2088,9 @@ void CSGPolygon3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon3D::set_path_continuous_u); ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon3D::is_path_continuous_u); + ClassDB::bind_method(D_METHOD("set_path_u_distance", "distance"), &CSGPolygon3D::set_path_u_distance); + ClassDB::bind_method(D_METHOD("get_path_u_distance"), &CSGPolygon3D::get_path_u_distance); + ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon3D::set_path_joined); ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon3D::is_path_joined); @@ -2061,10 +2109,13 @@ void CSGPolygon3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees"); ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.1,1.0,0.05,exp"), "set_path_interval", "get_path_interval"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "path_interval_type", PROPERTY_HINT_ENUM, "Distance,Subdivide"), "set_path_interval_type", "get_path_interval_type"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.01,1.0,0.01,exp,or_greater"), "set_path_interval", "get_path_interval"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1,exp"), "set_path_simplify_angle", "get_path_simplify_angle"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_u_distance", PROPERTY_HINT_RANGE, "0.0,10.0,0.01,or_greater"), "set_path_u_distance", "get_path_u_distance"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_joined"), "set_path_joined", "is_path_joined"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); @@ -2076,6 +2127,9 @@ void CSGPolygon3D::_bind_methods() { BIND_ENUM_CONSTANT(PATH_ROTATION_POLYGON); BIND_ENUM_CONSTANT(PATH_ROTATION_PATH); BIND_ENUM_CONSTANT(PATH_ROTATION_PATH_FOLLOW); + + BIND_ENUM_CONSTANT(PATH_INTERVAL_DISTANCE); + BIND_ENUM_CONSTANT(PATH_INTERVAL_SUBDIVIDE); } void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) { @@ -2119,6 +2173,16 @@ bool CSGPolygon3D::is_path_continuous_u() const { return path_continuous_u; } +void CSGPolygon3D::set_path_u_distance(real_t p_path_u_distance) { + path_u_distance = p_path_u_distance; + _make_dirty(); + update_gizmos(); +} + +real_t CSGPolygon3D::get_path_u_distance() const { + return path_u_distance; +} + void CSGPolygon3D::set_spin_degrees(const float p_spin_degrees) { ERR_FAIL_COND(p_spin_degrees < 0.01 || p_spin_degrees > 360); spin_degrees = p_spin_degrees; @@ -2151,8 +2215,17 @@ NodePath CSGPolygon3D::get_path_node() const { return path_node; } +void CSGPolygon3D::set_path_interval_type(PathIntervalType p_interval_type) { + path_interval_type = p_interval_type; + _make_dirty(); + update_gizmos(); +} + +CSGPolygon3D::PathIntervalType CSGPolygon3D::get_path_interval_type() const { + return path_interval_type; +} + void CSGPolygon3D::set_path_interval(float p_interval) { - ERR_FAIL_COND_MSG(p_interval <= 0 || p_interval > 1, "Path interval must be greater than 0 and less than or equal to 1.0."); path_interval = p_interval; _make_dirty(); update_gizmos(); @@ -2162,6 +2235,16 @@ float CSGPolygon3D::get_path_interval() const { return path_interval; } +void CSGPolygon3D::set_path_simplify_angle(float p_angle) { + path_simplify_angle = p_angle; + _make_dirty(); + update_gizmos(); +} + +float CSGPolygon3D::get_path_simplify_angle() const { + return path_simplify_angle; +} + void CSGPolygon3D::set_path_rotation(PathRotation p_rotation) { path_rotation = p_rotation; _make_dirty(); @@ -2229,10 +2312,13 @@ CSGPolygon3D::CSGPolygon3D() { spin_degrees = 360; spin_sides = 8; smooth_faces = false; + path_interval_type = PATH_INTERVAL_DISTANCE; path_interval = 1.0; + path_simplify_angle = 0.0; path_rotation = PATH_ROTATION_PATH_FOLLOW; path_local = false; path_continuous_u = true; + path_u_distance = 1.0; path_joined = false; path = nullptr; } diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index 5cf371665e..c85cce776b 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -336,6 +336,11 @@ public: MODE_PATH }; + enum PathIntervalType { + PATH_INTERVAL_DISTANCE, + PATH_INTERVAL_SUBDIVIDE + }; + enum PathRotation { PATH_ROTATION_POLYGON, PATH_ROTATION_PATH, @@ -356,7 +361,9 @@ private: int spin_sides; NodePath path_node; + PathIntervalType path_interval_type; float path_interval; + float path_simplify_angle; PathRotation path_rotation; bool path_local; @@ -364,6 +371,7 @@ private: bool smooth_faces; bool path_continuous_u; + real_t path_u_distance; bool path_joined; bool _is_editable_3d_polygon() const; @@ -396,9 +404,15 @@ public: void set_path_node(const NodePath &p_path); NodePath get_path_node() const; + void set_path_interval_type(PathIntervalType p_interval_type); + PathIntervalType get_path_interval_type() const; + void set_path_interval(float p_interval); float get_path_interval() const; + void set_path_simplify_angle(float p_angle); + float get_path_simplify_angle() const; + void set_path_rotation(PathRotation p_rotation); PathRotation get_path_rotation() const; @@ -408,6 +422,9 @@ public: void set_path_continuous_u(bool p_enable); bool is_path_continuous_u() const; + void set_path_u_distance(real_t p_path_u_distance); + real_t get_path_u_distance() const; + void set_path_joined(bool p_enable); bool is_path_joined() const; @@ -422,5 +439,6 @@ public: VARIANT_ENUM_CAST(CSGPolygon3D::Mode) VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation) +VARIANT_ENUM_CAST(CSGPolygon3D::PathIntervalType) #endif // CSG_SHAPE_H diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index 5d56e56de9..ecbb7962d1 100644 --- a/modules/csg/doc_classes/CSGPolygon3D.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -24,6 +24,9 @@ <member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval"> When [member mode] is [constant MODE_PATH], the path interval or ratio of path points to extrusions. </member> + <member name="path_interval_type" type="int" setter="set_path_interval_type" getter="get_path_interval_type" enum="CSGPolygon3D.PathIntervalType"> + When [member mode] is [constant MODE_PATH], this will determine if the interval should be by distance ([constant PATH_INTERVAL_DISTANCE]) or subdivision fractions ([constant PATH_INTERVAL_SUBDIVIDE]). + </member> <member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined"> When [member mode] is [constant MODE_PATH], if [code]true[/code] the ends of the path are joined, by adding an extrusion between the last and first points of the path. </member> @@ -36,6 +39,12 @@ <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation"> When [member mode] is [constant MODE_PATH], the [enum PathRotation] method used to rotate the [member polygon] as it is extruded. </member> + <member name="path_simplify_angle" type="float" setter="set_path_simplify_angle" getter="get_path_simplify_angle"> + When [member mode] is [constant MODE_PATH], extrusions that are less than this angle, will be merged together to reduce polygon count. + </member> + <member name="path_u_distance" type="float" setter="set_path_u_distance" getter="get_path_u_distance"> + When [member mode] is [constant MODE_PATH], this is the distance along the path, in meters, the texture coordinates will tile. When set to 0, texture coordinates will match geometry exactly with no tiling. + </member> <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)"> The point array that defines the 2D polygon that is extruded. </member> @@ -70,5 +79,11 @@ <constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation"> The [member polygon] shape follows the path and its rotations around the path axis. </constant> + <constant name="PATH_INTERVAL_DISTANCE" value="0" enum="PathIntervalType"> + When [member mode] is set to [constant MODE_PATH], [member path_interval] will determine the distance, in meters, each interval of the path will extrude. + </constant> + <constant name="PATH_INTERVAL_SUBDIVIDE" value="1" enum="PathIntervalType"> + When [member mode] is set to [constant MODE_PATH], [member path_interval] will subdivide the polygons along the path. + </constant> </constants> </class> |