Repository: godotengine/godot (language: cpp)

Issue:
Selection in Game view stops working correctly when using in-game camera override feature
### Tested versions

v4.4.dev4.official [36e6207bb]

### System information

Godot v4.4.dev4 - Windows 10.0.19045 - Multi-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 980 Ti (NVIDIA; 32.0.15.6603) - Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz (8 threads)

### Issue description

Selection in new Game view (#97257) sometimes stops working correctly when using "Override the in-game camera" feature:

https://github.com/user-attachments/assets/69dc2c95-fbb2-4b41-9c43-88e40fa2042d

I had this happen with 2D selection as well, but I did something to fix it. Maybe switching back and forth between 2D and 3D selection fixed it?

### Steps to reproduce

I have not been able to reproduce this yet. I will update this issue if I'm able to find a way to reproduce it.

### Minimal reproduction project (MRP)

I was using https://github.com/allenwp/calinou-godot-demo-projects/tree/add-color-correction-demo at the time of discovering this issue, but I suspect this project has nothing to do with the issue.


Discussion / hints:

Fix patch:
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index dd0b95c65798..47abc6c1719f 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -915,6 +915,13 @@ PackedStringArray CSGShape3D::get_configuration_warnings() const {
 	return warnings;
 }
 
+Ref<TriangleMesh> CSGShape3D::generate_triangle_mesh() const {
+	if (root_mesh.is_valid()) {
+		return root_mesh->generate_triangle_mesh();
+	}
+	return Ref<TriangleMesh>();
+}
+
 void CSGShape3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape3D::_update_shape);
 	ClassDB::bind_method(D_METHOD("is_root_shape"), &CSGShape3D::is_root_shape);
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index e71baae85633..d748f0bb5d9d 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -169,6 +169,8 @@ class CSGShape3D : public GeometryInstance3D {
 	Ref<ArrayMesh> bake_static_mesh();
 	Ref<ConcavePolygonShape3D> bake_collision_shape();
 
+	virtual Ref<TriangleMesh> generate_triangle_mesh() const override;
+
 	CSGShape3D();
 	~CSGShape3D();
 };
diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h
index 332eaac18dd6..01281f29764a 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -253,7 +253,7 @@ class Label3D : public GeometryInstance3D {
 	StandardMaterial3D::TextureFilter get_texture_filter() const;
 
 	virtual AABB get_aabb() const override;
-	Ref<TriangleMesh> generate_triangle_mesh() const;
+	virtual Ref<TriangleMesh> generate_triangle_mesh() const override;
 
 	Label3D();
 	~Label3D();
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index e6a1d3914135..812655850585 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -835,6 +835,13 @@ Ref<ArrayMesh> MeshInstance3D::bake_mesh_from_current_skeleton_pose(Ref<ArrayMes
 	return bake_mesh;
 }
 
+Ref<TriangleMesh> MeshInstance3D::generate_triangle_mesh() const {
+	if (mesh.is_valid()) {
+		return mesh->generate_triangle_mesh();
+	}
+	return Ref<TriangleMesh>();
+}
+
 void MeshInstance3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshInstance3D::set_mesh);
 	ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance3D::get_mesh);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index 0eff12762dcb..aa7d256a3511 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -104,6 +104,8 @@ class MeshInstance3D : public GeometryInstance3D {
 	Ref<ArrayMesh> bake_mesh_from_current_blend_shape_mix(Ref<ArrayMesh> p_existing = Ref<ArrayMesh>());
 	Ref<ArrayMesh> bake_mesh_from_current_skeleton_pose(Ref<ArrayMesh> p_existing = Ref<ArrayMesh>());
 
+	virtual Ref<TriangleMesh> generate_triangle_mesh() const override;
+
 	MeshInstance3D();
 	~MeshInstance3D();
 };
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index bdc771444cc5..87327caca277 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -172,7 +172,7 @@ class SpriteBase3D : public GeometryInstance3D {
 
 	virtual AABB get_aabb() const override;
 
-	Ref<TriangleMesh> generate_triangle_mesh() const;
+	virtual Ref<TriangleMesh> generate_triangle_mesh() const override;
 
 	SpriteBase3D();
 	~SpriteBase3D();
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 2c7a004dd068..257cc2877258 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -530,6 +530,10 @@ bool GeometryInstance3D::is_ignoring_occlusion_culling() {
 	return ignore_occlusion_culling;
 }
 
+Ref<TriangleMesh> GeometryInstance3D::generate_triangle_mesh() const {
+	return Ref<TriangleMesh>();
+}
+
 PackedStringArray GeometryInstance3D::get_configuration_warnings() const {
 	PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
 
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 073fa74573d6..7091a8f14dfc 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -202,6 +202,8 @@ class GeometryInstance3D : public VisualInstance3D {
 	void set_ignore_occlusion_culling(bool p_enabled);
 	bool is_ignoring_occlusion_culling();
 
+	virtual Ref<TriangleMesh> generate_triangle_mesh() const;
+
 	PackedStringArray get_configuration_warnings() const override;
 	GeometryInstance3D();
 	virtual ~GeometryInstance3D();
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 1bac94b4fa17..56326597e31f 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -39,11 +39,9 @@
 #include "scene/2d/physics/collision_polygon_2d.h"
 #include "scene/2d/physics/collision_shape_2d.h"
 #ifndef _3D_DISABLED
-#include "scene/3d/label_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
 #include "scene/3d/physics/collision_object_3d.h"
 #include "scene/3d/physics/collision_shape_3d.h"
-#include "scene/3d/sprite_3d.h"
+#include "scene/3d/visual_instance_3d.h"
 #include "scene/resources/surface_tool.h"
 #endif // _3D_DISABLED
 #include "scene/gui/popup_menu.h"
@@ -1896,7 +1894,7 @@ void RuntimeNodeSelect::_find_3d_items_at_pos(const Point2 &p_pos, Vector<Select
 		if (ss->intersect_ray(ray_params, result)) {
 			SelectResult res;
 			res.item = Object::cast_to<Node>(result.collider);
-			res.order = -pos.distance_to(Object::cast_to<Node3D>(res.item)->get_global_transform().xform(result.position));
+			res.order = -pos.distance_to(result.position);
 
 			// Fetch collision shapes.
 			CollisionObject3D *collision = Object::cast_to<CollisionObject3D>(result.collider);
@@ -1923,40 +1921,23 @@ void RuntimeNodeSelect::_find_3d_items_at_pos(const Point2 &p_pos, Vector<Select
 	Vector<ObjectID> items = RS::get_singleton()->instances_cull_ray(pos, to, root->get_world_3d()->get_scenario());
 	for (int i = 0; i < items.size(); i++) {
 		Object *obj = ObjectDB::get_instance(items[i]);
-		GeometryInstance3D *geo_instance = nullptr;
-		Ref<TriangleMesh> mesh_collision;
-
-		MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(obj);
-		if (mesh_instance) {
-			if (mesh_instance->get_mesh().is_valid()) {
-				geo_instance = mesh_instance;
-				mesh_collision = mesh_instance->get_mesh()->generate_triangle_mesh();
-			}
-		} else {
-			Label3D *label = Object::cast_to<Label3D>(obj);
-			if (label) {
-				geo_instance = label;
-				mesh_collision = label->generate_triangle_mesh();
-			} else {
-				Sprite3D *sprite = Object::cast_to<Sprite3D>(obj);
-				if (sprite) {
-					geo_instance = sprite;
-					mesh_collision = sprite->generate_triangle_mesh();
-				}
-			}
-		}
 
-		if (mesh_collision.is_valid()) {
-			Transform3D gt = geo_instance->get_global_transform();
-			Transform3D ai = gt.affine_inverse();
-			Vector3 point, normal;
-			if (mesh_collision->intersect_ray(ai.xform(pos), ai.basis.xform(ray).normalized(), point, normal)) {
-				SelectResult res;
-				res.item = Object::cast_to<Node>(obj);
-				res.order = -pos.distance_to(gt.xform(point));
-				r_items.push_back(res);
-
-				continue;
+		GeometryInstance3D *geo_instance = Object::cast_to<GeometryInstance3D>(obj);
+		if (geo_instance) {
+			Ref<TriangleMesh> mesh_collision = geo_instance->generate_triangle_mesh();
+
+			if (mesh_collision.is_valid()) {
+				Transform3D gt = geo_instance->get_global_transform();
+				Transform3D ai = gt.affine_inverse();
+				Vector3 point, normal;
+				if (mesh_collision->intersect_ray(ai.xform(pos), ai.basis.xform(ray).normalized(), point, normal)) {
+					SelectResult res;
+					res.item = Object::cast_to<Node>(obj);
+					res.order = -pos.distance_to(gt.xform(point));
+					r_items.push_back(res);
+
+					continue;
+				}
 			}
 		}
 


Test patch: