From 8a3a4fa3a01d27f86a28160a10cf80523cba8fcb Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sat, 4 Jul 2020 00:11:56 +0200 Subject: [PATCH] Improve the 3D editor selection box appearance - Draw two boxes slightly offset from each other to give the illustion of a thicker outline. - Decrease the offset compared to the 3D node's AABB to give a more accurate representation of its size. - Make the box fully visible instead of only displaying the corners. - Draw a x-ray version of the box that's more translucent, but visible through walls. This helps make the box more visible while still having a sense of depth. - Use an orange color similar to the 2D editor. --- editor/plugins/node_3d_editor_plugin.cpp | 65 ++++++++++++++++++------ editor/plugins/node_3d_editor_plugin.h | 4 +- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index cc26caa5a35..fdbf3415db5 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2426,6 +2426,7 @@ void Node3DEditorViewport::_notification(int p_what) { t.basis = t.basis * aabb_s; RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance, t); + RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance_xray, t); } if (changed || (spatial_editor->is_gizmo_visible() && !exist)) { @@ -4417,6 +4418,9 @@ Node3DEditorSelectedItem::~Node3DEditorSelectedItem() { if (sbox_instance.is_valid()) { RenderingServer::get_singleton()->free(sbox_instance); } + if (sbox_instance_xray.is_valid()) { + RenderingServer::get_singleton()->free(sbox_instance_xray); + } } void Node3DEditor::select_gizmo_highlight_axis(int p_axis) { @@ -4500,42 +4504,73 @@ Object *Node3DEditor::_get_editor_data(Object *p_what) { Node3DEditorSelectedItem *si = memnew(Node3DEditorSelectedItem); si->sp = sp; - si->sbox_instance = RenderingServer::get_singleton()->instance_create2(selection_box->get_rid(), sp->get_world_3d()->get_scenario()); - RS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, RS::SHADOW_CASTING_SETTING_OFF); + si->sbox_instance = RenderingServer::get_singleton()->instance_create2( + selection_box->get_rid(), + sp->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting( + si->sbox_instance, + RS::SHADOW_CASTING_SETTING_OFF); + si->sbox_instance_xray = RenderingServer::get_singleton()->instance_create2( + selection_box_xray->get_rid(), + sp->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting( + si->sbox_instance_xray, + RS::SHADOW_CASTING_SETTING_OFF); return si; } -void Node3DEditor::_generate_selection_box() { +void Node3DEditor::_generate_selection_boxes() { + // Use two AABBs to create the illusion of a slightly thicker line. AABB aabb(Vector3(), Vector3(1, 1, 1)); - aabb.grow_by(aabb.get_longest_axis_size() / 20.0); + AABB aabb_offset(Vector3(), Vector3(1, 1, 1)); + // Grow the bounding boxes slightly to avoid Z-fighting with the mesh's edges. + aabb.grow_by(0.005); + aabb_offset.grow_by(0.01); + // Create a x-ray (visible through solid surfaces) and standard version of the selection box. + // Both will be drawn at the same position, but with different opacity. + // This lets the user see where the selection is while still having a sense of depth. Ref st = memnew(SurfaceTool); + Ref st_xray = memnew(SurfaceTool); st->begin(Mesh::PRIMITIVE_LINES); + st_xray->begin(Mesh::PRIMITIVE_LINES); for (int i = 0; i < 12; i++) { Vector3 a, b; aabb.get_edge(i, a, b); - st->add_color(Color(1.0, 1.0, 0.8, 0.8)); st->add_vertex(a); - st->add_color(Color(1.0, 1.0, 0.8, 0.4)); - st->add_vertex(a.lerp(b, 0.2)); - - st->add_color(Color(1.0, 1.0, 0.8, 0.4)); - st->add_vertex(a.lerp(b, 0.8)); - st->add_color(Color(1.0, 1.0, 0.8, 0.8)); st->add_vertex(b); + st_xray->add_vertex(a); + st_xray->add_vertex(b); + } + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb_offset.get_edge(i, a, b); + + st->add_vertex(a); + st->add_vertex(b); + st_xray->add_vertex(a); + st_xray->add_vertex(b); } Ref mat = memnew(StandardMaterial3D); mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - mat->set_albedo(Color(1, 1, 1)); + // Use a similar color to the 2D editor selection. + mat->set_albedo(Color(1, 0.5, 0)); mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); st->set_material(mat); selection_box = st->commit(); + + Ref mat_xray = memnew(StandardMaterial3D); + mat_xray->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + mat_xray->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true); + mat_xray->set_albedo(Color(1, 0.5, 0, 0.15)); + mat_xray->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + st_xray->set_material(mat_xray); + selection_box_xray = st_xray->commit(); } Dictionary Node3DEditor::get_state() const { @@ -5514,7 +5549,7 @@ void Node3DEditor::_init_indicators() { } } - _generate_selection_box(); + _generate_selection_boxes(); } void Node3DEditor::_update_gizmos_menu() { diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index e4a384449bd..4c4faef07f1 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -498,6 +498,7 @@ public: bool last_xform_dirty; Node3D *sp; RID sbox_instance; + RID sbox_instance_xray; Node3DEditorSelectedItem() { sp = nullptr; @@ -613,6 +614,7 @@ private: float snap_rotate_value; float snap_scale_value; + Ref selection_box_xray; Ref selection_box; RID indicators; RID indicators_instance; @@ -701,7 +703,7 @@ private: HBoxContainer *hbc_menu; - void _generate_selection_box(); + void _generate_selection_boxes(); UndoRedo *undo_redo; int camera_override_viewport_id;