From 69b99ba9cb9d048b0256f7a083aff794aac38961 Mon Sep 17 00:00:00 2001 From: Marcus Brummer Date: Thu, 22 Oct 2020 20:45:39 +0200 Subject: [PATCH] Improve rotation gizmo Hide the back sides of the rotation gizmo circles and add a white outline for better visualization of the rotation "sphere". This is a 3.2 backport of @JFons work on the master branch; all credit goes to him. --- editor/plugins/spatial_editor_plugin.cpp | 169 ++++++++++++++++++----- editor/plugins/spatial_editor_plugin.h | 6 +- 2 files changed, 137 insertions(+), 38 deletions(-) diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 3ac599072e4f..8b6a23b3f9e5 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -891,20 +891,21 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig float col_d = 1e20; for (int i = 0; i < 3; i++) { - Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); Vector3 r; if (!plane.intersects_ray(ray_pos, ray, &r)) continue; float dist = r.distance_to(gt.origin); - - if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) { - - float d = ray_pos.distance_to(r); - if (d < col_d) { - col_d = d; - col_axis = i; + Vector3 r_dir = (r - gt.origin).normalized(); + + if (_get_camera_normal().dot(r_dir) <= 0.005) { + if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) { + float d = ray_pos.distance_to(r); + if (d < col_d) { + col_d = d; + col_axis = i; + } } } } @@ -3104,6 +3105,14 @@ void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer); } + + // Rotation white outline + rotate_gizmo_instance[3] = VS::get_singleton()->instance_create(); + VS::get_singleton()->instance_set_base(rotate_gizmo_instance[3], spatial_editor->get_rotate_gizmo(3)->get_rid()); + VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[3], get_tree()->get_root()->get_world()->get_scenario()); + VS::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false); + VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[3], VS::SHADOW_CASTING_SETTING_OFF); + VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[3], layer); } void SpatialEditorViewport::_finish_gizmo_instances() { @@ -3115,6 +3124,9 @@ void SpatialEditorViewport::_finish_gizmo_instances() { VS::get_singleton()->free(scale_gizmo_instance[i]); VS::get_singleton()->free(scale_plane_gizmo_instance[i]); } + + // Rotation white outline + VS::get_singleton()->free(rotate_gizmo_instance[3]); } void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) { @@ -3207,6 +3219,9 @@ void SpatialEditorViewport::update_transform_gizmo_view() { VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false); VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); } + // Rotation white outline + VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false); + return; } @@ -3244,6 +3259,9 @@ void SpatialEditorViewport::update_transform_gizmo_view() { VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform); VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE)); } + // Rotation white outline + VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform); + VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE)); } void SpatialEditorViewport::set_state(const Dictionary &p_state) { @@ -4373,7 +4391,7 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_color_hl[i] : gizmo_color[i]); move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]); - rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]); + rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? rotate_gizmo_color_hl[i] : rotate_gizmo_color[i]); scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]); scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]); } @@ -5256,39 +5274,118 @@ void SpatialEditor::_init_indicators() { Ref surftool = memnew(SurfaceTool); surftool->begin(Mesh::PRIMITIVE_TRIANGLES); - Vector3 circle[5] = { - ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE, - ivec * -0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE, - ivec * -0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE, - ivec * 0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE, - ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE, - }; - - for (int k = 0; k < 64; k++) { - - Basis ma(ivec, Math_PI * 2 * float(k) / 64); - Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64); + int n = 128; // number of circle segments + int m = 6; // number of thickness segments + + for (int j = 0; j < n; ++j) { + Basis basis = Basis(ivec, (Math_PI * 2.0f * j) / n); + Vector3 vertex = basis.xform(ivec2 * GIZMO_CIRCLE_SIZE); + for (int k = 0; k < m; ++k) { + Vector2 ofs = Vector2(Math::cos((Math_PI * 2.0 * k) / m), Math::sin((Math_PI * 2.0 * k) / m)); + Vector3 normal = ivec * ofs.x + ivec2 * ofs.y; + surftool->add_normal(basis.xform(normal)); + surftool->add_vertex(vertex); + } + } - for (int j = 0; j < 4; j++) { + for (int j = 0; j < n; ++j) { + for (int k = 0; k < m; ++k) { + int current_ring = j * m; + int next_ring = ((j + 1) % n) * m; + int current_segment = k; + int next_segment = (k + 1) % m; - Vector3 points[4] = { - ma.xform(circle[j]), - mb.xform(circle[j]), - mb.xform(circle[j + 1]), - ma.xform(circle[j + 1]), - }; - surftool->add_vertex(points[0]); - surftool->add_vertex(points[1]); - surftool->add_vertex(points[2]); + surftool->add_index(current_ring + next_segment); + surftool->add_index(current_ring + current_segment); + surftool->add_index(next_ring + current_segment); - surftool->add_vertex(points[0]); - surftool->add_vertex(points[2]); - surftool->add_vertex(points[3]); + surftool->add_index(next_ring + current_segment); + surftool->add_index(next_ring + next_segment); + surftool->add_index(current_ring + next_segment); } } - surftool->set_material(mat); - surftool->commit(rotate_gizmo[i]); + Ref rotate_shader = memnew(Shader); + rotate_shader->set_code("\n" + "shader_type spatial; \n" + "render_mode unshaded, depth_test_disable; \n" + "uniform vec4 albedo; \n" + "\n" + "mat3 orthonormalize(mat3 m) { \n" + " vec3 x = normalize(m[0]); \n" + " vec3 y = normalize(m[1] - x * dot(x, m[1])); \n" + " vec3 z = m[2] - x * dot(x, m[2]); \n" + " z = normalize(z - y * (dot(y,m[2]))); \n" + " return mat3(x,y,z); \n" + "} \n" + "\n" + "void vertex() { \n" + " mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n" + " vec3 n = mv * VERTEX; \n" + " float orientation = dot(vec3(0,0,-1),n); \n" + " if (orientation <= 0.005) { \n" + " VERTEX += NORMAL*0.02; \n" + " } \n" + "} \n" + "\n" + "void fragment() { \n" + " ALBEDO = albedo.rgb; \n" + " ALPHA = albedo.a; \n" + "}"); + + Ref rotate_mat = memnew(ShaderMaterial); + rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX); + rotate_mat->set_shader(rotate_shader); + rotate_mat->set_shader_param("albedo", col); + rotate_gizmo_color[i] = rotate_mat; + + Array arrays = surftool->commit_to_arrays(); + rotate_gizmo[i]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays); + rotate_gizmo[i]->surface_set_material(0, rotate_mat); + + Ref rotate_mat_hl = rotate_mat->duplicate(); + rotate_mat_hl->set_shader_param("albedo", Color(col.r, col.g, col.b, 1.0)); + rotate_gizmo_color_hl[i] = rotate_mat_hl; + + if (i == 2) { // Rotation white outline + Ref border_mat = rotate_mat->duplicate(); + + Ref border_shader = memnew(Shader); + border_shader->set_code("\n" + "shader_type spatial; \n" + "render_mode unshaded, depth_test_disable; \n" + "uniform vec4 albedo; \n" + "\n" + "mat3 orthonormalize(mat3 m) { \n" + " vec3 x = normalize(m[0]); \n" + " vec3 y = normalize(m[1] - x * dot(x, m[1])); \n" + " vec3 z = m[2] - x * dot(x, m[2]); \n" + " z = normalize(z - y * (dot(y,m[2]))); \n" + " return mat3(x,y,z); \n" + "} \n" + "\n" + "void vertex() { \n" + " mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n" + " mv = inverse(mv); \n" + " VERTEX += NORMAL*0.008; \n" + " vec3 camera_dir_local = mv * vec3(0,0,1); \n" + " vec3 camera_up_local = mv * vec3(0,1,0); \n" + " mat3 rotation_matrix = mat3(cross(camera_dir_local, camera_up_local), camera_up_local, camera_dir_local); \n" + " VERTEX = rotation_matrix * VERTEX; \n" + "} \n" + "\n" + "void fragment() { \n" + " ALBEDO = albedo.rgb; \n" + " ALPHA = albedo.a; \n" + "}"); + + border_mat->set_shader(border_shader); + border_mat->set_shader_param("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0)); + + rotate_gizmo[3] = Ref(memnew(ArrayMesh)); + rotate_gizmo[3]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays); + rotate_gizmo[3]->surface_set_material(0, border_mat); + } } // Scale diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index e977b8ed4c29..821892ba49a4 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -394,7 +394,7 @@ class SpatialEditorViewport : public Control { real_t zoom_indicator_delay; - RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3], scale_plane_gizmo_instance[3]; + RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3]; String last_message; String message; @@ -585,11 +585,13 @@ class SpatialEditor : public VBoxContainer { bool grid_enable[3]; //should be always visible if true bool grid_enabled; - Ref move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3], scale_plane_gizmo[3]; + Ref move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3]; Ref gizmo_color[3]; Ref plane_gizmo_color[3]; + Ref rotate_gizmo_color[3]; Ref gizmo_color_hl[3]; Ref plane_gizmo_color_hl[3]; + Ref rotate_gizmo_color_hl[3]; int over_gizmo_handle; float snap_translate_value;