Merge pull request #28289 from aaronfranke/grid

Dynamic infinite 3D grid
This commit is contained in:
Rémi Verschelde 2020-05-26 13:39:53 +02:00 committed by GitHub
commit f8005cb699
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 169 additions and 59 deletions

View file

@ -503,17 +503,38 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/grid_map/pick_distance", 5000.0);
// 3D
_initial_set("editors/3d/primary_grid_color", Color(0.56, 0.56, 0.56));
hints["editors/3d/primary_grid_color"] = PropertyInfo(Variant::COLOR, "editors/3d/primary_grid_color", PROPERTY_HINT_COLOR_NO_ALPHA, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("editors/3d/primary_grid_color", Color(0.56, 0.56, 0.56, 0.5));
hints["editors/3d/primary_grid_color"] = PropertyInfo(Variant::COLOR, "editors/3d/primary_grid_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
_initial_set("editors/3d/secondary_grid_color", Color(0.38, 0.38, 0.38));
hints["editors/3d/secondary_grid_color"] = PropertyInfo(Variant::COLOR, "editors/3d/secondary_grid_color", PROPERTY_HINT_COLOR_NO_ALPHA, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("editors/3d/grid_size", 50);
hints["editors/3d/grid_size"] = PropertyInfo(Variant::INT, "editors/3d/grid_size", PROPERTY_HINT_RANGE, "1,500,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("editors/3d/secondary_grid_color", Color(0.38, 0.38, 0.38, 0.5));
hints["editors/3d/secondary_grid_color"] = PropertyInfo(Variant::COLOR, "editors/3d/secondary_grid_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
// If a line is a multiple of this, it uses the primary grid color.
_initial_set("editors/3d/primary_grid_steps", 10);
hints["editors/3d/primary_grid_steps"] = PropertyInfo(Variant::INT, "editors/3d/primary_grid_steps", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
hints["editors/3d/primary_grid_steps"] = PropertyInfo(Variant::INT, "editors/3d/primary_grid_steps", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT);
// At 1000, the grid mostly looks like it has no edge.
_initial_set("editors/3d/grid_size", 200);
hints["editors/3d/grid_size"] = PropertyInfo(Variant::INT, "editors/3d/grid_size", PROPERTY_HINT_RANGE, "1,2000,1", PROPERTY_USAGE_DEFAULT);
// Default largest grid size is 100m, 10^2 (primary grid lines are 1km apart when primary_grid_steps is 10).
_initial_set("editors/3d/grid_division_level_max", 2);
// Higher values produce graphical artifacts when far away unless View Z-Far
// is increased significantly more than it really should need to be.
hints["editors/3d/grid_division_level_max"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_max", PROPERTY_HINT_RANGE, "-1,3,1", PROPERTY_USAGE_DEFAULT);
// Default smallest grid size is 1cm, 10^-2.
_initial_set("editors/3d/grid_division_level_min", -2);
// Lower values produce graphical artifacts regardless of view clipping planes, so limit to -2 as a lower bound.
hints["editors/3d/grid_division_level_min"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_min", PROPERTY_HINT_RANGE, "-2,2,1", PROPERTY_USAGE_DEFAULT);
// -0.2 seems like a sensible default. -1.0 gives Blender-like behavior, 0.5 gives huge grids.
_initial_set("editors/3d/grid_division_level_bias", -0.2);
hints["editors/3d/grid_division_level_bias"] = PropertyInfo(Variant::FLOAT, "editors/3d/grid_division_level_bias", PROPERTY_HINT_RANGE, "-1.0,0.5,0.1", PROPERTY_USAGE_DEFAULT);
_initial_set("editors/3d/grid_xz_plane", true);
_initial_set("editors/3d/grid_xy_plane", false);
_initial_set("editors/3d/grid_yz_plane", false);
_initial_set("editors/3d/default_fov", 70.0);
_initial_set("editors/3d/default_z_near", 0.05);

View file

@ -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);
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[1] = true;
grid_visible[1] = true;
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;
// 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");
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);
// 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.");
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;
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()) {

View file

@ -766,6 +766,7 @@ public:
Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; }
void update_grid();
void update_transform_gizmo();
void update_all_gizmos(Node *p_node = nullptr);
void snap_selected_nodes_to_floor();

View file

@ -482,7 +482,7 @@ MainLoop *test() {
float gb = (rgbe >> 9) & 0x1ff;
float bb = (rgbe >> 18) & 0x1ff;
float eb = (rgbe >> 27);
float mb = Math::pow(2, eb - 15.0 - 9.0);
float mb = Math::pow(2.0, eb - 15.0 - 9.0);
float rd = rb * mb;
float gd = gb * mb;
float bd = bb * mb;