Skip to content

Commit

Permalink
Add ability to get barycentric coords from ray
Browse files Browse the repository at this point in the history
Add ability to get barycentric coords from ray
  • Loading branch information
PrecisionRender committed Jan 11, 2023
1 parent f73cb4c commit 7c0688a
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 29 deletions.
6 changes: 6 additions & 0 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,10 @@ Vector3 Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point
return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, s);
}

Vector3 Geometry3D::get_triangle_barycentric_coords(const Vector3& p_point, const Vector3& p_v0, const Vector3& p_v1, const Vector3& p_v2) {
return ::Geometry3D::triangle_get_barycentric_coords(p_v0, p_v1, p_v2, p_point);
}

Variant Geometry3D::ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) {
Vector3 res;
if (::Geometry3D::ray_intersects_triangle(p_from, p_dir, p_v0, p_v1, p_v2, &res)) {
Expand Down Expand Up @@ -983,6 +987,8 @@ void Geometry3D::_bind_methods() {

ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_uncapped", "point", "s1", "s2"), &Geometry3D::get_closest_point_to_segment_uncapped);

ClassDB::bind_method(D_METHOD("get_triangle_barycentric_coords", "point", "v0", "v1", "v2"), &Geometry3D::get_triangle_barycentric_coords);

ClassDB::bind_method(D_METHOD("ray_intersects_triangle", "from", "dir", "a", "b", "c"), &Geometry3D::ray_intersects_triangle);
ClassDB::bind_method(D_METHOD("segment_intersects_triangle", "from", "to", "a", "b", "c"), &Geometry3D::segment_intersects_triangle);
ClassDB::bind_method(D_METHOD("segment_intersects_sphere", "from", "to", "sphere_position", "sphere_radius"), &Geometry3D::segment_intersects_sphere);
Expand Down
1 change: 1 addition & 0 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ class Geometry3D : public Object {
Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2);
Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
Vector3 get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
Variant ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);
Variant segment_intersects_triangle(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2);

Expand Down
10 changes: 10 additions & 0 deletions doc/classes/Geometry3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
Given the two 3D segments ([param p1], [param p2]) and ([param q1], [param q2]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector3Array] that contains this point on ([param p1], [param p2]) as well the accompanying point on ([param q1], [param q2]).
</description>
</method>
<method name="triangle_get_barycentric_coords">
<return type="Variant" />
<param index="0" name="point" type="Vector3" />
<param index="1" name="v0" type="Vector3" />
<param index="2" name="v1" type="Vector3" />
<param index="3" name="v2" type="Vector3" />
<description>
Returns the barycentric coordinates for a given point inside a triangle.
</description>
</method>
<method name="ray_intersects_triangle">
<return type="Variant" />
<param index="0" name="from" type="Vector3" />
Expand Down
2 changes: 2 additions & 0 deletions doc/classes/PhysicsDirectSpaceState3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
[code]collider_id[/code]: The colliding object's ID.
[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]: Returns the the face index at the intersection point.
[b]Note:[/b] Returns a valid number only if the intersected shape is a [ConcavePolygonShape3D]. If false, [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.
Expand Down
6 changes: 6 additions & 0 deletions doc/classes/RayCast3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
Returns the shape ID of the first object that the ray intersects, or [code]0[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
<method name="get_collision_face_index" qualifiers="const">
<return type="int" />
<description>
Returns the collision object's face index at the collision point, or [code]-1[/code] if the shape intersecting the ray is not a [ConcavePolygonShape3D].
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />
Expand Down
6 changes: 6 additions & 0 deletions scene/3d/ray_cast_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ Vector3 RayCast3D::get_collision_normal() const {
return collision_normal;
}

int RayCast3D::get_collision_face_index() const {
return collision_face_index;
}

void RayCast3D::set_enabled(bool p_enabled) {
enabled = p_enabled;
update_gizmos();
Expand Down Expand Up @@ -231,6 +235,7 @@ void RayCast3D::_update_raycast_state() {
against_rid = rr.rid;
collision_point = rr.position;
collision_normal = rr.normal;
collision_face_index = rr.face_index;
against_shape = rr.shape;
} else {
collided = false;
Expand Down Expand Up @@ -312,6 +317,7 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast3D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast3D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast3D::get_collision_normal);
ClassDB::bind_method(D_METHOD("get_collision_face_index"), &RayCast3D::get_collision_face_index);

ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &RayCast3D::add_exception_rid);
ClassDB::bind_method(D_METHOD("add_exception", "node"), &RayCast3D::add_exception);
Expand Down
2 changes: 2 additions & 0 deletions scene/3d/ray_cast_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class RayCast3D : public Node3D {
int against_shape = 0;
Vector3 collision_point;
Vector3 collision_normal;
int collision_face_index = -1;

Vector3 target_position = Vector3(0, -1, 0);
HashSet<RID> exclude;
Expand Down Expand Up @@ -118,6 +119,7 @@ class RayCast3D : public Node3D {
int get_collider_shape() const;
Vector3 get_collision_point() const;
Vector3 get_collision_normal() const;
int get_collision_face_index() const;

void add_exception_rid(const RID &p_rid);
void add_exception(const CollisionObject3D *p_node);
Expand Down
3 changes: 2 additions & 1 deletion servers/physics_3d/godot_body_pair_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ 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, true)) {
int fi;
if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm, fi, true)) {
// there was no hit. Since the segment is the length of per-frame motion, this means the bodies will not
// actually collide yet on next frame. We'll probably check again next frame once they're closer.
return false;
Expand Down
3 changes: 2 additions & 1 deletion servers/physics_3d/godot_collision_solver_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ 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, true)) {
int fi;
if (!p_shape_B->intersect_segment(from, to, p, n, fi, true)) {
return false;
}

Expand Down
29 changes: 17 additions & 12 deletions servers/physics_3d/godot_shape_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Vector3 GodotWorldBoundaryShape3D::get_support(const Vector3 &p_normal) const {
return p_normal * 1e15;
}

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 GodotWorldBoundaryShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
bool inters = plane.intersects_segment(p_begin, p_end, &r_result);
if (inters) {
r_normal = plane.normal;
Expand Down Expand Up @@ -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, bool p_hit_back_faces) const {
bool GodotSeparationRayShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
return false; //simply not possible
}

Expand Down Expand Up @@ -268,7 +268,7 @@ void GodotSphereShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector
r_type = FEATURE_POINT;
}

bool GodotSphereShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
bool GodotSphereShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
return Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(), radius, &r_result, &r_normal);
}

Expand Down Expand Up @@ -410,7 +410,7 @@ void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *
r_supports[0] = point;
}

bool GodotBoxShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
bool GodotBoxShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
AABB aabb_ext(-half_extents, half_extents * 2.0);

return aabb_ext.intersects_segment(p_begin, p_end, &r_result, &r_normal);
Expand Down Expand Up @@ -544,7 +544,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, bool p_hit_back_faces) const {
bool GodotCapsuleShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
Vector3 norm = (p_end - p_begin).normalized();
real_t min_d = 1e20;

Expand Down Expand Up @@ -736,7 +736,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, bool p_hit_back_faces) const {
bool GodotCylinderShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
return Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &r_result, &r_normal, 1);
}

Expand Down Expand Up @@ -982,7 +982,7 @@ void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max,
r_type = FEATURE_POINT;
}

bool GodotConvexPolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
bool GodotConvexPolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
int fc = mesh.faces.size();

Expand Down Expand Up @@ -1258,7 +1258,7 @@ void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3
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, bool p_hit_back_faces) const {
bool GodotFaceShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
bool c = Geometry3D::segment_intersects_triangle(p_begin, p_end, vertex[0], vertex[1], vertex[2], &r_result);
if (c) {
r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
Expand Down Expand Up @@ -1368,12 +1368,14 @@ void GodotConcavePolygonShape3D::_cull_segment(int p_idx, _SegmentCullParams *p_

Vector3 res;
Vector3 normal;
if (face->intersect_segment(p_params->from, p_params->to, res, normal, true)) {
int face_index = params_bvh->face_index;
if (face->intersect_segment(p_params->from, p_params->to, res, normal, face_index, true)) {
real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
if ((d > 0) && (d < p_params->min_d)) {
p_params->min_d = d;
p_params->result = res;
p_params->normal = normal;
p_params->face_index = face_index;
p_params->collisions++;
}
}
Expand All @@ -1387,7 +1389,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, bool p_hit_back_faces) const {
bool GodotConcavePolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
if (faces.size() == 0) {
return false;
}
Expand Down Expand Up @@ -1417,6 +1419,7 @@ bool GodotConcavePolygonShape3D::intersect_segment(const Vector3 &p_begin, const
if (params.collisions > 0) {
r_result = params.result;
r_normal = params.normal;
r_face_index = params.face_index;
return true;
} else {
return false;
Expand Down Expand Up @@ -1740,9 +1743,11 @@ struct _HeightmapGridCullState {
_FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) {
Vector3 res;
Vector3 normal;
if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal, true)) {
int fi;
if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal, fi, true)) {
p_params.result = res;
p_params.normal = normal;

return true;
}

Expand Down Expand Up @@ -1946,7 +1951,7 @@ bool GodotHeightMapShape3D::_intersect_grid_segment(ProcessFunction &p_process,
return false;
}

bool GodotHeightMapShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, bool p_hit_back_faces) const {
bool GodotHeightMapShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
if (heights.is_empty()) {
return false;
}
Expand Down
Loading

0 comments on commit 7c0688a

Please sign in to comment.