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

Added support for shapeCast and merged raycastFirst and raycastAll into raycast #5039

Open
wants to merge 102 commits into
base: main
Choose a base branch
from

Conversation

MushAsterion
Copy link
Collaborator

@MushAsterion MushAsterion commented Feb 3, 2023

  • Requires to update Ammo.js to latest version. (which is not a breaking change)
  • No custom IDL for Ammo.js required.

Deprecated RaycastResult for HitResult as it is now returned by shapeCast.
Added the following property for HitResult public API:

  • distance: The distance at which the hit occurred from the starting point.

As shape may have lower hitFraction but be more distant than another hit with higher hitFraction (for example a side of the cylinder will be closest in distance than its other tip. (#5179)

Deprecated raycastFirst and raycastAll for a new function raycast defaulting to a "first" behavior, with possibility to use with option findAll = true to have all results.

raycast(start: Vec3, end: Vec3, options)

Added test and cast for shapes using shapeCast:

shapeCast(shape, startPosition: Vec3, startRotation: Vec3|Quat, endPosition; Vec3, options)

Where shape can either be a Ammo.btCollisionShape or an object defined as follows:

{
    type: "box"|"cylinder"|"capsule"|"cone"|"sphere",
    halfExtends: Vec3, // For type "box"
    radius: number, // For any type but "box"
    height: number, // For types "cylinder", "capsule" and "cone"
    axis: number // For types "cylinder", "capsule" and "cone"
}

And where available options are:

{
    sort: boolean,
    endRotation: Vec3|Quat,
    findAll: boolean, // Not available if different end transform
    filterCollisionGroup: number,
    filterCollisionMask: number,
    filterTags: string[]|string[][], // Not available if different end transform
    filterCallback: (entity: Entity) => boolean, // Not available if different end transform
    destroyShape: boolean // Forced true when shape is a configuration
}

Fixes #2094

I confirm I have read the contributing guidelines and signed the Contributor License Agreement.

Added cast for shapes using `shapeCast` and by configuring the shape. It also provide API for each primitive shapes:
- `boxCast(halfExtends, position, rotation)`
- `capsuleCast(radius, heigh, axis, position, rotation)`
- `coneCast(radius, heigh, axis, position, rotation)`
- `cylinderCast(radius, heigh, axis, position, rotation)`
- `sphereCast(radius, position, rotation)`

There is also a private function `_shapecast(shape, collision, rotation)` if you wish to use your own shape (Ammo.btCollisionShape).
Include full comments and docs. Include assertion of `Ammo.ConcreteContactResultCallback` for every public function. No assertion on private function to reduce function calls.
*
* @returns {RaycastResult[]} An array of shapecast hit results (0 length if there were no hits).
*/
shapeCast(shape, position, rotation) {
Copy link
Contributor

@willeastcott willeastcott Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is a utility function that basically calls the shape-specific functions. For the purpose of maintaining a nice and accessible API, should we:

  1. just retain this 'all-in-one' function as public
  2. just retain the shape-specific function as public
  3. keep all public

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The advantage of "all-in-one" function is that you can actually use a JSON format for all the shape config meaning it can easily be assigned from a script attribute to edit it within the editor directly and avoid having to be only code-based. In another hand the shape-specific function allow users used to other engines to find the function easily (especially sphereCast which is really common).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's a great point. OK, fair enough. 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to unresolve this discussion and talk about it some more, @MushAsterion. I do still feel that this PR introduces a lot of additions to the API. 18 methods at the moment. And if shapeCastAll flavors get added, it takes it to 24. Plus the two existing raycasting functions, that'd be 26 functions for testing and casting. I think that's just too much. We could just have:

raycast (we could deprecate raycastFirst and raycastAll - note we don't _have_ to do that in this PR)
shapeCast
shapeTest

The all versus first could just be an option (maybe defaulting to first).

It just feels to me that the JSON approach is interesting, but it's very niche and, in reality, the vast majority of developers won't call the API like that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could potentially also drop shapeTest if start and end pos/rot of shapeCast where the same too maybe?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shapeTestFirst is doing more work due to how Bullet/Ammo work and completely different from raycasting as raycasting is only a question of point while the closest point in a shape's position is not always the first to be detected since it depends on how the physics engine perform the test.

Once again the exposure of First/All methods is to match with what the engine has already implemented. I'm an external contributor so I don't want to step or change core project features. I personally find it handy for beginners to have the support for sure but as @willeastcott mentioned it's a very long list of new public methods which might also bring more confusion. I think it's a good solution to merge as much as possible to reduce public methods but I'm concerned about how easy it would be for people that are just looking to make a quick project without trying to get a deep understanding of the engine's API... I'll surely update to fit whatever they think is best anyway, the core features of the PR are already done and updating them is not a big deal

Copy link
Contributor

@LeXXik LeXXik May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff! Many useful features are being added. Although, I do agree that the API is too verbose. We can simplify those, and move most of the customization stuff to options.

My vote goes for dropping -all/-first from the method name, and use an option setting.

shapeTestFirst seems a bit superfluous. We can just return everything and let user decide what to do with the results. If future Ammo adds a feature to allow collecting only the first intersection (which sounds strange to me), we can add it via an option. Shape and point collision tests are usually useful for getting all colliders they intersect, otherwise a sweep test is used.

About shape target rotation during sweep. Personally, I've never met a need to use it. Maybe it is useful in robotics, where Bullet engine is popular? No idea. Most of the other other physics engines don't allow it (Rapier, PhysX, Jolt). As such, I would actually move it to options as well.

Whatever the names are, but signatures could look something like:

raycast(start, end, opts = {});

shapecast(shape, pos, rot, dir = Vec3.ZERO, opts = {});

If dir is a zero vector, we do shape test. Otherwise it is a non-normalized cast direction (its normal for direction, its magnitude as cast distance). Shape properties can be part of the options, e.g. radius for radius-based shapes. We could also use the end position instead and check if it is same as start position, as Will suggested. Perhaps would be a better match to raycast then.

About destroying a shape used in sweep. If a shape is not auto-destroyed (e.g. via some option), then there should be a method to destroy it later. Never mind, it is for a user created one, which he is in control of.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure to understand the point of changing endPosition into dir while raycast has a end param, is there any particular reason to make it different?

Something like

shapecast(shape, start, end, opts = {})

Where options could have something like

{
    startRotation: Vec3|Quat,
    endRotation: Vec3|Quat,
    findAll: boolean, // Defaults to false, not possible if end transform !== start transform
    // ... other options
}

Would be more fitting with the suggested raycast signature.

Copy link
Contributor

@LeXXik LeXXik May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, something like that. I think starting rotation is probably not in options, as it is often used for non-spheres. Target rotation can be.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright so based on feedback I just rewrote the PR. Let me know if it better fits now 🙃

@mvaligursky
Copy link
Contributor

Nice PR! Two comments:

@MushAsterion
Copy link
Collaborator Author

MushAsterion commented Feb 3, 2023

Thanks! And thank you for your review.

Regarding your questions @mvaligursky,

I tested it within the production version from online editor and re-checked after with engine-only to make sure it was working. Here is the project I made to do it: https://playcanvas.com/project/1034600.

To be completely honest with you I'm far from being the best on creating full project, I'll leave this to someone else.

@willeastcott willeastcott self-assigned this Feb 3, 2023
@willeastcott willeastcott added feature area: physics Physics related issue labels Feb 3, 2023
@willeastcott
Copy link
Contributor

@MushAsterion I think it's OK to skip the example if you're not confident about putting one together. We can maybe open another issue requesting that...

@willeastcott
Copy link
Contributor

@MushAsterion I just chatted to @slimbuck about this. He's busy working on a SuperSplat update at the moment but he'll deploy the latest ammo.js as soon as he's able.

@willeastcott
Copy link
Contributor

@MushAsterion We just checked our current Ammo version. It has both convexSweepTest and ClosestConvexResultCallback. Is there anything else we might be missing?

@MushAsterion
Copy link
Collaborator Author

MushAsterion commented May 30, 2024

@MushAsterion We just checked our current Ammo version. It has both convexSweepTest and ClosestConvexResultCallback. Is there anything else we might be missing?

Not too sure, actually checking from my previous edits of original post it requires exposure of:

btCollisionObject on ClosestConvexResultCallback (for shapeCastFirst) and the ConvexResultCallback constructor (for shapeCastAll)

Just tested and actually everything works fine with latest Ammo version from Editor

@MushAsterion MushAsterion changed the title Added support for shapeTestFirst, shapeTestAll and shapeCastFirst Added support for shapeCast and merged raycastFirst and raycastAll into raycast May 31, 2024
Copy link
Contributor

@LeXXik LeXXik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with minor comments

src/framework/components/rigid-body/system.js Show resolved Hide resolved
src/framework/components/rigid-body/system.js Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: physics Physics related issue feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for spherecast
10 participants