Skip to content

Commit

Permalink
Improve rotation gizmo
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mbrlabs committed Oct 22, 2020
1 parent db42201 commit 69b99ba
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 38 deletions.
169 changes: 133 additions & 36 deletions editor/plugins/spatial_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}
Expand Down Expand Up @@ -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() {
Expand All @@ -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) {

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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]);
}
Expand Down Expand Up @@ -5256,39 +5274,118 @@ void SpatialEditor::_init_indicators() {
Ref<SurfaceTool> 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<Shader> 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<ShaderMaterial> 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<ShaderMaterial> 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<ShaderMaterial> border_mat = rotate_mat->duplicate();

Ref<Shader> 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<ArrayMesh>(memnew(ArrayMesh));
rotate_gizmo[3]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
rotate_gizmo[3]->surface_set_material(0, border_mat);
}
}

// Scale
Expand Down
6 changes: 4 additions & 2 deletions editor/plugins/spatial_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -585,11 +585,13 @@ class SpatialEditor : public VBoxContainer {
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], scale_gizmo[3], scale_plane_gizmo[3];
Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3];
Ref<SpatialMaterial> gizmo_color[3];
Ref<SpatialMaterial> plane_gizmo_color[3];
Ref<ShaderMaterial> rotate_gizmo_color[3];
Ref<SpatialMaterial> gizmo_color_hl[3];
Ref<SpatialMaterial> plane_gizmo_color_hl[3];
Ref<ShaderMaterial> rotate_gizmo_color_hl[3];

int over_gizmo_handle;
float snap_translate_value;
Expand Down

0 comments on commit 69b99ba

Please sign in to comment.