-
Notifications
You must be signed in to change notification settings - Fork 288
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
#291 Fixing Pickshapes using farseer #579
Conversation
update master
Explicit C# Language Version
Added Simple RigidBody Physics Test
Since there's a ToDo comment, is this still WiP? Let me know when it's ready for review 👍 |
The chainshape part is buggy so I left that out for now. Just did the circle and poly shapes for now. The chainshapes were not working before either so its not breaking anything. |
I'll take a look as soon as I get around to it. Since polygons and circles only would be equal to the old functionality, we could merge this PR even without the chain shape checks after review. Should be fine as long as we don't introduce a regression. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perf-wise, maybe provide a private (!) version of the fully parameterized instance PickShapes method that takes a Farseer polygon shape instance and (by-ref) transform? You could call this method from the regular public overload, and the static PickShapesGlobal method: No added benefit for the first one, but the second one would only create and configure the shape once.
Final question: How's performance compared to before? (And which test setup did you use? Good to know for context.)
So far I like the Farseer version of this fix much better, very compact and self-contained. Nice work on this 👍
{ | ||
pickedShapes.Add(s); | ||
continue; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's a polygon shape, but does not have any collisions, it will continue checking whether it could be a circle shape next. Consider changing this to an if-else structure, or moving the continue statement out of the point count check!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ye missed that, it should obviously not do the circle check after it already done the polygon one.
Too bad we dont have C# 7 as pattern matching would make this so much more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found out there is a ShapeType enum property on the fixture so I can use that in a switch. Much more readable.
Vector2 fsWorldCoord = PhysicsUnit.LengthToPhysical * worldCoord; | ||
FarseerPhysics.Collision.AABB fsWorldAABB = new FarseerPhysics.Collision.AABB(fsWorldCoord, PhysicsUnit.LengthToPhysical * (worldCoord + size)); | ||
|
||
PolygonShape boxShape = new PolygonShape(new Vertices(new List<Vector2>() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad you didn't bother keeping the old fsWorldCoord
naming / variable scheme. That was terrible. This one looks definitely cleaner.
PhysicsUnit.LengthToPhysical * new Vector2(worldCoord.X + size.X, worldCoord.Y), | ||
PhysicsUnit.LengthToPhysical * (worldCoord + size), | ||
PhysicsUnit.LengthToPhysical * new Vector2(worldCoord.X, worldCoord.Y + size.Y) }), 1); | ||
Mat22 rot = new Mat22(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a newline, so the box transform creation is its own block, similar to the body transform retrieval below. Also, maybe move the oldCount and manifold declarations down to directly in front of the loop, so it doesn't get mixes up with the transform creation blocks?
Mat22 rot = new Mat22(); | ||
rot.SetIdentity(); | ||
Vector2 pos = new Vector2(0, 0); | ||
FarseerPhysics.Common.Transform boxTransform = new FarseerPhysics.Common.Transform(ref pos, ref rot); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are transform position and rotation public fields? If so, no need to declare and assign rotation and position separately! Just call SetIdentity directly on the box transform rotation field, and assign the position directly without declaring an extra variable. Could also use the default / empty constructor in that case.
(If they are not public fields, disregard my comment.)
{ | ||
pickedShapes.Add(s); | ||
break; | ||
continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above!
// { | ||
// var jNext = j + 1; | ||
// if (jNext >= chainShape.Vertices.Count) jNext = 0; | ||
// var edgeShape = new EdgeShape(chainShape.Vertices[j], chainShape.Vertices[jNext]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if that will fix it, but instead of creating a new edge shape every loop iteration, create it once and let the chain shape configure it. There's a GetChildEdge
method that is public and I believe also used by Farseers internals, here.
Alternatively, if you want to keep chain shapes our of this PR for now, maybe just add a note to the commented out section regarding this, for future reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was still experimenting with this part. I already tried it with GetChildEdge but got some weird results so have to investigate that some more. Not for this PR though so Ill put a clarifying comment there
When I get back home I will give you the setup I used for measuring performance. So far the performance was slower than my own implementation. Good point about the private parameterized instance method I will add that. |
Tested the performance and compared to my own implementation the farseer is slower. How much depends on the shape and where the collision is: Now the question is is it worth sacrificing some performance to avoid duplicate collision code? Note that my own implementation is not optimized yet. I think it should be possible to operate directly on the farseer data now I understand farseer a little better for instance. Tbh I don't think anyone will be running in performance issues anytime soon with PickShapes as I had to call it quite a lot of times before you could start noticing it. Attached is the Data and Source folder I used when testing this. To use:
Note that there are currently no unit tests in this branch. I could copy some over from #577. |
FarseerPhysics.Common.Transform boxTransform = new FarseerPhysics.Common.Transform(); | ||
boxTransform.SetIdentity(); | ||
|
||
return PickShapes(boxShape, boxTransform, pickedShapes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use this.
for instance member access as well. Would merge anyway since it's really just a detail, so whoever of us gets to it first can do it.
Changes look good so far!
Good question! In this case, I think the answer should be "yes, if it's not too severe", but it should definitely be on a list of potential optimization for when issue #570 is done. Will take a closer look at performance myself before merging - if it doesn't have a serious impact except in benchmarks, I think it should be fine. Will have to see how close it is to real-world impact. |
#FIX: Fixed a bug where complex polygon shapes would be returned multiple times in the result list of PickShapes when intersecting more than one convex segment.
#CHANGE: Renamed local variable from single-letter indexer style to a descriptive name.
Took a brief look and probably wouldn't do a merge for them as-is, so I'd keep this PR separate for now so we can get it merged. Tests for this would be great, but I'd probably do a draft / design pass in the discussion of #533 first before implementing it. Found a small bug where a ShapeInfo was sometimes added multiple times to the result list for complex polygons and fixed it. Looked into performance and getting between 30ms and 350ms for 50000 tests / up to 0.007 ms per test on my machine depending on which bodies are checked - not great, but not catastrophic either. I do see some optimization potential on the Farseer side of things, but that's an issue for another day. A bit busy right now, so will have to do it later, but I'd say this is a merge. Nice work 👍 ToDo:
|
Hmm well the contains check also adds overhead in all cases atm. Not sure what would be faster since that will also depend on how much shapes you are picking. This would need benchmarking. Changing the signature would break compatibility so definitely not for v2. |
Yep, but also different kinds of overhead! Perf right now, but design in the other case, e.g. forcing the callsite to use a more complex collection. Totally agree on the perf consideration though, if it shows up on the profiler at some point, this will have to change. |
No description provided.