Bläddra i källkod

Merge pull request #68860 from xiongyaohua/path3d_fishbones

Draw fish bones for Path3D and Path2D in the Editor
Rémi Verschelde 2 år sedan
förälder
incheckning
14861c45b5

+ 44 - 19
editor/plugins/path_3d_editor_plugin.cpp

@@ -240,38 +240,63 @@ void Path3DGizmo::redraw() {
 		return;
 	}
 
-	Vector<Vector3> v3a = c->tessellate();
-	//Vector<Vector3> v3a=c->get_baked_points();
+	real_t interval = 0.1;
+	const real_t length = c->get_baked_length();
 
-	int v3s = v3a.size();
-	if (v3s == 0) {
-		return;
-	}
-	Vector<Vector3> v3p;
-	const Vector3 *r = v3a.ptr();
-
-	// BUG: the following won't work when v3s, avoid drawing as a temporary workaround.
-	for (int i = 0; i < v3s - 1; i++) {
-		v3p.push_back(r[i]);
-		v3p.push_back(r[i + 1]);
-		//v3p.push_back(r[i]);
-		//v3p.push_back(r[i]+Vector3(0,0.2,0));
-	}
+	// 1. Draw curve and bones.
+	if (length > CMP_EPSILON) {
+		const int sample_count = int(length / interval) + 2;
+		interval = length / (sample_count - 1); // Recalculate real interval length.
+
+		Vector<Transform3D> frames;
+		frames.resize(sample_count);
+
+		{
+			Transform3D *w = frames.ptrw();
+
+			for (int i = 0; i < sample_count; i++) {
+				w[i] = c->sample_baked_with_rotation(i * interval, true, true);
+			}
+		}
+
+		const Transform3D *r = frames.ptr();
+		Vector<Vector3> v3p;
+		for (int i = 0; i < sample_count - 1; i++) {
+			const Vector3 p1 = r[i].origin;
+			const Vector3 p2 = r[i + 1].origin;
+			const Vector3 side = r[i].basis.get_column(0);
+			const Vector3 up = r[i].basis.get_column(1);
+			const Vector3 forward = r[i].basis.get_column(2);
+
+			// Curve segment.
+			v3p.push_back(p1);
+			v3p.push_back(p2);
+
+			// Fish Bone.
+			v3p.push_back(p1);
+			v3p.push_back(p1 + (side - forward) * 0.06);
+
+			v3p.push_back(p1);
+			v3p.push_back(p1 + (-side - forward) * 0.06);
+
+			v3p.push_back(p1);
+			v3p.push_back(p1 + up * 0.03);
+		}
 
-	if (v3p.size() > 1) {
 		add_lines(v3p, path_material);
 		add_collision_segments(v3p);
 	}
 
+	// 2. Draw handles.
 	if (Path3DEditorPlugin::singleton->get_edited_path() == path) {
-		v3p.clear();
+		Vector<Vector3> v3p;
 		Vector<Vector3> handle_points;
 		Vector<Vector3> sec_handle_points;
 
 		for (int i = 0; i < c->get_point_count(); i++) {
 			Vector3 p = c->get_point_position(i);
 			handle_points.push_back(p);
-			// push Out points first so they get selected if the In and Out points are on top of each other.
+			// Push out points first so they get selected if the In and Out points are on top of each other.
 			if (i < c->get_point_count() - 1) {
 				v3p.push_back(p);
 				v3p.push_back(p + c->get_point_out(i));

+ 49 - 10
scene/2d/path_2d.cpp

@@ -106,18 +106,57 @@ void Path2D::_notification(int p_what) {
 #else
 			const real_t line_width = get_tree()->get_debug_paths_width();
 #endif
-			_cached_draw_pts.resize(curve->get_point_count() * 8);
-			int count = 0;
-
-			for (int i = 0; i < curve->get_point_count(); i++) {
-				for (int j = 0; j < 8; j++) {
-					real_t frac = j * (1.0 / 8.0);
-					Vector2 p = curve->sample(i, frac);
-					_cached_draw_pts.set(count++, p);
+			real_t interval = 10;
+			const real_t length = curve->get_baked_length();
+
+			if (length > CMP_EPSILON) {
+				const int sample_count = int(length / interval) + 2;
+				interval = length / (sample_count - 1); // Recalculate real interval length.
+
+				Vector<Transform2D> frames;
+				frames.resize(sample_count);
+
+				{
+					Transform2D *w = frames.ptrw();
+
+					for (int i = 0; i < sample_count; i++) {
+						w[i] = curve->sample_baked_with_rotation(i * interval, true, true);
+					}
 				}
-			}
 
-			draw_polyline(_cached_draw_pts, get_tree()->get_debug_paths_color(), line_width, true);
+				const Transform2D *r = frames.ptr();
+				// Draw curve segments
+				{
+					PackedVector2Array v2p;
+					v2p.resize(sample_count);
+					Vector2 *w = v2p.ptrw();
+
+					for (int i = 0; i < sample_count; i++) {
+						w[i] = r[i].get_origin();
+					}
+					draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width, false);
+				}
+
+				// Draw fish bones
+				{
+					PackedVector2Array v2p;
+					v2p.resize(3);
+					Vector2 *w = v2p.ptrw();
+
+					for (int i = 0; i < sample_count; i++) {
+						const Vector2 p = r[i].get_origin();
+						const Vector2 side = r[i].columns[0];
+						const Vector2 forward = r[i].columns[1];
+
+						// Fish Bone.
+						w[0] = p + (side - forward) * 5;
+						w[1] = p;
+						w[2] = p + (-side - forward) * 5;
+
+						draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width * 0.5, false);
+					}
+				}
+			}
 		} break;
 	}
 }

+ 0 - 1
scene/2d/path_2d.h

@@ -38,7 +38,6 @@ class Path2D : public Node2D {
 	GDCLASS(Path2D, Node2D);
 
 	Ref<Curve2D> curve;
-	Vector<Vector2> _cached_draw_pts;
 
 	void _curve_changed();
 

+ 25 - 7
servers/rendering/renderer_canvas_cull.cpp

@@ -1075,18 +1075,36 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
 
 void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
 	ERR_FAIL_COND(p_points.size() < 2);
-	Item *canvas_item = canvas_item_owner.get_or_null(p_item);
-	ERR_FAIL_COND(!canvas_item);
-
-	Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
-	ERR_FAIL_COND(!pline);
 
-	if (true || p_width <= 1) {
-#define TODO make thick lines possible
+	// TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out.
+	if (p_width <= 1) {
+		Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+		ERR_FAIL_COND(!canvas_item);
 
+		Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
+		ERR_FAIL_COND(!pline);
 		pline->primitive = RS::PRIMITIVE_LINES;
 		pline->polygon.create(Vector<int>(), p_points, p_colors);
 	} else {
+		if (p_colors.size() == 1) {
+			Color color = p_colors[0];
+			for (int i = 0; i < p_points.size() >> 1; i++) {
+				Vector2 from = p_points[i * 2 + 0];
+				Vector2 to = p_points[i * 2 + 1];
+
+				canvas_item_add_line(p_item, from, to, color, p_width);
+			}
+		} else if (p_colors.size() == p_points.size() >> 1) {
+			for (int i = 0; i < p_points.size() >> 1; i++) {
+				Color color = p_colors[i];
+				Vector2 from = p_points[i * 2 + 0];
+				Vector2 to = p_points[i * 2 + 1];
+
+				canvas_item_add_line(p_item, from, to, color, p_width);
+			}
+		} else {
+			ERR_FAIL_MSG("Length of p_colors is invalid.");
+		}
 	}
 }