Skip to content

Commit

Permalink
Merge pull request #54857 from nekomatata/raycast-hit-from-inside
Browse files Browse the repository at this point in the history
  • Loading branch information
akien-mga authored Nov 11, 2021
2 parents c0fdbf1 + c3ae7dd commit 86460db
Show file tree
Hide file tree
Showing 22 changed files with 166 additions and 57 deletions.
2 changes: 1 addition & 1 deletion doc/classes/PhysicsDirectSpaceState2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
[code]collider[/code]: The colliding object.
[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]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
Expand Down
2 changes: 1 addition & 1 deletion doc/classes/PhysicsDirectSpaceState3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
[code]collider[/code]: The colliding object.
[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]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/PhysicsRayQueryParameters2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
<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.
</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)">
The ending point of the ray being queried for, in global coordinates.
</member>
Expand Down
6 changes: 6 additions & 0 deletions doc/classes/PhysicsRayQueryParameters3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
<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.
</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)">
The ending point of the ray being queried for, in global coordinates.
</member>
Expand Down
5 changes: 4 additions & 1 deletion doc/classes/RayCast2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
<method name="get_collision_normal" qualifiers="const">
<return type="Vector2" />
<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>
</method>
<method name="get_collision_point" qualifiers="const">
Expand Down Expand Up @@ -118,6 +118,9 @@
<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.
</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)">
The ray's destination point, relative to the RayCast's [code]position[/code].
</member>
Expand Down
5 changes: 4 additions & 1 deletion doc/classes/RayCast3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<method name="get_collision_normal" qualifiers="const">
<return type="Vector3" />
<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>
</method>
<method name="get_collision_point" qualifiers="const">
Expand Down Expand Up @@ -127,6 +127,9 @@
<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.
</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)">
The ray's destination point, relative to the RayCast's [code]position[/code].
</member>
Expand Down
21 changes: 17 additions & 4 deletions scene/2d/ray_cast_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ void RayCast2D::_update_raycast_state() {
ray_params.collision_mask = collision_mask;
ray_params.collide_with_bodies = collide_with_bodies;
ray_params.collide_with_areas = collide_with_areas;
ray_params.hit_from_inside = hit_from_inside;

if (dss->intersect_ray(ray_params, rr)) {
collided = true;
Expand Down Expand Up @@ -290,22 +291,30 @@ void RayCast2D::clear_exceptions() {
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 {
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 {
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() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast2D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast2D::is_enabled);
Expand Down Expand Up @@ -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("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, "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::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_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
Expand Down
5 changes: 5 additions & 0 deletions scene/2d/ray_cast_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class RayCast2D : public Node2D {
bool collide_with_areas = false;
bool collide_with_bodies = true;

bool hit_from_inside = false;

void _draw_debug_shape();

protected:
Expand All @@ -65,6 +67,9 @@ class RayCast2D : public Node2D {
void set_collide_with_bodies(bool p_clip);
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);
bool is_enabled() const;

Expand Down
21 changes: 17 additions & 4 deletions scene/3d/ray_cast_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ void RayCast3D::_update_raycast_state() {
ray_params.collision_mask = collision_mask;
ray_params.collide_with_bodies = collide_with_bodies;
ray_params.collide_with_areas = collide_with_areas;
ray_params.hit_from_inside = hit_from_inside;

PhysicsDirectSpaceState3D::RayResult rr;
if (dss->intersect_ray(ray_params, rr)) {
Expand Down Expand Up @@ -268,22 +269,30 @@ void RayCast3D::clear_exceptions() {
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 {
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 {
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() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled);
Expand Down Expand Up @@ -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("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("get_debug_shape_custom_color"), &RayCast3D::get_debug_shape_custom_color);

Expand All @@ -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::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::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled");

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");
Expand Down
9 changes: 7 additions & 2 deletions scene/3d/ray_cast_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,23 @@ class RayCast3D : public Node3D {
bool collide_with_areas = false;
bool collide_with_bodies = true;

bool hit_from_inside = false;

protected:
void _notification(int p_what);
void _update_raycast_state();
static void _bind_methods();

public:
void set_collide_with_areas(bool p_clip);
void set_collide_with_areas(bool p_enabled);
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;

void set_hit_from_inside(bool p_enabled);
bool is_hit_from_inside_enabled() const;

void set_enabled(bool p_enabled);
bool is_enabled() const;

Expand Down
16 changes: 16 additions & 0 deletions servers/physics_2d/godot_space_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,22 @@ bool GodotPhysicsDirectSpaceState2D::intersect_ray(const RayParameters &p_parame

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)) {
Transform2D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
shape_point = xform.xform(shape_point);
Expand Down
2 changes: 1 addition & 1 deletion servers/physics_3d/godot_body_pair_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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;
}

Expand Down
2 changes: 1 addition & 1 deletion servers/physics_3d/godot_collision_solver_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ bool GodotCollisionSolver3D::solve_separation_ray(const GodotShape3D *p_shape_A,
to = ai.xform(to);

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;
}

Expand Down
Loading

0 comments on commit 86460db

Please sign in to comment.