|
@@ -328,17 +328,13 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
|
|
|
//-------
|
|
|
// Apply camera transform
|
|
|
|
|
|
- float tolerance = 0.001;
|
|
|
+ real_t tolerance = 0.001;
|
|
|
bool equal = true;
|
|
|
- if (Math::abs(old_camera_cursor.x_rot - camera_cursor.x_rot) > tolerance || Math::abs(old_camera_cursor.y_rot - camera_cursor.y_rot) > tolerance) {
|
|
|
+ if (!Math::is_equal_approx(old_camera_cursor.x_rot, camera_cursor.x_rot, tolerance) || !Math::is_equal_approx(old_camera_cursor.y_rot, camera_cursor.y_rot, tolerance)) {
|
|
|
equal = false;
|
|
|
- }
|
|
|
-
|
|
|
- if (equal && old_camera_cursor.pos.distance_squared_to(camera_cursor.pos) > tolerance * tolerance) {
|
|
|
+ } else if (!old_camera_cursor.pos.is_equal_approx(camera_cursor.pos)) {
|
|
|
equal = false;
|
|
|
- }
|
|
|
-
|
|
|
- if (equal && Math::abs(old_camera_cursor.distance - camera_cursor.distance) > tolerance) {
|
|
|
+ } else if (!Math::is_equal_approx(old_camera_cursor.distance, camera_cursor.distance, tolerance)) {
|
|
|
equal = false;
|
|
|
}
|
|
|
|
|
@@ -356,6 +352,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
|
|
|
update_transform_gizmo_view();
|
|
|
rotation_control->update();
|
|
|
}
|
|
|
+ spatial_editor->update_grid();
|
|
|
}
|
|
|
|
|
|
Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
|
|
@@ -4929,8 +4926,10 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
|
|
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
if (grid_enable[i]) {
|
|
|
- RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled);
|
|
|
grid_visible[i] = grid_enabled;
|
|
|
+ if (grid_instance[i].is_valid()) {
|
|
|
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -5054,6 +5053,7 @@ void Node3DEditor::_init_indicators() {
|
|
|
indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
|
|
|
indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
|
|
|
indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
|
|
|
+ indicator_mat->set_transparency(StandardMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS);
|
|
|
|
|
|
Vector<Color> origin_colors;
|
|
|
Vector<Vector3> origin_points;
|
|
@@ -5082,12 +5082,27 @@ void Node3DEditor::_init_indicators() {
|
|
|
|
|
|
origin_colors.push_back(origin_color);
|
|
|
origin_colors.push_back(origin_color);
|
|
|
- origin_points.push_back(axis * 4096);
|
|
|
- origin_points.push_back(axis * -4096);
|
|
|
- }
|
|
|
-
|
|
|
- grid_enable[1] = true;
|
|
|
- grid_visible[1] = true;
|
|
|
+ origin_colors.push_back(origin_color);
|
|
|
+ origin_colors.push_back(origin_color);
|
|
|
+ origin_colors.push_back(origin_color);
|
|
|
+ origin_colors.push_back(origin_color);
|
|
|
+ // To both allow having a large origin size and avoid jitter
|
|
|
+ // at small scales, we should segment the line into pieces.
|
|
|
+ // 3 pieces seems to do the trick, and let's use powers of 2.
|
|
|
+ origin_points.push_back(axis * 1048576);
|
|
|
+ origin_points.push_back(axis * 1024);
|
|
|
+ origin_points.push_back(axis * 1024);
|
|
|
+ origin_points.push_back(axis * -1024);
|
|
|
+ origin_points.push_back(axis * -1024);
|
|
|
+ origin_points.push_back(axis * -1048576);
|
|
|
+ }
|
|
|
+
|
|
|
+ grid_enable[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane");
|
|
|
+ grid_enable[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane");
|
|
|
+ grid_enable[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane");
|
|
|
+ grid_visible[0] = grid_enable[0];
|
|
|
+ grid_visible[1] = grid_enable[1];
|
|
|
+ grid_visible[2] = grid_enable[2];
|
|
|
|
|
|
_init_grid();
|
|
|
|
|
@@ -5418,6 +5433,15 @@ void Node3DEditor::_update_gizmos_menu_theme() {
|
|
|
}
|
|
|
|
|
|
void Node3DEditor::_init_grid() {
|
|
|
+ if (!grid_enabled) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Camera3D *camera = get_editor_viewport(0)->camera;
|
|
|
+ Vector3 camera_position = camera->get_translation();
|
|
|
+ if (camera_position == Vector3()) {
|
|
|
+ return; // Camera3D is invalid, don't draw the grid.
|
|
|
+ }
|
|
|
+
|
|
|
Vector<Color> grid_colors[3];
|
|
|
Vector<Vector3> grid_points[3];
|
|
|
|
|
@@ -5426,52 +5450,111 @@ void Node3DEditor::_init_grid() {
|
|
|
int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size");
|
|
|
int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps");
|
|
|
|
|
|
- for (int i = 0; i < 3; i++) {
|
|
|
- Vector3 axis;
|
|
|
- axis[i] = 1;
|
|
|
- Vector3 axis_n1;
|
|
|
- axis_n1[(i + 1) % 3] = 1;
|
|
|
- Vector3 axis_n2;
|
|
|
- axis_n2[(i + 2) % 3] = 1;
|
|
|
-
|
|
|
- for (int j = -grid_size; j <= grid_size; j++) {
|
|
|
- Vector3 p1 = axis_n1 * j + axis_n2 * -grid_size;
|
|
|
- Vector3 p1_dest = p1 * (-axis_n2 + axis_n1);
|
|
|
- Vector3 p2 = axis_n2 * j + axis_n1 * -grid_size;
|
|
|
- Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
|
|
|
-
|
|
|
- Color line_color = secondary_grid_color;
|
|
|
- if (origin_enabled && j == 0) {
|
|
|
- // Don't draw the center lines of the grid if the origin is enabled
|
|
|
- // The origin would overlap the grid lines in this case, causing flickering
|
|
|
- continue;
|
|
|
- } else if (j % primary_grid_steps == 0) {
|
|
|
- line_color = primary_grid_color;
|
|
|
+ // Which grid planes are enabled? Which should we generate?
|
|
|
+ grid_enable[0] = grid_visible[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane");
|
|
|
+ grid_enable[1] = grid_visible[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane");
|
|
|
+ grid_enable[2] = grid_visible[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane");
|
|
|
+
|
|
|
+ // Offsets division_level for bigger or smaller grids.
|
|
|
+ // Default value is -0.2. -1.0 gives Blender-like behavior, 0.5 gives huge grids.
|
|
|
+ real_t division_level_bias = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_bias");
|
|
|
+ // Default largest grid size is 100m, 10^2 (default value is 2).
|
|
|
+ int division_level_max = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_max");
|
|
|
+ // Default smallest grid size is 1cm, 10^-2 (default value is -2).
|
|
|
+ int division_level_min = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_min");
|
|
|
+ ERR_FAIL_COND_MSG(division_level_max < division_level_min, "The 3D grid's maximum division level cannot be lower than its minimum division level.");
|
|
|
+
|
|
|
+ if (primary_grid_steps != 10) { // Log10 of 10 is 1.
|
|
|
+ // Change of base rule, divide by ln(10).
|
|
|
+ real_t div = Math::log((real_t)primary_grid_steps) / (real_t)2.302585092994045901094;
|
|
|
+ // Trucation (towards zero) is intentional.
|
|
|
+ division_level_max = (int)(division_level_max / div);
|
|
|
+ division_level_min = (int)(division_level_min / div);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int a = 0; a < 3; a++) {
|
|
|
+ if (!grid_enable[a]) {
|
|
|
+ continue; // If this grid plane is disabled, skip generation.
|
|
|
+ }
|
|
|
+ int b = (a + 1) % 3;
|
|
|
+ int c = (a + 2) % 3;
|
|
|
+
|
|
|
+ real_t division_level = Math::log(Math::abs(camera_position[c])) / Math::log((double)primary_grid_steps) + division_level_bias;
|
|
|
+ division_level = CLAMP(division_level, division_level_min, division_level_max);
|
|
|
+ real_t division_level_floored = Math::floor(division_level);
|
|
|
+ real_t division_level_decimals = division_level - division_level_floored;
|
|
|
+
|
|
|
+ real_t small_step_size = Math::pow(primary_grid_steps, division_level_floored);
|
|
|
+ real_t large_step_size = small_step_size * primary_grid_steps;
|
|
|
+ real_t center_a = large_step_size * (int)(camera_position[a] / large_step_size);
|
|
|
+ real_t center_b = large_step_size * (int)(camera_position[b] / large_step_size);
|
|
|
+
|
|
|
+ real_t bgn_a = center_a - grid_size * small_step_size;
|
|
|
+ real_t end_a = center_a + grid_size * small_step_size;
|
|
|
+ real_t bgn_b = center_b - grid_size * small_step_size;
|
|
|
+ real_t end_b = center_b + grid_size * small_step_size;
|
|
|
+
|
|
|
+ // In each iteration of this loop, draw one line in each direction (so two lines per loop, in each if statement).
|
|
|
+ for (int i = -grid_size; i <= grid_size; i++) {
|
|
|
+ Color line_color;
|
|
|
+ // Is this a primary line? Set the appropriate color.
|
|
|
+ if (i % primary_grid_steps == 0) {
|
|
|
+ line_color = primary_grid_color.lerp(secondary_grid_color, division_level_decimals);
|
|
|
+ } else {
|
|
|
+ line_color = secondary_grid_color;
|
|
|
+ line_color.a = line_color.a * (1 - division_level_decimals);
|
|
|
+ }
|
|
|
+ // Makes lines farther from the center fade out.
|
|
|
+ // Due to limitations of lines, any that come near the camera have full opacity always.
|
|
|
+ // This should eventually be replaced by some kind of "distance fade" system, outside of this function.
|
|
|
+ // But the effect is still somewhat convincing...
|
|
|
+ line_color.a *= 1 - (1 - division_level_decimals * 0.9) * (Math::abs(i / (float)grid_size));
|
|
|
+
|
|
|
+ real_t position_a = center_a + i * small_step_size;
|
|
|
+ real_t position_b = center_b + i * small_step_size;
|
|
|
+
|
|
|
+ // Don't draw lines over the origin if it's enabled.
|
|
|
+ if (!(origin_enabled && Math::is_zero_approx(position_a))) {
|
|
|
+ Vector3 line_bgn = Vector3();
|
|
|
+ Vector3 line_end = Vector3();
|
|
|
+ line_bgn[a] = position_a;
|
|
|
+ line_end[a] = position_a;
|
|
|
+ line_bgn[b] = bgn_b;
|
|
|
+ line_end[b] = end_b;
|
|
|
+ grid_points[c].push_back(line_bgn);
|
|
|
+ grid_points[c].push_back(line_end);
|
|
|
+ grid_colors[c].push_back(line_color);
|
|
|
+ grid_colors[c].push_back(line_color);
|
|
|
}
|
|
|
|
|
|
- grid_points[i].push_back(p1);
|
|
|
- grid_points[i].push_back(p1_dest);
|
|
|
- grid_colors[i].push_back(line_color);
|
|
|
- grid_colors[i].push_back(line_color);
|
|
|
-
|
|
|
- grid_points[i].push_back(p2);
|
|
|
- grid_points[i].push_back(p2_dest);
|
|
|
- grid_colors[i].push_back(line_color);
|
|
|
- grid_colors[i].push_back(line_color);
|
|
|
+ if (!(origin_enabled && Math::is_zero_approx(position_b))) {
|
|
|
+ Vector3 line_bgn = Vector3();
|
|
|
+ Vector3 line_end = Vector3();
|
|
|
+ line_bgn[b] = position_b;
|
|
|
+ line_end[b] = position_b;
|
|
|
+ line_bgn[a] = bgn_a;
|
|
|
+ line_end[a] = end_a;
|
|
|
+ grid_points[c].push_back(line_bgn);
|
|
|
+ grid_points[c].push_back(line_end);
|
|
|
+ grid_colors[c].push_back(line_color);
|
|
|
+ grid_colors[c].push_back(line_color);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- grid[i] = RenderingServer::get_singleton()->mesh_create();
|
|
|
+ // Create a mesh from the pushed vector points and colors.
|
|
|
+ grid[c] = RenderingServer::get_singleton()->mesh_create();
|
|
|
Array d;
|
|
|
d.resize(RS::ARRAY_MAX);
|
|
|
- d[RenderingServer::ARRAY_VERTEX] = grid_points[i];
|
|
|
- d[RenderingServer::ARRAY_COLOR] = grid_colors[i];
|
|
|
- RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], RenderingServer::PRIMITIVE_LINES, d);
|
|
|
- RenderingServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());
|
|
|
- grid_instance[i] = RenderingServer::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world_3d()->get_scenario());
|
|
|
+ d[RenderingServer::ARRAY_VERTEX] = grid_points[c];
|
|
|
+ d[RenderingServer::ARRAY_COLOR] = grid_colors[c];
|
|
|
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[c], RenderingServer::PRIMITIVE_LINES, d);
|
|
|
+ RenderingServer::get_singleton()->mesh_surface_set_material(grid[c], 0, indicator_mat->get_rid());
|
|
|
+ grid_instance[c] = RenderingServer::get_singleton()->instance_create2(grid[c], get_tree()->get_root()->get_world_3d()->get_scenario());
|
|
|
|
|
|
- RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_visible[i]);
|
|
|
- RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
|
|
|
- RS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
|
|
|
+ // Yes, the end of this line is supposed to be a.
|
|
|
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[c], grid_visible[a]);
|
|
|
+ RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[c], RS::SHADOW_CASTING_SETTING_OFF);
|
|
|
+ RS::get_singleton()->instance_set_layer_mask(grid_instance[c], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -5489,6 +5572,11 @@ void Node3DEditor::_finish_grid() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void Node3DEditor::update_grid() {
|
|
|
+ _finish_grid();
|
|
|
+ _init_grid();
|
|
|
+}
|
|
|
+
|
|
|
bool Node3DEditor::is_any_freelook_active() const {
|
|
|
for (unsigned int i = 0; i < VIEWPORTS_COUNT; ++i) {
|
|
|
if (viewports[i]->is_freelook_active()) {
|