Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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