summaryrefslogtreecommitdiffstats
path: root/editor/plugins/node_3d_editor_plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins/node_3d_editor_plugin.cpp')
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp74
1 files changed, 58 insertions, 16 deletions
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index dc86acd884..0cf194b7fe 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -4255,8 +4255,31 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const
ray_params.to = world_pos + world_ray * camera->get_far();
PhysicsDirectSpaceState3D::RayResult result;
- if (ss->intersect_ray(ray_params, result)) {
- return result.position;
+ if (ss->intersect_ray(ray_params, result) && preview_node->get_child_count() > 0) {
+ // Calculate an offset for the `preview_node` such that the its bounding box is on top of and touching the contact surface's plane.
+
+ // Use the Gram-Schmidt process to get an orthonormal Basis aligned with the surface normal.
+ const Vector3 bb_basis_x = result.normal;
+ Vector3 bb_basis_y = Vector3(0, 1, 0);
+ bb_basis_y = bb_basis_y - bb_basis_y.project(bb_basis_x);
+ if (bb_basis_y.is_zero_approx()) {
+ bb_basis_y = Vector3(0, 0, 1);
+ bb_basis_y = bb_basis_y - bb_basis_y.project(bb_basis_x);
+ }
+ bb_basis_y = bb_basis_y.normalized();
+ const Vector3 bb_basis_z = bb_basis_x.cross(bb_basis_y);
+ const Basis bb_basis = Basis(bb_basis_x, bb_basis_y, bb_basis_z);
+
+ // This normal-aligned Basis allows us to create an AABB that can fit on the surface plane as snugly as possible.
+ const Transform3D bb_transform = Transform3D(bb_basis, preview_node->get_transform().origin);
+ const AABB preview_node_bb = _calculate_spatial_bounds(preview_node, true, &bb_transform);
+ // The x-axis's alignment with the surface normal also makes it trivial to get the distance from `preview_node`'s origin at (0, 0, 0) to the correct AABB face.
+ const float offset_distance = -preview_node_bb.position.x;
+
+ // `result_offset` is in global space.
+ const Vector3 result_offset = result.position + result.normal * offset_distance;
+
+ return result_offset;
}
const bool is_orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL;
@@ -4284,18 +4307,21 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const
return world_pos + world_ray * FALLBACK_DISTANCE;
}
-AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, const Node3D *p_top_level_parent) {
+AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_omit_top_level, const Transform3D *p_bounds_orientation) {
AABB bounds;
- if (!p_top_level_parent) {
- p_top_level_parent = p_parent;
+ Transform3D bounds_orientation;
+ if (p_bounds_orientation) {
+ bounds_orientation = *p_bounds_orientation;
+ } else {
+ bounds_orientation = p_parent->get_global_transform();
}
if (!p_parent) {
return AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
}
- Transform3D xform_to_top_level_parent_space = p_top_level_parent->get_global_transform().affine_inverse() * p_parent->get_global_transform();
+ const Transform3D xform_to_top_level_parent_space = bounds_orientation.affine_inverse() * p_parent->get_global_transform();
const VisualInstance3D *visual_instance = Object::cast_to<VisualInstance3D>(p_parent);
if (visual_instance) {
@@ -4306,9 +4332,9 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, con
bounds = xform_to_top_level_parent_space.xform(bounds);
for (int i = 0; i < p_parent->get_child_count(); i++) {
- Node3D *child = Object::cast_to<Node3D>(p_parent->get_child(i));
- if (child) {
- AABB child_bounds = _calculate_spatial_bounds(child, p_top_level_parent);
+ const Node3D *child = Object::cast_to<Node3D>(p_parent->get_child(i));
+ if (child && !(p_omit_top_level && child->is_set_as_top_level())) {
+ const AABB child_bounds = _calculate_spatial_bounds(child, p_omit_top_level, &bounds_orientation);
bounds.merge_with(child_bounds);
}
}
@@ -4359,6 +4385,10 @@ void Node3DEditorViewport::_create_preview_node(const Vector<String> &files) con
if (instance) {
instance = _sanitize_preview_node(instance);
preview_node->add_child(instance);
+ Node3D *node_3d = Object::cast_to<Node3D>(instance);
+ if (node_3d) {
+ node_3d->set_as_top_level(false);
+ }
}
add_preview = true;
}
@@ -4579,8 +4609,12 @@ bool Node3DEditorViewport::_create_instance(Node *p_parent, const String &p_path
}
Transform3D new_tf = node3d->get_transform();
- new_tf.origin = parent_tf.affine_inverse().xform(preview_node_pos + node3d->get_position());
- new_tf.basis = parent_tf.affine_inverse().basis * new_tf.basis;
+ if (node3d->is_set_as_top_level()) {
+ new_tf.origin += preview_node_pos;
+ } else {
+ new_tf.origin = parent_tf.affine_inverse().xform(preview_node_pos + node3d->get_position());
+ new_tf.basis = parent_tf.affine_inverse().basis * new_tf.basis;
+ }
undo_redo->add_do_method(instantiated_scene, "set_transform", new_tf);
}
@@ -9003,8 +9037,7 @@ Node3DEditor::Node3DEditor() {
current_hover_gizmo_handle = -1;
current_hover_gizmo_handle_secondary = false;
{
- //sun popup
-
+ // Sun/preview environment popup.
sun_environ_popup = memnew(PopupPanel);
add_child(sun_environ_popup);
@@ -9018,7 +9051,7 @@ Node3DEditor::Node3DEditor() {
sun_vb->hide();
sun_title = memnew(Label);
- sun_title->set_theme_type_variation("HeaderSmall");
+ sun_title->set_theme_type_variation("HeaderMedium");
sun_vb->add_child(sun_title);
sun_title->set_text(TTR("Preview Sun"));
sun_title->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
@@ -9056,11 +9089,14 @@ void fragment() {
sun_direction->set_material(sun_direction_material);
HBoxContainer *sun_angle_hbox = memnew(HBoxContainer);
+ sun_angle_hbox->set_h_size_flags(SIZE_EXPAND_FILL);
VBoxContainer *sun_angle_altitude_vbox = memnew(VBoxContainer);
+ sun_angle_altitude_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
Label *sun_angle_altitude_label = memnew(Label);
sun_angle_altitude_label->set_text(TTR("Angular Altitude"));
sun_angle_altitude_vbox->add_child(sun_angle_altitude_label);
sun_angle_altitude = memnew(EditorSpinSlider);
+ sun_angle_altitude->set_suffix(U"\u00B0");
sun_angle_altitude->set_max(90);
sun_angle_altitude->set_min(-90);
sun_angle_altitude->set_step(0.1);
@@ -9068,11 +9104,13 @@ void fragment() {
sun_angle_altitude_vbox->add_child(sun_angle_altitude);
sun_angle_hbox->add_child(sun_angle_altitude_vbox);
VBoxContainer *sun_angle_azimuth_vbox = memnew(VBoxContainer);
+ sun_angle_azimuth_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
sun_angle_azimuth_vbox->set_custom_minimum_size(Vector2(100, 0));
Label *sun_angle_azimuth_label = memnew(Label);
sun_angle_azimuth_label->set_text(TTR("Azimuth"));
sun_angle_azimuth_vbox->add_child(sun_angle_azimuth_label);
sun_angle_azimuth = memnew(EditorSpinSlider);
+ sun_angle_azimuth->set_suffix(U"\u00B0");
sun_angle_azimuth->set_max(180);
sun_angle_azimuth->set_min(-180);
sun_angle_azimuth->set_step(0.1);
@@ -9117,7 +9155,7 @@ void fragment() {
sun_state->set_h_size_flags(SIZE_EXPAND_FILL);
VSeparator *sc = memnew(VSeparator);
- sc->set_custom_minimum_size(Size2(50 * EDSCALE, 0));
+ sc->set_custom_minimum_size(Size2(10 * EDSCALE, 0));
sc->set_v_size_flags(SIZE_EXPAND_FILL);
sun_environ_hb->add_child(sc);
@@ -9127,7 +9165,7 @@ void fragment() {
environ_vb->hide();
environ_title = memnew(Label);
- environ_title->set_theme_type_variation("HeaderSmall");
+ environ_title->set_theme_type_variation("HeaderMedium");
environ_vb->add_child(environ_title);
environ_title->set_text(TTR("Preview Environment"));
@@ -9154,21 +9192,25 @@ void fragment() {
environ_ao_button = memnew(Button);
environ_ao_button->set_text(TTR("AO"));
+ environ_ao_button->set_h_size_flags(SIZE_EXPAND_FILL);
environ_ao_button->set_toggle_mode(true);
environ_ao_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED);
fx_vb->add_child(environ_ao_button);
environ_glow_button = memnew(Button);
environ_glow_button->set_text(TTR("Glow"));
+ environ_glow_button->set_h_size_flags(SIZE_EXPAND_FILL);
environ_glow_button->set_toggle_mode(true);
environ_glow_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED);
fx_vb->add_child(environ_glow_button);
environ_tonemap_button = memnew(Button);
environ_tonemap_button->set_text(TTR("Tonemap"));
+ environ_tonemap_button->set_h_size_flags(SIZE_EXPAND_FILL);
environ_tonemap_button->set_toggle_mode(true);
environ_tonemap_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED);
fx_vb->add_child(environ_tonemap_button);
environ_gi_button = memnew(Button);
environ_gi_button->set_text(TTR("GI"));
+ environ_gi_button->set_h_size_flags(SIZE_EXPAND_FILL);
environ_gi_button->set_toggle_mode(true);
environ_gi_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_preview_settings_changed), CONNECT_DEFERRED);
fx_vb->add_child(environ_gi_button);