Skip to content

Commit 4325e1f

Browse files
committed
Ignore backfaces during Node3D selection
1 parent 89f32c6 commit 4325e1f

File tree

8 files changed

+28
-15
lines changed

8 files changed

+28
-15
lines changed

core/math/triangle_mesh.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en
290290
return inters;
291291
}
292292

293-
bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index, int32_t *r_face_index) const {
293+
bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index, int32_t *r_face_index, bool p_ignore_backfaces) const {
294294
if (!valid) {
295295
return false;
296296
}
@@ -338,18 +338,23 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
338338
Vector3 res;
339339

340340
if (f3.intersects_ray(p_begin, p_dir, &res)) {
341-
real_t nd = n.dot(res);
342-
if (nd < d) {
343-
d = nd;
344-
r_point = res;
345-
r_normal = f3.get_plane().get_normal();
346-
if (r_surf_index) {
347-
*r_surf_index = s.surface_index;
341+
Vector3 face_normal = f3.get_plane().get_normal();
342+
if (p_ignore_backfaces && p_dir.dot(face_normal) >= 0) {
343+
// Skip this triangle.
344+
} else {
345+
real_t nd = n.dot(res);
346+
if (nd < d) {
347+
d = nd;
348+
r_point = res;
349+
r_normal = face_normal;
350+
if (r_surf_index) {
351+
*r_surf_index = s.surface_index;
352+
}
353+
if (r_face_index) {
354+
*r_face_index = b.face_index;
355+
}
356+
inters = true;
348357
}
349-
if (r_face_index) {
350-
*r_face_index = b.face_index;
351-
}
352-
inters = true;
353358
}
354359
}
355360

core/math/triangle_mesh.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class TriangleMesh : public RefCounted {
8585
public:
8686
bool is_valid() const;
8787
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr) const;
88-
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr) const;
88+
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr, bool p_ignore_backfaces = false) const;
8989
bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const;
9090
Vector<Face3> get_faces() const;
9191

doc/classes/EditorSettings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,9 @@
357357
<member name="editors/3d/grid_yz_plane" type="bool" setter="" getter="">
358358
If [code]true[/code], renders the grid on the YZ plane in perspective view. This can be useful for 3D side-scrolling games.
359359
</member>
360+
<member name="editors/3d/ignore_backfaces_on_selection" type="bool" setter="" getter="">
361+
If [code]true[/code], backfaces are ignored for 3D selection. This is useful for level editing, to select nodes inside enclosed geometry without accidentally selecting the ceiling or walls.
362+
</member>
360363
<member name="editors/3d/manipulator_gizmo_opacity" type="float" setter="" getter="">
361364
Opacity of the default gizmo for moving, rotating, and scaling 3D nodes.
362365
</member>

editor/run/game_view_plugin.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ void GameViewDebugger::_session_started(Ref<EditorDebuggerSession> p_session) {
7878
settings["editors/3d/freelook/freelook_sensitivity"] = EDITOR_GET("editors/3d/freelook/freelook_sensitivity");
7979
settings["editors/3d/navigation_feel/orbit_sensitivity"] = EDITOR_GET("editors/3d/navigation_feel/orbit_sensitivity");
8080
settings["editors/3d/navigation_feel/translation_sensitivity"] = EDITOR_GET("editors/3d/navigation_feel/translation_sensitivity");
81+
settings["editors/3d/ignore_backfaces_on_selection"] = EDITOR_GET("editors/3d/ignore_backfaces_on_selection");
8182
settings["editors/3d/selection_box_color"] = EDITOR_GET("editors/3d/selection_box_color");
8283
settings["editors/3d/freelook/freelook_base_speed"] = EDITOR_GET("editors/3d/freelook/freelook_base_speed");
8384

editor/scene/3d/node_3d_editor_gizmos.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,9 +762,10 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
762762
Vector3 ray_dir = ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized();
763763
Vector3 rpos, rnorm;
764764

765+
bool ignore_backfaces = EDITOR_GET("editors/3d/ignore_backfaces_on_selection");
765766
for (Ref<TriangleMesh> collision_mesh : collision_meshes) {
766767
if (collision_mesh.is_valid()) {
767-
if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm)) {
768+
if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm, nullptr, nullptr, ignore_backfaces)) {
768769
r_pos = gt.xform(rpos);
769770
r_normal = gt.basis.xform(rnorm).normalized();
770771
return true;

editor/settings/editor_settings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
858858
EDITOR_SETTING_BASIC(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/primary_grid_color", Color(0.56, 0.56, 0.56, 0.5), "")
859859
EDITOR_SETTING_BASIC(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/secondary_grid_color", Color(0.38, 0.38, 0.38, 0.5), "")
860860

861+
EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "editors/3d/ignore_backfaces_on_selection", true, "", PROPERTY_USAGE_DEFAULT)
861862
// Use a similar color to the 2D editor selection.
862863
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/selection_box_color", Color(1.0, 0.5, 0), "", PROPERTY_USAGE_DEFAULT)
863864
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/active_selection_box_color", Color(1.5, 0.75, 0, 1.0), "", PROPERTY_USAGE_DEFAULT)

scene/debugger/scene_debugger.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,7 @@ void RuntimeNodeSelect::_setup(const Dictionary &p_settings) {
15371537
/// 3D Selection Box Generation
15381538
// Copied from the Node3DEditor implementation.
15391539

1540+
ignore_backfaces_on_selection = p_settings.get("editors/3d/ignore_backfaces_on_selection", true);
15401541
sbox_3d_color = p_settings.get("editors/3d/selection_box_color", Color());
15411542

15421543
// Use two AABBs to create the illusion of a slightly thicker line.
@@ -2562,7 +2563,7 @@ void RuntimeNodeSelect::_find_3d_items_at_pos(const Point2 &p_pos, Vector<Select
25622563
Transform3D gt = geo_instance->get_global_transform();
25632564
Transform3D ai = gt.affine_inverse();
25642565
Vector3 point, normal;
2565-
if (mesh_collision->intersect_ray(ai.xform(pos), ai.basis.xform(ray).normalized(), point, normal)) {
2566+
if (mesh_collision->intersect_ray(ai.xform(pos), ai.basis.xform(ray).normalized(), point, normal, nullptr, nullptr, ignore_backfaces_on_selection)) {
25662567
SelectResult res;
25672568
res.item = Object::cast_to<Node>(obj);
25682569
res.order = -pos.distance_to(gt.xform(point));

scene/debugger/scene_debugger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ class RuntimeNodeSelect : public Object {
361361
};
362362
HashMap<ObjectID, Ref<SelectionBox3D>> selected_3d_nodes;
363363

364+
bool ignore_backfaces_on_selection = true;
364365
Color sbox_3d_color;
365366
Ref<ArrayMesh> sbox_3d_mesh;
366367
Ref<ArrayMesh> sbox_3d_mesh_xray;

0 commit comments

Comments
 (0)