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

Shape2D.collide_and_get_contacts returns incorrect contact points between convex polygon and line segment #48520

Open
Tracked by #45334
davidscholberg opened this issue May 6, 2021 · 5 comments

Comments

@davidscholberg
Copy link

Godot version:
v3.2.3.stable.official

OS/device including version:
Windows 10, OpenGL ES 3.0 Renderer: GeForce GTX 1070/PCIe/SSE2

Issue description:
Shape2D.collide_and_get_contacts can sometimes return incorrect contact points between a convex polygon and a line segment. The following script and screenshot illustrate this:

extends Node2D

var rect_points: PoolVector2Array
var segment_point_a: Vector2
var segment_point_b: Vector2
var contact_points: Array
var intersection_point: Vector2

func _ready():
	var rect_point_a: Vector2 = Vector2(294.51239, 351.953125)
	var rect_point_b: Vector2 = Vector2(423.069946, 505.161987)
	var rect_point_c: Vector2 = Vector2(729.48761, 248.046875)
	var rect_point_d: Vector2 = Vector2(600.930054, 94.838013)

	rect_points.append(rect_point_a)
	rect_points.append(rect_point_b)
	rect_points.append(rect_point_c)
	rect_points.append(rect_point_d)

	var rect_shape: ConvexPolygonShape2D = ConvexPolygonShape2D.new()
	rect_shape.set_point_cloud(rect_points)

	segment_point_a = Vector2(500, 100)
	segment_point_b = Vector2(500, 300)

	var segment_shape: SegmentShape2D = SegmentShape2D.new()
	segment_shape.a = segment_point_a
	segment_shape.b = segment_point_b

	contact_points = rect_shape.collide_and_get_contacts(Transform2D(), segment_shape, Transform2D())

	intersection_point = Geometry.segment_intersects_segment_2d(segment_point_a, segment_point_b, rect_point_d, rect_point_a)

func _draw():
	draw_colored_polygon(rect_points, Color.blue)
	draw_line(segment_point_a, segment_point_b, Color.green, 5)
	for contact_point in contact_points:
		draw_circle(contact_point, 5, Color.white)
	draw_circle(intersection_point, 5, Color.red)

CollideAndGetContactsTest

The white circles are the contact points returned by the call to Shape2D.collide_and_get_contacts (one of which is plainly incorrect), and the red circle is the intersection point found by Geometry.segment_intersects_segment_2d (which is plainly correct).

Steps to reproduce:
Attach the above script to a Node2D and run the scene.

Minimal reproduction project:
The above script is a sufficient test and has no dependencies.

@pouleyKetchoupp
Copy link
Contributor

This seems like the expected behavior.

Contact points are not necessarily along the segment shape and are different from an intersection. They are used by the physics engine for collision and they are calculated to be at the closest edge, so the shapes are pushed out from each other with minimal distance.

Geometry is the correct API to use for shape intersection.

That said, I would like to know if there's a specific reason for you to expect contact points to be different. If something is not working as expected, could you share a bit more about your use case to see if I or someone else can help?

@davidscholberg
Copy link
Author

@pouleyKetchoupp Intuitively, as a godot novice, I would have thought that the contact points returned by Shape2D.collide_and_get_contacts would be the points where the shapes intersect. The documentation for Shape2D.collide_and_get_contacts even says:

Returns a list of the points where this shape touches another.

Maybe it's just me, but it seems like the behavior in my example above doesn't align with the documentation as stated. Maybe the documentation should be more clear on this?

As for what I'm trying to accomplish, I'm trying to implement a laser light in 2D, so when something collides with the laser light rectangle, the light needs to be redrawn based on the colliding shape. If Geometry is the correct API for that, then I am more than happy to use it.

@pouleyKetchoupp
Copy link
Contributor

Maybe it's just me, but it seems like the behavior in my example above doesn't align with the documentation as stated. Maybe the documentation should be more clear on this?

Yeah, definitely. The documentation should explain contact points more in details and possibly link to Geometry as well to help with cases where intersection is needed.

As for what I'm trying to accomplish, I'm trying to implement a laser light in 2D, so when something collides with the laser light rectangle, the light needs to be redrawn based on the colliding shape. If Geometry is the correct API for that, then I am more than happy to use it.

I can confirm intersections from the Geometry API is what will work the best in this case.

That also makes me think it could be useful to have an API in the future that helps with getting shape intersections, without having to pick specific functions manually from Geometry. It would work in a similar way as collide_and_get_contacts.
(I'm taking a note of your use case for a future proposal)

@Giwayume
Copy link
Contributor

Giwayume commented Nov 17, 2021

Can a method be added to find what a typical user is expecting out of collide_and_get_contacts? Actual intersection points?

I don't see a single method in the Geometry class that takes 2 Shape2D objects and returns intersection points. It looks like trying to emulate our expected behavior of collide_and_get_contacts with the Geometry class in a general use case is going to take a ton of code.

@pouleyKetchoupp
Copy link
Contributor

Can a method be added to find what a typical user is expecting out of collide_and_get_contacts? Actual intersection points?

I don't see a single method in the Geometry class that takes 2 Shape2D objects and returns intersection points. It looks like trying to emulate our expected behavior of collide_and_get_contacts with the Geometry class in a general use case is going to take a ton of code.

Just to be clear, the physics system is designed to provide contact points that can be used for shape separation, not generic shape intersection, so it's not a trivial thing to add to the API. The documentation for collide_and_get_contacts is not very clear and should be improved.

That said, if there's something commonly needed and missing in the API, we can discuss how to solve the problem.

I would suggest to open a proposal (https://github.com/godotengine/godot-proposals) with more details about your use case. Then we can make an assessment:

  • Whether it can be solved by script or needs a new functionality
  • Whether the Geometry API can be improved, or a new function needs to be added in the physics shapes API
  • Possibly discussed with other users, so if we decide to add something we can make sure it will benefit more people

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants