Browse Source

Merge pull request #102176 from ryevdokimov/fix-local-space-gizmo-basis

Add "active" state to one of the multiple selected Node3Ds to determine basis in Local mode
Thaddeus Crews 5 months ago
parent
commit
37fed7790e

+ 4 - 0
doc/classes/EditorSettings.xml

@@ -292,6 +292,10 @@
 		<member name="editors/2d/zoom_speed_factor" type="float" setter="" getter="">
 		<member name="editors/2d/zoom_speed_factor" type="float" setter="" getter="">
 			The factor to use when zooming in or out in the 2D editor. For example, [code]1.1[/code] will zoom in by 10% with every step. If set to [code]2.0[/code], zooming will only cycle through powers of two.
 			The factor to use when zooming in or out in the 2D editor. For example, [code]1.1[/code] will zoom in by 10% with every step. If set to [code]2.0[/code], zooming will only cycle through powers of two.
 		</member>
 		</member>
+		<member name="editors/3d/active_selection_box_color" type="Color" setter="" getter="">
+			The color to use for the active selection box that surrounds selected nodes in the 3D editor viewport. The color's alpha channel influences the selection box's opacity.
+			[b]Note:[/b] The term "active" indicates that this object is the primary selection used as the basis for certain operations. This is the last selected [Node3D], which can be reordered with [kbd]Shift + Left mouse button[/kbd].
+		</member>
 		<member name="editors/3d/default_fov" type="float" setter="" getter="">
 		<member name="editors/3d/default_fov" type="float" setter="" getter="">
 			The default camera vertical field of view to use in the 3D editor (in degrees). The camera field of view can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera field of view adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a [Camera3D] node is being previewed in the editor.
 			The default camera vertical field of view to use in the 3D editor (in degrees). The camera field of view can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera field of view adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a [Camera3D] node is being previewed in the editor.
 			[b]Note:[/b] The editor camera always uses the [b]Keep Height[/b] aspect mode.
 			[b]Note:[/b] The editor camera always uses the [b]Keep Height[/b] aspect mode.

+ 1 - 0
editor/editor_settings.cpp

@@ -789,6 +789,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 
 
 	// Use a similar color to the 2D editor selection.
 	// Use a similar color to the 2D editor selection.
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/selection_box_color", Color(1.0, 0.5, 0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/selection_box_color", Color(1.0, 0.5, 0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/active_selection_box_color", Color(1.5, 0.75, 0, 1.0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/aabb", Color(0.28, 0.8, 0.82), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
 	EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/aabb", Color(0.28, 0.8, 0.82), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)

+ 62 - 4
editor/plugins/node_3d_editor_plugin.cpp

@@ -791,8 +791,12 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) {
 
 
 	if (p_allow_locked || (selected != nullptr && !_is_node_locked(selected))) {
 	if (p_allow_locked || (selected != nullptr && !_is_node_locked(selected))) {
 		if (clicked_wants_append) {
 		if (clicked_wants_append) {
+			Node *active_node = editor_selection->get_selected_node_list().is_empty() ? nullptr : editor_selection->get_selected_node_list().back()->get();
 			if (editor_selection->is_selected(selected)) {
 			if (editor_selection->is_selected(selected)) {
 				editor_selection->remove_node(selected);
 				editor_selection->remove_node(selected);
+				if (selected != active_node) {
+					editor_selection->add_node(selected);
+				}
 			} else {
 			} else {
 				editor_selection->add_node(selected);
 				editor_selection->add_node(selected);
 			}
 			}
@@ -6242,7 +6246,7 @@ void Node3DEditor::update_transform_gizmo() {
 		for (const KeyValue<int, Transform3D> &E : se->subgizmos) {
 		for (const KeyValue<int, Transform3D> &E : se->subgizmos) {
 			Transform3D xf = se->sp->get_global_transform() * se->gizmo->get_subgizmo_transform(E.key);
 			Transform3D xf = se->sp->get_global_transform() * se->gizmo->get_subgizmo_transform(E.key);
 			gizmo_center += xf.origin;
 			gizmo_center += xf.origin;
-			if (count == 0 && local_gizmo_coords) {
+			if ((unsigned int)count == se->subgizmos.size() - 1 && local_gizmo_coords) {
 				gizmo_basis = xf.basis;
 				gizmo_basis = xf.basis;
 			}
 			}
 			count++;
 			count++;
@@ -6266,7 +6270,7 @@ void Node3DEditor::update_transform_gizmo() {
 
 
 			Transform3D xf = sel_item->sp->get_global_transform();
 			Transform3D xf = sel_item->sp->get_global_transform();
 			gizmo_center += xf.origin;
 			gizmo_center += xf.origin;
-			if (count == 0 && local_gizmo_coords) {
+			if (count == selection.size() - 1 && local_gizmo_coords) {
 				gizmo_basis = xf.basis;
 				gizmo_basis = xf.basis;
 			}
 			}
 			count++;
 			count++;
@@ -6275,7 +6279,7 @@ void Node3DEditor::update_transform_gizmo() {
 
 
 	gizmo.visible = count > 0;
 	gizmo.visible = count > 0;
 	gizmo.transform.origin = (count > 0) ? gizmo_center / count : Vector3();
 	gizmo.transform.origin = (count > 0) ? gizmo_center / count : Vector3();
-	gizmo.transform.basis = (count == 1) ? gizmo_basis : Basis();
+	gizmo.transform.basis = gizmo_basis;
 
 
 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
 		viewports[i]->update_transform_gizmo_view();
 		viewports[i]->update_transform_gizmo_view();
@@ -6367,23 +6371,33 @@ void Node3DEditor::_generate_selection_boxes() {
 	// This lets the user see where the selection is while still having a sense of depth.
 	// This lets the user see where the selection is while still having a sense of depth.
 	Ref<SurfaceTool> st = memnew(SurfaceTool);
 	Ref<SurfaceTool> st = memnew(SurfaceTool);
 	Ref<SurfaceTool> st_xray = memnew(SurfaceTool);
 	Ref<SurfaceTool> st_xray = memnew(SurfaceTool);
+	Ref<SurfaceTool> active_st = memnew(SurfaceTool);
+	Ref<SurfaceTool> active_st_xray = memnew(SurfaceTool);
 
 
 	st->begin(Mesh::PRIMITIVE_LINES);
 	st->begin(Mesh::PRIMITIVE_LINES);
 	st_xray->begin(Mesh::PRIMITIVE_LINES);
 	st_xray->begin(Mesh::PRIMITIVE_LINES);
+	active_st->begin(Mesh::PRIMITIVE_LINES);
+	active_st_xray->begin(Mesh::PRIMITIVE_LINES);
 	for (int i = 0; i < 12; i++) {
 	for (int i = 0; i < 12; i++) {
 		Vector3 a, b;
 		Vector3 a, b;
 		aabb.get_edge(i, a, b);
 		aabb.get_edge(i, a, b);
 
 
 		st->add_vertex(a);
 		st->add_vertex(a);
 		st->add_vertex(b);
 		st->add_vertex(b);
+		active_st->add_vertex(a);
+		active_st->add_vertex(b);
 		st_xray->add_vertex(a);
 		st_xray->add_vertex(a);
 		st_xray->add_vertex(b);
 		st_xray->add_vertex(b);
+		active_st_xray->add_vertex(a);
+		active_st_xray->add_vertex(b);
 	}
 	}
 
 
+	const Color selection_box_color = EDITOR_GET("editors/3d/selection_box_color");
+	const Color active_selection_box_color = EDITOR_GET("editors/3d/active_selection_box_color");
+
 	Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
 	Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
 	mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
 	mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
 	mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
 	mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
-	const Color selection_box_color = EDITOR_GET("editors/3d/selection_box_color");
 	mat->set_albedo(selection_box_color);
 	mat->set_albedo(selection_box_color);
 	mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
 	mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
 	st->set_material(mat);
 	st->set_material(mat);
@@ -6397,6 +6411,23 @@ void Node3DEditor::_generate_selection_boxes() {
 	mat_xray->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
 	mat_xray->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
 	st_xray->set_material(mat_xray);
 	st_xray->set_material(mat_xray);
 	selection_box_xray = st_xray->commit();
 	selection_box_xray = st_xray->commit();
+
+	Ref<StandardMaterial3D> active_mat = memnew(StandardMaterial3D);
+	active_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+	active_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
+	active_mat->set_albedo(active_selection_box_color);
+	active_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+	active_st->set_material(active_mat);
+	active_selection_box = active_st->commit();
+
+	Ref<StandardMaterial3D> active_mat_xray = memnew(StandardMaterial3D);
+	active_mat_xray->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+	active_mat_xray->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
+	active_mat_xray->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
+	active_mat_xray->set_albedo(active_selection_box_color * Color(1, 1, 1, 0.15));
+	active_mat_xray->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+	active_st_xray->set_material(active_mat_xray);
+	active_selection_box_xray = active_st_xray->commit();
 }
 }
 
 
 Dictionary Node3DEditor::get_state() const {
 Dictionary Node3DEditor::get_state() const {
@@ -7831,6 +7862,33 @@ void Node3DEditor::update_grid() {
 
 
 void Node3DEditor::_selection_changed() {
 void Node3DEditor::_selection_changed() {
 	_refresh_menu_icons();
 	_refresh_menu_icons();
+
+	const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
+
+	for (const KeyValue<Node *, Object *> &E : selection) {
+		Node3D *sp = Object::cast_to<Node3D>(E.key);
+		if (!sp) {
+			continue;
+		}
+
+		Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+		if (!se) {
+			continue;
+		}
+
+		if (sp == editor_selection->get_selected_node_list().back()->get()) {
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance, active_selection_box->get_rid());
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance_xray, active_selection_box_xray->get_rid());
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance_offset, active_selection_box->get_rid());
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance_xray_offset, active_selection_box_xray->get_rid());
+		} else {
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance, selection_box->get_rid());
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance_xray, selection_box_xray->get_rid());
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance_offset, selection_box->get_rid());
+			RenderingServer::get_singleton()->instance_set_base(se->sbox_instance_xray_offset, selection_box_xray->get_rid());
+		}
+	}
+
 	if (selected && editor_selection->get_selected_node_list().size() != 1) {
 	if (selected && editor_selection->get_selected_node_list().size() != 1) {
 		Vector<Ref<Node3DGizmo>> gizmos = selected->get_gizmos();
 		Vector<Ref<Node3DGizmo>> gizmos = selected->get_gizmos();
 		for (int i = 0; i < gizmos.size(); i++) {
 		for (int i = 0; i < gizmos.size(); i++) {

+ 3 - 0
editor/plugins/node_3d_editor_plugin.h

@@ -693,8 +693,11 @@ private:
 	real_t snap_rotate_value;
 	real_t snap_rotate_value;
 	real_t snap_scale_value;
 	real_t snap_scale_value;
 
 
+	Ref<ArrayMesh> active_selection_box_xray;
+	Ref<ArrayMesh> active_selection_box;
 	Ref<ArrayMesh> selection_box_xray;
 	Ref<ArrayMesh> selection_box_xray;
 	Ref<ArrayMesh> selection_box;
 	Ref<ArrayMesh> selection_box;
+
 	RID indicators;
 	RID indicators;
 	RID indicators_instance;
 	RID indicators_instance;
 	RID cursor_mesh;
 	RID cursor_mesh;