Переглянути джерело

Merge pull request #11478 from n-pigeon/scale_gizmo

Scale editing Gizmo for Spatial Editor
Andreas Haas 8 роки тому
батько
коміт
5cd68abf88

+ 186 - 52
editor/plugins/spatial_editor_plugin.cpp

@@ -49,13 +49,15 @@
 
 #define DISTANCE_DEFAULT 4
 
-#define GIZMO_ARROW_SIZE 0.3
+#define GIZMO_ARROW_SIZE 0.35
 #define GIZMO_RING_HALF_WIDTH 0.1
 //#define GIZMO_SCALE_DEFAULT 0.28
 #define GIZMO_SCALE_DEFAULT 0.15
 #define GIZMO_PLANE_SIZE 0.2
 #define GIZMO_PLANE_DST 0.3
-#define GIZMO_CIRCLE_SIZE 0.9
+#define GIZMO_CIRCLE_SIZE 1.1
+#define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
+#define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
 
 #define ZOOM_MIN_DISTANCE 0.001
 #define ZOOM_MULTIPLIER 1.08
@@ -538,8 +540,6 @@ void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
 
 	List<Node *> &selection = editor_selection->get_selected_node_list();
 
-	//Vector3 center;
-	//int nc=0;
 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
 
 		Spatial *sp = Object::cast_to<Spatial>(E->get());
@@ -551,14 +551,8 @@ void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
 			continue;
 
 		se->original = se->sp->get_global_transform();
-		//center+=se->original.origin;
-		//nc++;
+		se->original_local = se->sp->get_transform();
 	}
-
-	/*
-	if (nc)
-		_edit.center=center/float(nc);
-	*/
 }
 
 static int _get_key_modifier_setting(const String &p_property) {
@@ -609,7 +603,7 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig
 
 		for (int i = 0; i < 3; i++) {
 
-			Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs;
+			Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
 			float grabber_radius = gs * GIZMO_ARROW_SIZE;
 
 			Vector3 r;
@@ -624,7 +618,7 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig
 		}
 
 		bool is_plane_translate = false;
-		// second try
+		// plane select
 		if (col_axis == -1) {
 			col_d = 1e20;
 
@@ -710,6 +704,43 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig
 		}
 	}
 
+	if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) {
+
+		int col_axis = -1;
+		float col_d = 1e20;
+
+		for (int i = 0; i < 3; i++) {
+
+			Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET;
+			float grabber_radius = gs * GIZMO_ARROW_SIZE;
+
+			Vector3 r;
+
+			if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * 10000.0, grabber_pos, grabber_radius, &r)) {
+				float d = r.distance_to(ray_pos);
+				if (d < col_d) {
+					col_d = d;
+					col_axis = i;
+				}
+			}
+		}
+
+		if (col_axis != -1) {
+
+			if (p_highlight_only) {
+
+				spatial_editor->select_gizmo_highlight_axis(col_axis + 9);
+
+			} else {
+				//handle scale
+				_edit.mode = TRANSFORM_SCALE;
+				_compute_edit(Point2(p_screenpos.x, p_screenpos.y));
+				_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
+			}
+			return true;
+		}
+	}
+
 	if (p_highlight_only)
 		spatial_editor->select_gizmo_highlight_axis(-1);
 
@@ -1182,7 +1213,28 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
 
 					case TRANSFORM_SCALE: {
 
-						Plane plane = Plane(_edit.center, _get_camera_normal());
+						Vector3 motion_mask;
+						Plane plane;
+						bool plane_mv;
+
+						switch (_edit.plane) {
+							case TRANSFORM_VIEW:
+								motion_mask = Vector3(0, 0, 0);
+								plane = Plane(_edit.center, _get_camera_normal());
+								break;
+							case TRANSFORM_X_AXIS:
+								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
+								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+								break;
+							case TRANSFORM_Y_AXIS:
+								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
+								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+								break;
+							case TRANSFORM_Z_AXIS:
+								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
+								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+								break;
+						}
 
 						Vector3 intersection;
 						if (!plane.intersects_ray(ray_pos, ray, &intersection))
@@ -1192,42 +1244,78 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
 						if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
 							break;
 
-						float center_click_dist = click.distance_to(_edit.center);
-						float center_inters_dist = intersection.distance_to(_edit.center);
-						if (center_click_dist == 0)
-							break;
+						Vector3 motion = intersection - click;
+						print_line(String(intersection) + " --- " + String(click));
+						if (motion_mask != Vector3()) {
 
-						float scale = (center_inters_dist / center_click_dist) * 100.0;
+							motion = motion_mask.dot(motion) * motion_mask;
+						} else {
 
-						if (_edit.snap || spatial_editor->is_snap_enabled()) {
+							float center_click_dist = click.distance_to(_edit.center);
+							float center_inters_dist = intersection.distance_to(_edit.center);
+							if (center_click_dist == 0)
+								break;
 
-							scale = Math::stepify(scale, spatial_editor->get_scale_snap());
+							float scale = center_inters_dist - center_click_dist;
+							motion = Vector3(scale, scale, scale);
 						}
 
-						set_message(vformat(TTR("Scaling to %s%%."), String::num(scale, 1)));
-						scale /= 100.0;
+						List<Node *> &selection = editor_selection->get_selected_node_list();
 
-						Transform r;
-						r.basis.scale(Vector3(scale, scale, scale));
+						bool local_coords = (spatial_editor->are_local_coords_enabled() && motion_mask != Vector3()); // Disable local transformation for TRANSFORM_VIEW
 
-						List<Node *> &selection = editor_selection->get_selected_node_list();
+						float snap = 0;
+						if (_edit.snap || spatial_editor->is_snap_enabled()) {
+
+							snap = spatial_editor->get_scale_snap() / 100;
+						}
 
 						for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
 
 							Spatial *sp = Object::cast_to<Spatial>(E->get());
-							if (!sp)
+							if (!sp) {
 								continue;
+							}
 
 							SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
-							if (!se)
+							if (!se) {
 								continue;
+							}
 
 							Transform original = se->original;
-
+							Transform original_local = se->original_local;
 							Transform base = Transform(Basis(), _edit.center);
-							Transform t = base * (r * (base.inverse() * original));
+							Transform t;
+							Vector3 local_scale;
 
-							sp->set_global_transform(t);
+							if (local_coords) {
+
+								Basis g = original.basis.orthonormalized();
+								Vector3 local_motion = g.inverse().xform(motion);
+
+								if (_edit.snap || spatial_editor->is_snap_enabled()) {
+									local_motion.snap(Vector3(snap, snap, snap));
+								}
+
+								local_scale = original_local.basis.get_scale() * (local_motion + Vector3(1, 1, 1));
+
+							} else {
+
+								if (_edit.snap || spatial_editor->is_snap_enabled()) {
+									motion.snap(Vector3(snap, snap, snap));
+								}
+
+								Transform r;
+								r.basis.scale(motion + Vector3(1, 1, 1));
+								t = base * (r * (base.inverse() * original));
+							}
+
+							// Apply scale
+							if (local_coords) {
+								sp->set_scale(local_scale);
+							} else {
+								sp->set_global_transform(t);
+							}
 						}
 
 						surface->update();
@@ -2271,6 +2359,14 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
 		//VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
 		VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
+
+		scale_gizmo_instance[i] = VS::get_singleton()->instance_create();
+		VS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid());
+		VS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
+		VS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
+		//VS::get_singleton()->instance_geometry_set_flag(scale_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
+		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
+		VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer);
 	}
 }
 
@@ -2280,6 +2376,7 @@ void SpatialEditorViewport::_finish_gizmo_instances() {
 		VS::get_singleton()->free(move_gizmo_instance[i]);
 		VS::get_singleton()->free(move_plane_gizmo_instance[i]);
 		VS::get_singleton()->free(rotate_gizmo_instance[i]);
+		VS::get_singleton()->free(scale_gizmo_instance[i]);
 	}
 }
 void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
@@ -2374,6 +2471,8 @@ void SpatialEditorViewport::update_transform_gizmo_view() {
 		VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
 		VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
 		VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE));
+		VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
+		VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
 	}
 }
 
@@ -3259,6 +3358,7 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) {
 		move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_hl : gizmo_color[i]);
 		move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? gizmo_hl : plane_gizmo_color[i]);
 		rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_hl : gizmo_color[i]);
+		scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_hl : gizmo_color[i]);
 	}
 }
 
@@ -3269,7 +3369,7 @@ void SpatialEditor::update_transform_gizmo() {
 	bool first = true;
 
 	Basis gizmo_basis;
-	bool local_gizmo_coords = transform_menu->get_popup()->is_item_checked(transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS));
+	bool local_gizmo_coords = are_local_coords_enabled();
 
 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
 
@@ -3720,10 +3820,6 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
 
 void SpatialEditor::_init_indicators() {
 
-	//RID mat = VisualServer::get_singleton()->fixed_material_create();
-	///VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
-	//VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
-
 	{
 
 		indicator_mat.instance();
@@ -3835,6 +3931,7 @@ void SpatialEditor::_init_indicators() {
 			move_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
 			move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
 			rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+			scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
 
 			Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
 			mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
@@ -3857,25 +3954,25 @@ void SpatialEditor::_init_indicators() {
 			Vector3 ivec3;
 			ivec3[(i + 2) % 3] = 1;
 
+			//translate
 			{
 
 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
 
-				//translate
-
+				// Arrow profile
 				const int arrow_points = 5;
 				Vector3 arrow[5] = {
 					nivec * 0.0 + ivec * 0.0,
 					nivec * 0.01 + ivec * 0.0,
-					nivec * 0.01 + ivec * 1.0,
-					nivec * 0.1 + ivec * 1.0,
-					nivec * 0.0 + ivec * (1 + GIZMO_ARROW_SIZE),
+					nivec * 0.01 + ivec * GIZMO_ARROW_OFFSET,
+					nivec * 0.065 + ivec * GIZMO_ARROW_OFFSET,
+					nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE),
 				};
 
 				int arrow_sides = 6;
 
-				for (int k = 0; k < 7; k++) {
+				for (int k = 0; k < 6; k++) {
 
 					Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
 					Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
@@ -3902,7 +3999,7 @@ void SpatialEditor::_init_indicators() {
 				surftool->commit(move_gizmo[i]);
 			}
 
-			// plane translation
+			// Plane Translation
 			{
 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
@@ -3945,6 +4042,7 @@ void SpatialEditor::_init_indicators() {
 				surftool->commit(move_plane_gizmo[i]);
 			}
 
+			// Rotate
 			{
 
 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
@@ -3958,7 +4056,7 @@ void SpatialEditor::_init_indicators() {
 					ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
 				};
 
-				for (int k = 0; k < 33; k++) {
+				for (int k = 0; k < 32; k++) {
 
 					Basis ma(ivec, Math_PI * 2 * float(k) / 32);
 					Basis mb(ivec, Math_PI * 2 * float(k + 1) / 32);
@@ -3984,19 +4082,55 @@ void SpatialEditor::_init_indicators() {
 				surftool->set_material(mat);
 				surftool->commit(rotate_gizmo[i]);
 			}
-		}
-	}
 
-	/*for(int i=0;i<4;i++) {
+			// Scale
+			{
+				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
 
-		viewports[i]->init_gizmo_instance(i);
-	}*/
+				// Cube arrow profile
+				const int arrow_points = 6;
+				Vector3 arrow[6] = {
+					nivec * 0.0 + ivec * 0.0,
+					nivec * 0.01 + ivec * 0.0,
+					nivec * 0.01 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
+					nivec * 0.07 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
+					nivec * 0.07 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
+					nivec * 0.0 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
+				};
 
-	_generate_selection_box();
+				int arrow_sides = 4;
+
+				for (int k = 0; k < 4; k++) {
 
-	//Object::cast_to<EditorNode>(get_scene()->get_root_node())->get_scene_root()->add_child(camera);
+					Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
+					Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
 
-	//current_camera=camera;
+					for (int j = 0; j < arrow_points - 1; j++) {
+
+						Vector3 points[4] = {
+							ma.xform(arrow[j]),
+							mb.xform(arrow[j]),
+							mb.xform(arrow[j + 1]),
+							ma.xform(arrow[j + 1]),
+						};
+						surftool->add_vertex(points[0]);
+						surftool->add_vertex(points[1]);
+						surftool->add_vertex(points[2]);
+
+						surftool->add_vertex(points[0]);
+						surftool->add_vertex(points[2]);
+						surftool->add_vertex(points[3]);
+					}
+				}
+
+				surftool->set_material(mat);
+				surftool->commit(scale_gizmo[i]);
+			}
+		}
+	}
+
+	_generate_selection_box();
 }
 
 void SpatialEditor::_finish_indicators() {

+ 4 - 2
editor/plugins/spatial_editor_plugin.h

@@ -245,7 +245,7 @@ private:
 
 	real_t zoom_indicator_delay;
 
-	RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3];
+	RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3];
 
 	String last_message;
 	String message;
@@ -319,6 +319,7 @@ class SpatialEditorSelectedItem : public Object {
 public:
 	Rect3 aabb;
 	Transform original; // original location when moving
+	Transform original_local;
 	Transform last_xform; // last transform
 	Spatial *sp;
 	RID sbox_instance;
@@ -407,7 +408,7 @@ private:
 	bool grid_enable[3]; //should be always visible if true
 	bool grid_enabled;
 
-	Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3];
+	Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3];
 	Ref<SpatialMaterial> gizmo_color[3];
 	Ref<SpatialMaterial> plane_gizmo_color[3];
 	Ref<SpatialMaterial> gizmo_hl;
@@ -557,6 +558,7 @@ public:
 	Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
 	Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
 	Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; }
+	Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
 
 	void update_transform_gizmo();