Browse Source

Add raycast options to hit when starting inside / hit back faces

Makes the results consistent for all shape types with options to set
the desired behavior.
PouleyKetchoupp 3 years ago
parent
commit
c3ae7ddedd

+ 1 - 1
doc/classes/PhysicsDirectSpaceState2D.xml

@@ -64,7 +64,7 @@
 				Intersects a ray in a given space. Ray position and other parameters are defined through [PhysicsRayQueryParameters2D]. The returned object is a dictionary with the following fields:
 				Intersects a ray in a given space. Ray position and other parameters are defined through [PhysicsRayQueryParameters2D]. The returned object is a dictionary with the following fields:
 				[code]collider[/code]: The colliding object.
 				[code]collider[/code]: The colliding object.
 				[code]collider_id[/code]: The colliding object's ID.
 				[code]collider_id[/code]: The colliding object's ID.
-				[code]normal[/code]: The object's surface normal at the intersection point.
+				[code]normal[/code]: The object's surface normal at the intersection point, or [code]Vector2(0, 0)[/code] if the ray starts inside the shape and [member PhysicsRayQueryParameters2D.hit_from_inside] is [code]true[/code].
 				[code]position[/code]: The intersection point.
 				[code]position[/code]: The intersection point.
 				[code]rid[/code]: The intersecting object's [RID].
 				[code]rid[/code]: The intersecting object's [RID].
 				[code]shape[/code]: The shape index of the colliding shape.
 				[code]shape[/code]: The shape index of the colliding shape.

+ 1 - 1
doc/classes/PhysicsDirectSpaceState3D.xml

@@ -65,7 +65,7 @@
 				Intersects a ray in a given space. Ray position and other parameters are defined through [PhysicsRayQueryParameters3D]. The returned object is a dictionary with the following fields:
 				Intersects a ray in a given space. Ray position and other parameters are defined through [PhysicsRayQueryParameters3D]. The returned object is a dictionary with the following fields:
 				[code]collider[/code]: The colliding object.
 				[code]collider[/code]: The colliding object.
 				[code]collider_id[/code]: The colliding object's ID.
 				[code]collider_id[/code]: The colliding object's ID.
-				[code]normal[/code]: The object's surface normal at the intersection point.
+				[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]position[/code]: The intersection point.
 				[code]rid[/code]: The intersecting object's [RID].
 				[code]rid[/code]: The intersecting object's [RID].
 				[code]shape[/code]: The shape index of the colliding shape.
 				[code]shape[/code]: The shape index of the colliding shape.

+ 3 - 0
doc/classes/PhysicsRayQueryParameters2D.xml

@@ -24,6 +24,9 @@
 		<member name="from" type="Vector2" setter="set_from" getter="get_from" default="Vector2(0, 0)">
 		<member name="from" type="Vector2" setter="set_from" getter="get_from" default="Vector2(0, 0)">
 			The starting point of the ray being queried for, in global coordinates.
 			The starting point of the ray being queried for, in global coordinates.
 		</member>
 		</member>
+		<member name="hit_from_inside" type="bool" setter="set_hit_from_inside" getter="is_hit_from_inside_enabled" default="false">
+			If [code]true[/code], the query will detect a hit when starting inside shapes. In this case the collision normal will be [code]Vector2(0, 0)[/code]. Does not affect concave polygon shapes.
+		</member>
 		<member name="to" type="Vector2" setter="set_to" getter="get_to" default="Vector2(0, 0)">
 		<member name="to" type="Vector2" setter="set_to" getter="get_to" default="Vector2(0, 0)">
 			The ending point of the ray being queried for, in global coordinates.
 			The ending point of the ray being queried for, in global coordinates.
 		</member>
 		</member>

+ 6 - 0
doc/classes/PhysicsRayQueryParameters3D.xml

@@ -24,6 +24,12 @@
 		<member name="from" type="Vector3" setter="set_from" getter="get_from" default="Vector3(0, 0, 0)">
 		<member name="from" type="Vector3" setter="set_from" getter="get_from" default="Vector3(0, 0, 0)">
 			The starting point of the ray being queried for, in global coordinates.
 			The starting point of the ray being queried for, in global coordinates.
 		</member>
 		</member>
+		<member name="hit_back_faces" type="bool" setter="set_hit_back_faces" getter="is_hit_back_faces_enabled" default="true">
+			If [code]true[/code], the query will hit back faces with concave polygon shapes with back face enabled or heightmap shapes.
+		</member>
+		<member name="hit_from_inside" type="bool" setter="set_hit_from_inside" getter="is_hit_from_inside_enabled" default="false">
+			If [code]true[/code], the query will detect a hit when starting inside shapes. In this case the collision normal will be [code]Vector3(0, 0, 0)[/code]. Does not affect concave polygon shapes or heightmap shapes.
+		</member>
 		<member name="to" type="Vector3" setter="set_to" getter="get_to" default="Vector3(0, 0, 0)">
 		<member name="to" type="Vector3" setter="set_to" getter="get_to" default="Vector3(0, 0, 0)">
 			The ending point of the ray being queried for, in global coordinates.
 			The ending point of the ray being queried for, in global coordinates.
 		</member>
 		</member>

+ 4 - 1
doc/classes/RayCast2D.xml

@@ -63,7 +63,7 @@
 		<method name="get_collision_normal" qualifiers="const">
 		<method name="get_collision_normal" qualifiers="const">
 			<return type="Vector2" />
 			<return type="Vector2" />
 			<description>
 			<description>
-				Returns the normal of the intersecting object's shape at the collision point.
+				Returns the normal of the intersecting object's shape at the collision point, or [code]Vector2(0, 0)[/code] if the ray starts inside the shape and [member hit_from_inside] is [code]true[/code].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_collision_point" qualifiers="const">
 		<method name="get_collision_point" qualifiers="const">
@@ -118,6 +118,9 @@
 		<member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true">
 		<member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true">
 			If [code]true[/code], the parent node will be excluded from collision detection.
 			If [code]true[/code], the parent node will be excluded from collision detection.
 		</member>
 		</member>
+		<member name="hit_from_inside" type="bool" setter="set_hit_from_inside" getter="is_hit_from_inside_enabled" default="false">
+			If [code]true[/code], the ray will detect a hit when starting inside shapes. In this case the collision normal will be [code]Vector2(0, 0)[/code]. Does not affect concave polygon shapes.
+		</member>
 		<member name="target_position" type="Vector2" setter="set_target_position" getter="get_target_position" default="Vector2(0, 50)">
 		<member name="target_position" type="Vector2" setter="set_target_position" getter="get_target_position" default="Vector2(0, 50)">
 			The ray's destination point, relative to the RayCast's [code]position[/code].
 			The ray's destination point, relative to the RayCast's [code]position[/code].
 		</member>
 		</member>

+ 4 - 1
doc/classes/RayCast3D.xml

@@ -65,7 +65,7 @@
 		<method name="get_collision_normal" qualifiers="const">
 		<method name="get_collision_normal" qualifiers="const">
 			<return type="Vector3" />
 			<return type="Vector3" />
 			<description>
 			<description>
-				Returns the normal of the intersecting object's shape at the collision point.
+				Returns the normal of the intersecting object's shape at the collision point, or [code]Vector3(0, 0, 0)[/code] if the ray starts inside the shape and [member hit_from_inside] is [code]true[/code].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_collision_point" qualifiers="const">
 		<method name="get_collision_point" qualifiers="const">
@@ -127,6 +127,9 @@
 		<member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true">
 		<member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true">
 			If [code]true[/code], collisions will be ignored for this RayCast3D's immediate parent.
 			If [code]true[/code], collisions will be ignored for this RayCast3D's immediate parent.
 		</member>
 		</member>
+		<member name="hit_from_inside" type="bool" setter="set_hit_from_inside" getter="is_hit_from_inside_enabled" default="false">
+			If [code]true[/code], the ray will detect a hit when starting inside shapes. In this case the collision normal will be [code]Vector3(0, 0, 0)[/code]. Does not affect shapes with no volume like concave polygon or heightmap.
+		</member>
 		<member name="target_position" type="Vector3" setter="set_target_position" getter="get_target_position" default="Vector3(0, -1, 0)">
 		<member name="target_position" type="Vector3" setter="set_target_position" getter="get_target_position" default="Vector3(0, -1, 0)">
 			The ray's destination point, relative to the RayCast's [code]position[/code].
 			The ray's destination point, relative to the RayCast's [code]position[/code].
 		</member>
 		</member>

+ 17 - 4
scene/2d/ray_cast_2d.cpp

@@ -200,6 +200,7 @@ void RayCast2D::_update_raycast_state() {
 	ray_params.collision_mask = collision_mask;
 	ray_params.collision_mask = collision_mask;
 	ray_params.collide_with_bodies = collide_with_bodies;
 	ray_params.collide_with_bodies = collide_with_bodies;
 	ray_params.collide_with_areas = collide_with_areas;
 	ray_params.collide_with_areas = collide_with_areas;
+	ray_params.hit_from_inside = hit_from_inside;
 
 
 	if (dss->intersect_ray(ray_params, rr)) {
 	if (dss->intersect_ray(ray_params, rr)) {
 		collided = true;
 		collided = true;
@@ -290,22 +291,30 @@ void RayCast2D::clear_exceptions() {
 	exclude.clear();
 	exclude.clear();
 }
 }
 
 
-void RayCast2D::set_collide_with_areas(bool p_clip) {
-	collide_with_areas = p_clip;
+void RayCast2D::set_collide_with_areas(bool p_enabled) {
+	collide_with_areas = p_enabled;
 }
 }
 
 
 bool RayCast2D::is_collide_with_areas_enabled() const {
 bool RayCast2D::is_collide_with_areas_enabled() const {
 	return collide_with_areas;
 	return collide_with_areas;
 }
 }
 
 
-void RayCast2D::set_collide_with_bodies(bool p_clip) {
-	collide_with_bodies = p_clip;
+void RayCast2D::set_collide_with_bodies(bool p_enabled) {
+	collide_with_bodies = p_enabled;
 }
 }
 
 
 bool RayCast2D::is_collide_with_bodies_enabled() const {
 bool RayCast2D::is_collide_with_bodies_enabled() const {
 	return collide_with_bodies;
 	return collide_with_bodies;
 }
 }
 
 
+void RayCast2D::set_hit_from_inside(bool p_enabled) {
+	hit_from_inside = p_enabled;
+}
+
+bool RayCast2D::is_hit_from_inside_enabled() const {
+	return hit_from_inside;
+}
+
 void RayCast2D::_bind_methods() {
 void RayCast2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast2D::set_enabled);
 	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast2D::set_enabled);
 	ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast2D::is_enabled);
 	ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast2D::is_enabled);
@@ -344,10 +353,14 @@ void RayCast2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast2D::set_collide_with_bodies);
 	ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast2D::set_collide_with_bodies);
 	ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast2D::is_collide_with_bodies_enabled);
 	ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast2D::is_collide_with_bodies_enabled);
 
 
+	ClassDB::bind_method(D_METHOD("set_hit_from_inside", "enable"), &RayCast2D::set_hit_from_inside);
+	ClassDB::bind_method(D_METHOD("is_hit_from_inside_enabled"), &RayCast2D::is_hit_from_inside_enabled);
+
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled");
 
 
 	ADD_GROUP("Collide With", "collide_with");
 	ADD_GROUP("Collide With", "collide_with");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");

+ 5 - 0
scene/2d/ray_cast_2d.h

@@ -51,6 +51,8 @@ class RayCast2D : public Node2D {
 	bool collide_with_areas = false;
 	bool collide_with_areas = false;
 	bool collide_with_bodies = true;
 	bool collide_with_bodies = true;
 
 
+	bool hit_from_inside = false;
+
 	void _draw_debug_shape();
 	void _draw_debug_shape();
 
 
 protected:
 protected:
@@ -65,6 +67,9 @@ public:
 	void set_collide_with_bodies(bool p_clip);
 	void set_collide_with_bodies(bool p_clip);
 	bool is_collide_with_bodies_enabled() const;
 	bool is_collide_with_bodies_enabled() const;
 
 
+	void set_hit_from_inside(bool p_enable);
+	bool is_hit_from_inside_enabled() const;
+
 	void set_enabled(bool p_enabled);
 	void set_enabled(bool p_enabled);
 	bool is_enabled() const;
 	bool is_enabled() const;
 
 

+ 17 - 4
scene/3d/ray_cast_3d.cpp

@@ -219,6 +219,7 @@ void RayCast3D::_update_raycast_state() {
 	ray_params.collision_mask = collision_mask;
 	ray_params.collision_mask = collision_mask;
 	ray_params.collide_with_bodies = collide_with_bodies;
 	ray_params.collide_with_bodies = collide_with_bodies;
 	ray_params.collide_with_areas = collide_with_areas;
 	ray_params.collide_with_areas = collide_with_areas;
+	ray_params.hit_from_inside = hit_from_inside;
 
 
 	PhysicsDirectSpaceState3D::RayResult rr;
 	PhysicsDirectSpaceState3D::RayResult rr;
 	if (dss->intersect_ray(ray_params, rr)) {
 	if (dss->intersect_ray(ray_params, rr)) {
@@ -268,22 +269,30 @@ void RayCast3D::clear_exceptions() {
 	exclude.clear();
 	exclude.clear();
 }
 }
 
 
-void RayCast3D::set_collide_with_areas(bool p_clip) {
-	collide_with_areas = p_clip;
+void RayCast3D::set_collide_with_areas(bool p_enabled) {
+	collide_with_areas = p_enabled;
 }
 }
 
 
 bool RayCast3D::is_collide_with_areas_enabled() const {
 bool RayCast3D::is_collide_with_areas_enabled() const {
 	return collide_with_areas;
 	return collide_with_areas;
 }
 }
 
 
-void RayCast3D::set_collide_with_bodies(bool p_clip) {
-	collide_with_bodies = p_clip;
+void RayCast3D::set_collide_with_bodies(bool p_enabled) {
+	collide_with_bodies = p_enabled;
 }
 }
 
 
 bool RayCast3D::is_collide_with_bodies_enabled() const {
 bool RayCast3D::is_collide_with_bodies_enabled() const {
 	return collide_with_bodies;
 	return collide_with_bodies;
 }
 }
 
 
+void RayCast3D::set_hit_from_inside(bool p_enabled) {
+	hit_from_inside = p_enabled;
+}
+
+bool RayCast3D::is_hit_from_inside_enabled() const {
+	return hit_from_inside;
+}
+
 void RayCast3D::_bind_methods() {
 void RayCast3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled);
 	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled);
 	ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled);
 	ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled);
@@ -322,6 +331,9 @@ void RayCast3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast3D::set_collide_with_bodies);
 	ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast3D::set_collide_with_bodies);
 	ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast3D::is_collide_with_bodies_enabled);
 	ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast3D::is_collide_with_bodies_enabled);
 
 
+	ClassDB::bind_method(D_METHOD("set_hit_from_inside", "enable"), &RayCast3D::set_hit_from_inside);
+	ClassDB::bind_method(D_METHOD("is_hit_from_inside_enabled"), &RayCast3D::is_hit_from_inside_enabled);
+
 	ClassDB::bind_method(D_METHOD("set_debug_shape_custom_color", "debug_shape_custom_color"), &RayCast3D::set_debug_shape_custom_color);
 	ClassDB::bind_method(D_METHOD("set_debug_shape_custom_color", "debug_shape_custom_color"), &RayCast3D::set_debug_shape_custom_color);
 	ClassDB::bind_method(D_METHOD("get_debug_shape_custom_color"), &RayCast3D::get_debug_shape_custom_color);
 	ClassDB::bind_method(D_METHOD("get_debug_shape_custom_color"), &RayCast3D::get_debug_shape_custom_color);
 
 
@@ -332,6 +344,7 @@ void RayCast3D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled");
 
 
 	ADD_GROUP("Collide With", "collide_with");
 	ADD_GROUP("Collide With", "collide_with");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");

+ 7 - 2
scene/3d/ray_cast_3d.h

@@ -65,18 +65,23 @@ class RayCast3D : public Node3D {
 	bool collide_with_areas = false;
 	bool collide_with_areas = false;
 	bool collide_with_bodies = true;
 	bool collide_with_bodies = true;
 
 
+	bool hit_from_inside = false;
+
 protected:
 protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
 	void _update_raycast_state();
 	void _update_raycast_state();
 	static void _bind_methods();
 	static void _bind_methods();
 
 
 public:
 public:
-	void set_collide_with_areas(bool p_clip);
+	void set_collide_with_areas(bool p_enabled);
 	bool is_collide_with_areas_enabled() const;
 	bool is_collide_with_areas_enabled() const;
 
 
-	void set_collide_with_bodies(bool p_clip);
+	void set_collide_with_bodies(bool p_enabled);
 	bool is_collide_with_bodies_enabled() const;
 	bool is_collide_with_bodies_enabled() const;
 
 
+	void set_hit_from_inside(bool p_enabled);
+	bool is_hit_from_inside_enabled() const;
+
 	void set_enabled(bool p_enabled);
 	void set_enabled(bool p_enabled);
 	bool is_enabled() const;
 	bool is_enabled() const;
 
 

+ 16 - 0
servers/physics_2d/godot_space_2d.cpp

@@ -153,6 +153,22 @@ bool GodotPhysicsDirectSpaceState2D::intersect_ray(const RayParameters &p_parame
 
 
 		Vector2 shape_point, shape_normal;
 		Vector2 shape_point, shape_normal;
 
 
+		if (shape->contains_point(local_from)) {
+			if (p_parameters.hit_from_inside) {
+				// Hit shape at starting point.
+				min_d = 0;
+				res_point = local_from;
+				res_normal = Vector2();
+				res_shape = shape_idx;
+				res_obj = col_obj;
+				collided = true;
+				break;
+			} else {
+				// Ignore shape when starting inside.
+				continue;
+			}
+		}
+
 		if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
 		if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
 			Transform2D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
 			Transform2D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
 			shape_point = xform.xform(shape_point);
 			shape_point = xform.xform(shape_point);

+ 1 - 1
servers/physics_3d/godot_body_pair_3d.cpp

@@ -191,7 +191,7 @@ bool GodotBodyPair3D::_test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A,
 	Vector3 local_to = from_inv.xform(to);
 	Vector3 local_to = from_inv.xform(to);
 
 
 	Vector3 rpos, rnorm;
 	Vector3 rpos, rnorm;
-	if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm)) {
+	if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm, true)) {
 		return false;
 		return false;
 	}
 	}
 
 

+ 1 - 1
servers/physics_3d/godot_collision_solver_3d.cpp

@@ -102,7 +102,7 @@ bool GodotCollisionSolver3D::solve_separation_ray(const GodotShape3D *p_shape_A,
 	to = ai.xform(to);
 	to = ai.xform(to);
 
 
 	Vector3 p, n;
 	Vector3 p, n;
-	if (!p_shape_B->intersect_segment(from, to, p, n)) {
+	if (!p_shape_B->intersect_segment(from, to, p, n, true)) {
 		return false;
 		return false;
 	}
 	}
 
 

+ 15 - 15
servers/physics_3d/godot_shape_3d.cpp

@@ -119,7 +119,7 @@ Vector3 GodotWorldBoundaryShape3D::get_support(const Vector3 &p_normal) const {
 	return p_normal * 1e15;
 	return p_normal * 1e15;
 }
 }
 
 
-bool GodotWorldBoundaryShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotWorldBoundaryShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	bool inters = plane.intersects_segment(p_begin, p_end, &r_result);
 	bool inters = plane.intersects_segment(p_begin, p_end, &r_result);
 	if (inters) {
 	if (inters) {
 		r_normal = plane.normal;
 		r_normal = plane.normal;
@@ -200,7 +200,7 @@ void GodotSeparationRayShape3D::get_supports(const Vector3 &p_normal, int p_max,
 	}
 	}
 }
 }
 
 
-bool GodotSeparationRayShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotSeparationRayShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	return false; //simply not possible
 	return false; //simply not possible
 }
 }
 
 
@@ -268,7 +268,7 @@ void GodotSphereShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector
 	r_type = FEATURE_POINT;
 	r_type = FEATURE_POINT;
 }
 }
 
 
-bool GodotSphereShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotSphereShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	return Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(), radius, &r_result, &r_normal);
 	return Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(), radius, &r_result, &r_normal);
 }
 }
 
 
@@ -410,7 +410,7 @@ void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *
 	r_supports[0] = point;
 	r_supports[0] = point;
 }
 }
 
 
-bool GodotBoxShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotBoxShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	AABB aabb(-half_extents, half_extents * 2.0);
 	AABB aabb(-half_extents, half_extents * 2.0);
 
 
 	return aabb.intersects_segment(p_begin, p_end, &r_result, &r_normal);
 	return aabb.intersects_segment(p_begin, p_end, &r_result, &r_normal);
@@ -546,7 +546,7 @@ void GodotCapsuleShape3D::get_supports(const Vector3 &p_normal, int p_max, Vecto
 	}
 	}
 }
 }
 
 
-bool GodotCapsuleShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotCapsuleShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	Vector3 norm = (p_end - p_begin).normalized();
 	Vector3 norm = (p_end - p_begin).normalized();
 	real_t min_d = 1e20;
 	real_t min_d = 1e20;
 
 
@@ -761,7 +761,7 @@ void GodotCylinderShape3D::get_supports(const Vector3 &p_normal, int p_max, Vect
 	}
 	}
 }
 }
 
 
-bool GodotCylinderShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotCylinderShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	return Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &r_result, &r_normal, 1);
 	return Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &r_result, &r_normal, 1);
 }
 }
 
 
@@ -954,7 +954,7 @@ void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max,
 	r_type = FEATURE_POINT;
 	r_type = FEATURE_POINT;
 }
 }
 
 
-bool GodotConvexPolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotConvexPolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
 	const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
 	int fc = mesh.faces.size();
 	int fc = mesh.faces.size();
 
 
@@ -1188,12 +1188,12 @@ void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3
 	r_supports[0] = vertex[vert_support_idx];
 	r_supports[0] = vertex[vert_support_idx];
 }
 }
 
 
-bool GodotFaceShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotFaceShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	bool c = Geometry3D::segment_intersects_triangle(p_begin, p_end, vertex[0], vertex[1], vertex[2], &r_result);
 	bool c = Geometry3D::segment_intersects_triangle(p_begin, p_end, vertex[0], vertex[1], vertex[2], &r_result);
 	if (c) {
 	if (c) {
 		r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
 		r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
 		if (r_normal.dot(p_end - p_begin) > 0) {
 		if (r_normal.dot(p_end - p_begin) > 0) {
-			if (backface_collision) {
+			if (backface_collision && p_hit_back_faces) {
 				r_normal = -r_normal;
 				r_normal = -r_normal;
 			} else {
 			} else {
 				c = false;
 				c = false;
@@ -1304,7 +1304,7 @@ void GodotConcavePolygonShape3D::_cull_segment(int p_idx, _SegmentCullParams *p_
 
 
 		Vector3 res;
 		Vector3 res;
 		Vector3 normal;
 		Vector3 normal;
-		if (face->intersect_segment(p_params->from, p_params->to, res, normal)) {
+		if (face->intersect_segment(p_params->from, p_params->to, res, normal, true)) {
 			real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
 			real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
 			if ((d > 0) && (d < p_params->min_d)) {
 			if ((d > 0) && (d < p_params->min_d)) {
 				p_params->min_d = d;
 				p_params->min_d = d;
@@ -1323,7 +1323,7 @@ void GodotConcavePolygonShape3D::_cull_segment(int p_idx, _SegmentCullParams *p_
 	}
 	}
 }
 }
 
 
-bool GodotConcavePolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotConcavePolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	if (faces.size() == 0) {
 	if (faces.size() == 0) {
 		return false;
 		return false;
 	}
 	}
@@ -1334,7 +1334,7 @@ bool GodotConcavePolygonShape3D::intersect_segment(const Vector3 &p_begin, const
 	const BVH *br = bvh.ptr();
 	const BVH *br = bvh.ptr();
 
 
 	GodotFaceShape3D face;
 	GodotFaceShape3D face;
-	face.backface_collision = backface_collision;
+	face.backface_collision = backface_collision && p_hit_back_faces;
 
 
 	_SegmentCullParams params;
 	_SegmentCullParams params;
 	params.from = p_begin;
 	params.from = p_begin;
@@ -1675,7 +1675,7 @@ struct _HeightmapGridCullState {
 _FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) {
 _FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) {
 	Vector3 res;
 	Vector3 res;
 	Vector3 normal;
 	Vector3 normal;
-	if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal)) {
+	if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal, true)) {
 		p_params.result = res;
 		p_params.result = res;
 		p_params.normal = normal;
 		p_params.normal = normal;
 		return true;
 		return true;
@@ -1881,7 +1881,7 @@ bool GodotHeightMapShape3D::_intersect_grid_segment(ProcessFunction &p_process,
 	return false;
 	return false;
 }
 }
 
 
-bool GodotHeightMapShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const {
+bool GodotHeightMapShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, bool p_hit_back_faces) const {
 	if (heights.is_empty()) {
 	if (heights.is_empty()) {
 		return false;
 		return false;
 	}
 	}
@@ -1899,7 +1899,7 @@ bool GodotHeightMapShape3D::intersect_segment(const Vector3 &p_begin, const Vect
 		// Simple case for rays that don't traverse the grid horizontally.
 		// Simple case for rays that don't traverse the grid horizontally.
 		// Just perform a test on the given cell.
 		// Just perform a test on the given cell.
 		GodotFaceShape3D face;
 		GodotFaceShape3D face;
-		face.backface_collision = false;
+		face.backface_collision = p_hit_back_faces;
 
 
 		_HeightmapSegmentCullParams params;
 		_HeightmapSegmentCullParams params;
 		params.from = p_begin;
 		params.from = p_begin;

+ 12 - 12
servers/physics_3d/godot_shape_3d.h

@@ -80,7 +80,7 @@ public:
 	virtual Vector3 get_support(const Vector3 &p_normal) const;
 	virtual Vector3 get_support(const Vector3 &p_normal) const;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const = 0;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const = 0;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const = 0;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, bool p_hit_back_faces) const = 0;
 	virtual bool intersect_point(const Vector3 &p_point) const = 0;
 	virtual bool intersect_point(const Vector3 &p_point) const = 0;
 	virtual Vector3 get_moment_of_inertia(real_t p_mass) const = 0;
 	virtual Vector3 get_moment_of_inertia(real_t p_mass) const = 0;
 
 
@@ -126,7 +126,7 @@ public:
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
 
 
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
 	virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;
@@ -153,7 +153,7 @@ public:
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 
 
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -180,7 +180,7 @@ public:
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -205,7 +205,7 @@ public:
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -234,7 +234,7 @@ public:
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -263,7 +263,7 @@ public:
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -288,7 +288,7 @@ public:
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -366,7 +366,7 @@ public:
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 
 
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -429,7 +429,7 @@ public:
 
 
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 
 
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
@@ -456,7 +456,7 @@ struct GodotFaceShape3D : public GodotShape3D {
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual Vector3 get_support(const Vector3 &p_normal) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override;
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual bool intersect_point(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
 
 
@@ -495,7 +495,7 @@ struct GodotMotionShape3D : public GodotShape3D {
 	}
 	}
 
 
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
 	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override { return false; }
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override { return false; }
 	virtual bool intersect_point(const Vector3 &p_point) const override { return false; }
 	virtual bool intersect_point(const Vector3 &p_point) const override { return false; }
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override { return p_point; }
 	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override { return p_point; }
 
 

+ 1 - 1
servers/physics_3d/godot_soft_body_3d.cpp

@@ -1300,7 +1300,7 @@ struct _SoftBodyIntersectSegmentInfo {
 	}
 	}
 };
 };
 
 
-bool GodotSoftBodyShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+bool GodotSoftBodyShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
 	_SoftBodyIntersectSegmentInfo query_info;
 	_SoftBodyIntersectSegmentInfo query_info;
 	query_info.soft_body = soft_body;
 	query_info.soft_body = soft_body;
 	query_info.from = p_begin;
 	query_info.from = p_begin;

+ 12 - 12
servers/physics_3d/godot_soft_body_3d.h

@@ -257,18 +257,18 @@ class GodotSoftBodyShape3D : public GodotShape3D {
 public:
 public:
 	GodotSoftBody3D *get_soft_body() const { return soft_body; }
 	GodotSoftBody3D *get_soft_body() const { return soft_body; }
 
 
-	virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SOFT_BODY; }
-	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; }
-	virtual Vector3 get_support(const Vector3 &p_normal) const { return Vector3(); }
-	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
-
-	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
-	virtual bool intersect_point(const Vector3 &p_point) const;
-	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
-	virtual Vector3 get_moment_of_inertia(real_t p_mass) const { return Vector3(); }
-
-	virtual void set_data(const Variant &p_data) {}
-	virtual Variant get_data() const { return Variant(); }
+	virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SOFT_BODY; }
+	virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override { r_min = r_max = 0.0; }
+	virtual Vector3 get_support(const Vector3 &p_normal) const override { return Vector3(); }
+	virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }
+
+	virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override;
+	virtual bool intersect_point(const Vector3 &p_point) const override;
+	virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;
+	virtual Vector3 get_moment_of_inertia(real_t p_mass) const override { return Vector3(); }
+
+	virtual void set_data(const Variant &p_data) override {}
+	virtual Variant get_data() const override { return Variant(); }
 
 
 	void update_bounds();
 	void update_bounds();
 
 

+ 17 - 1
servers/physics_3d/godot_space_3d.cpp

@@ -148,7 +148,23 @@ bool GodotPhysicsDirectSpaceState3D::intersect_ray(const RayParameters &p_parame
 
 
 		Vector3 shape_point, shape_normal;
 		Vector3 shape_point, shape_normal;
 
 
-		if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
+		if (shape->intersect_point(local_from)) {
+			if (p_parameters.hit_from_inside) {
+				// Hit shape at starting point.
+				min_d = 0;
+				res_point = local_from;
+				res_normal = Vector3();
+				res_shape = shape_idx;
+				res_obj = col_obj;
+				collided = true;
+				break;
+			} else {
+				// Ignore shape when starting inside.
+				continue;
+			}
+		}
+
+		if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal, p_parameters.hit_back_faces)) {
 			Transform3D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
 			Transform3D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
 			shape_point = xform.xform(shape_point);
 			shape_point = xform.xform(shape_point);
 
 

+ 4 - 0
servers/physics_server_2d.cpp

@@ -172,12 +172,16 @@ void PhysicsRayQueryParameters2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsRayQueryParameters2D::set_collide_with_areas);
 	ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsRayQueryParameters2D::set_collide_with_areas);
 	ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsRayQueryParameters2D::is_collide_with_areas_enabled);
 	ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsRayQueryParameters2D::is_collide_with_areas_enabled);
 
 
+	ClassDB::bind_method(D_METHOD("set_hit_from_inside", "enable"), &PhysicsRayQueryParameters2D::set_hit_from_inside);
+	ClassDB::bind_method(D_METHOD("is_hit_from_inside_enabled"), &PhysicsRayQueryParameters2D::is_hit_from_inside_enabled);
+
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "from"), "set_from", "get_from");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "from"), "set_from", "get_from");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "to"), "set_to", "get_to");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "to"), "set_to", "get_to");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude");
 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled");
 }
 }
 
 
 ///////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////

+ 5 - 0
servers/physics_server_2d.h

@@ -121,6 +121,8 @@ public:
 
 
 		bool collide_with_bodies = true;
 		bool collide_with_bodies = true;
 		bool collide_with_areas = false;
 		bool collide_with_areas = false;
+
+		bool hit_from_inside = false;
 	};
 	};
 
 
 	struct RayResult {
 	struct RayResult {
@@ -604,6 +606,9 @@ public:
 	void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; }
 	void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; }
 	bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; }
 	bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; }
 
 
+	void set_hit_from_inside(bool p_enable) { parameters.hit_from_inside = p_enable; }
+	bool is_hit_from_inside_enabled() const { return parameters.hit_from_inside; }
+
 	void set_exclude(const Vector<RID> &p_exclude);
 	void set_exclude(const Vector<RID> &p_exclude);
 	Vector<RID> get_exclude() const;
 	Vector<RID> get_exclude() const;
 };
 };

+ 8 - 0
servers/physics_server_3d.cpp

@@ -175,12 +175,20 @@ void PhysicsRayQueryParameters3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsRayQueryParameters3D::set_collide_with_areas);
 	ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsRayQueryParameters3D::set_collide_with_areas);
 	ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsRayQueryParameters3D::is_collide_with_areas_enabled);
 	ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsRayQueryParameters3D::is_collide_with_areas_enabled);
 
 
+	ClassDB::bind_method(D_METHOD("set_hit_from_inside", "enable"), &PhysicsRayQueryParameters3D::set_hit_from_inside);
+	ClassDB::bind_method(D_METHOD("is_hit_from_inside_enabled"), &PhysicsRayQueryParameters3D::is_hit_from_inside_enabled);
+
+	ClassDB::bind_method(D_METHOD("set_hit_back_faces", "enable"), &PhysicsRayQueryParameters3D::set_hit_back_faces);
+	ClassDB::bind_method(D_METHOD("is_hit_back_faces_enabled"), &PhysicsRayQueryParameters3D::is_hit_back_faces_enabled);
+
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "from"), "set_from", "get_from");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "from"), "set_from", "get_from");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "to"), "set_to", "get_to");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "to"), "set_to", "get_to");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude");
 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_back_faces"), "set_hit_back_faces", "is_hit_back_faces_enabled");
 }
 }
 
 
 ///////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////

+ 9 - 0
servers/physics_server_3d.h

@@ -125,6 +125,9 @@ public:
 		bool collide_with_bodies = true;
 		bool collide_with_bodies = true;
 		bool collide_with_areas = false;
 		bool collide_with_areas = false;
 
 
+		bool hit_from_inside = false;
+		bool hit_back_faces = true;
+
 		bool pick_ray = false;
 		bool pick_ray = false;
 	};
 	};
 
 
@@ -805,6 +808,12 @@ public:
 	void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; }
 	void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; }
 	bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; }
 	bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; }
 
 
+	void set_hit_from_inside(bool p_enable) { parameters.hit_from_inside = p_enable; }
+	bool is_hit_from_inside_enabled() const { return parameters.hit_from_inside; }
+
+	void set_hit_back_faces(bool p_enable) { parameters.hit_back_faces = p_enable; }
+	bool is_hit_back_faces_enabled() const { return parameters.hit_back_faces; }
+
 	void set_exclude(const Vector<RID> &p_exclude);
 	void set_exclude(const Vector<RID> &p_exclude);
 	Vector<RID> get_exclude() const;
 	Vector<RID> get_exclude() const;
 };
 };