diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
index b13abb04da09..2921f760dd4a 100644
--- a/doc/classes/PhysicsDirectSpaceState3D.xml
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -69,12 +69,21 @@
[code]normal[/code]: The object's surface normal at the intersection point, or [code]Vector3(0, 0, 0)[/code] if the ray starts inside the shape and [member PhysicsRayQueryParameters3D.hit_from_inside] is [code]true[/code].
[code]position[/code]: The intersection point.
[code]face_index[/code]: The face index at the intersection point.
- [b]Note:[/b] Returns a valid number only if the intersected shape is a [ConcavePolygonShape3D]. Otherwise, [code]-1[/code] is returned.
+ [b]Note:[/b] This value is only valid if the intersected shape is a [ConcavePolygonShape3D]. Otherwise, [code]-1[/code] is returned.
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
If the ray did not intersect anything, then an empty dictionary is returned instead.
+
+
+
+
+
+ Intersects a ray in a given space. Ray position and other parameters are defined through [PhysicsRayQueryParameters3D]. If an intersection occurs, this method returns true and writes the intersection information into the [PhysicsRayQueryResult3D] object passed in [code skip-lint]result[/code].
+ If the ray did not intersect anything, false is returned instead.
+
+
diff --git a/doc/classes/PhysicsRayQueryResult3D.xml b/doc/classes/PhysicsRayQueryResult3D.xml
new file mode 100644
index 000000000000..87e97518ba95
--- /dev/null
+++ b/doc/classes/PhysicsRayQueryResult3D.xml
@@ -0,0 +1,36 @@
+
+
+
+ Stores the result of a ray intersection query.
+
+
+ This object contains the intersection information produced by [method PhysicsDirectSpaceState3D.intersect_ray_no_alloc].
+ After calling [method PhysicsDirectSpaceState3D.intersect_ray_no_alloc], the fields of this object will be populated with the hit information if the ray intersects a shape. If no intersection occurred, the values remain unchanged from the previous state.
+
+
+
+
+
+ The colliding object.
+
+
+ The colliding object's ID.
+
+
+ The face index at the intersection point.
+ [b]Note:[/b] This value is only valid if the intersected shape is a [ConcavePolygonShape3D]. Otherwise, [code]-1[/code] is returned.
+
+
+ The object's surface normal at the intersection point, or [code]Vector3(0, 0, 0)[/code] if the ray starts inside the shape and [member PhysicsRayQueryParameters3D.hit_from_inside] is [code]true[/code].
+
+
+ The intersection point.
+
+
+ The intersecting object's [RID].
+
+
+ The shape index of the colliding shape.
+
+
+
diff --git a/servers/physics_3d/physics_server_3d.cpp b/servers/physics_3d/physics_server_3d.cpp
index 67dee00fe2d9..b6627014cab9 100644
--- a/servers/physics_3d/physics_server_3d.cpp
+++ b/servers/physics_3d/physics_server_3d.cpp
@@ -238,6 +238,39 @@ void PhysicsRayQueryParameters3D::_bind_methods() {
///////////////////////////////////////////////////////
+void PhysicsRayQueryResult3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &PhysicsRayQueryResult3D::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &PhysicsRayQueryResult3D::get_position);
+
+ ClassDB::bind_method(D_METHOD("set_normal", "normal"), &PhysicsRayQueryResult3D::set_normal);
+ ClassDB::bind_method(D_METHOD("get_normal"), &PhysicsRayQueryResult3D::get_normal);
+
+ ClassDB::bind_method(D_METHOD("set_rid", "rid"), &PhysicsRayQueryResult3D::set_rid);
+ ClassDB::bind_method(D_METHOD("get_rid"), &PhysicsRayQueryResult3D::get_rid);
+
+ ClassDB::bind_method(D_METHOD("set_collider_id", "collider_id"), &PhysicsRayQueryResult3D::set_collider_id);
+ ClassDB::bind_method(D_METHOD("get_collider_id"), &PhysicsRayQueryResult3D::get_collider_id);
+
+ ClassDB::bind_method(D_METHOD("set_collider", "collider"), &PhysicsRayQueryResult3D::set_collider);
+ ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsRayQueryResult3D::get_collider);
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &PhysicsRayQueryResult3D::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &PhysicsRayQueryResult3D::get_shape);
+
+ ClassDB::bind_method(D_METHOD("set_face_index", "face_index"), &PhysicsRayQueryResult3D::set_face_index);
+ ClassDB::bind_method(D_METHOD("get_face_index"), &PhysicsRayQueryResult3D::get_face_index);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "normal"), "set_normal", "get_normal");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "rid"), "set_rid", "get_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "set_collider_id", "get_collider_id");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "set_collider", "get_collider");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shape"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "face_index"), "set_face_index", "get_face_index");
+}
+
+///////////////////////////////////////////////////////
+
Ref PhysicsRayQueryParameters3D::create(Vector3 p_from, Vector3 p_to, uint32_t p_mask, const TypedArray &p_exclude) {
Ref params;
params.instantiate();
@@ -383,6 +416,13 @@ Dictionary PhysicsDirectSpaceState3D::_intersect_ray(RequiredParam rp_ray_query, RequiredParam rp_ray_result) {
+ EXTRACT_PARAM_OR_FAIL_V(p_ray_query, rp_ray_query, false);
+ EXTRACT_PARAM_OR_FAIL_V(p_ray_result, rp_ray_result, false);
+
+ return intersect_ray(p_ray_query->get_parameters(), *p_ray_result->get_result_ptr());
+}
+
TypedArray PhysicsDirectSpaceState3D::_intersect_point(RequiredParam rp_point_query, int p_max_results) {
EXTRACT_PARAM_OR_FAIL_V(p_point_query, rp_point_query, TypedArray());
@@ -488,6 +528,7 @@ PhysicsDirectSpaceState3D::PhysicsDirectSpaceState3D() {
void PhysicsDirectSpaceState3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("intersect_point", "parameters", "max_results"), &PhysicsDirectSpaceState3D::_intersect_point, DEFVAL(32));
ClassDB::bind_method(D_METHOD("intersect_ray", "parameters"), &PhysicsDirectSpaceState3D::_intersect_ray);
+ ClassDB::bind_method(D_METHOD("intersect_ray_no_alloc", "parameters", "result"), &PhysicsDirectSpaceState3D::_intersect_ray_no_alloc);
ClassDB::bind_method(D_METHOD("intersect_shape", "parameters", "max_results"), &PhysicsDirectSpaceState3D::_intersect_shape, DEFVAL(32));
ClassDB::bind_method(D_METHOD("cast_motion", "parameters"), &PhysicsDirectSpaceState3D::_cast_motion);
ClassDB::bind_method(D_METHOD("collide_shape", "parameters", "max_results"), &PhysicsDirectSpaceState3D::_collide_shape, DEFVAL(32));
diff --git a/servers/physics_3d/physics_server_3d.h b/servers/physics_3d/physics_server_3d.h
index 3738c1ee7061..ed8e21b9c08a 100644
--- a/servers/physics_3d/physics_server_3d.h
+++ b/servers/physics_3d/physics_server_3d.h
@@ -119,6 +119,7 @@ class PhysicsDirectBodyState3D : public Object {
};
class PhysicsRayQueryParameters3D;
+class PhysicsRayQueryResult3D;
class PhysicsPointQueryParameters3D;
class PhysicsShapeQueryParameters3D;
@@ -127,6 +128,7 @@ class PhysicsDirectSpaceState3D : public Object {
private:
Dictionary _intersect_ray(RequiredParam rp_ray_query);
+ bool _intersect_ray_no_alloc(RequiredParam rp_ray_query, RequiredParam rp_ray_result);
TypedArray _intersect_point(RequiredParam rp_point_query, int p_max_results = 32);
TypedArray _intersect_shape(RequiredParam rp_shape_query, int p_max_results = 32);
Vector _cast_motion(RequiredParam rp_shape_query);
@@ -869,6 +871,39 @@ class PhysicsRayQueryParameters3D : public RefCounted {
TypedArray get_exclude() const;
};
+class PhysicsRayQueryResult3D : public RefCounted {
+ GDCLASS(PhysicsRayQueryResult3D, RefCounted);
+
+ PhysicsDirectSpaceState3D::RayResult result;
+
+protected:
+ static void _bind_methods();
+
+public:
+ PhysicsDirectSpaceState3D::RayResult *get_result_ptr() { return &result; }
+
+ void set_position(const Vector3 &p_position) { result.position = p_position; }
+ const Vector3 &get_position() const { return result.position; }
+
+ void set_normal(const Vector3 &p_normal) { result.normal = p_normal; }
+ const Vector3 &get_normal() const { return result.normal; }
+
+ void set_rid(const RID &p_rid) { result.rid = p_rid; }
+ RID get_rid() const { return result.rid; }
+
+ void set_collider_id(ObjectID p_collider_id) { result.collider_id = p_collider_id; }
+ ObjectID get_collider_id() const { return result.collider_id; }
+
+ void set_collider(Object *p_collider) { result.collider = p_collider; }
+ Object *get_collider() const { return result.collider; }
+
+ void set_shape(int p_shape) { result.shape = p_shape; }
+ int get_shape() const { return result.shape; }
+
+ void set_face_index(int p_face_index) { result.face_index = p_face_index; }
+ int get_face_index() const { return result.face_index; }
+};
+
class PhysicsPointQueryParameters3D : public RefCounted {
GDCLASS(PhysicsPointQueryParameters3D, RefCounted);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index de4033378577..2c320f9b6e01 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -346,6 +346,7 @@ void register_server_types() {
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionResult, "Vector3 travel;Vector3 remainder;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;PhysicsServer3DExtensionMotionCollision collisions[32];int collision_count");
GDREGISTER_CLASS(PhysicsRayQueryParameters3D);
+ GDREGISTER_CLASS(PhysicsRayQueryResult3D);
GDREGISTER_CLASS(PhysicsPointQueryParameters3D);
GDREGISTER_CLASS(PhysicsShapeQueryParameters3D);
GDREGISTER_CLASS(PhysicsTestMotionParameters3D);