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

Beta release of JointComponent #7135

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

Beta release of JointComponent #7135

wants to merge 6 commits into from

Conversation

willeastcott
Copy link
Contributor

@willeastcott willeastcott commented Nov 23, 2024

Releases the JointComponent API in beta. For anyone with physics experience, please take a look and offer your thoughts/comments.

Also added a new rope bridge engine example:

rope-bridge.mp4

API reference:

image

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

@willeastcott willeastcott added feature area: physics Physics related issue labels Nov 23, 2024
@willeastcott willeastcott self-assigned this Nov 23, 2024
@LeXXik
Copy link
Contributor

LeXXik commented Nov 25, 2024

I always welcome a constraints component, which I think was missing for a while. There are so many cases where it could be used for interactivity. However, I am not sure of the design. Not that it is wrong, but that there is no definite standard for it so far, so it is up to discussion.

For example, if the ball falling on the bridge disables an entity it touches, then I would expect the bridge would behave as if it would have been cut in the middle. However, that is not the case, since a constraint is its own entity and lives its own life. The bridge would probably fall apart with a constraint still alive that is very soft, like a chewing gum.

Also, I remember making a game for one company, where you would draw a wheel for a vehicle to traverse a terrain. Once you drew a wheel, it would replace the old one, which was connected with a hinge constraint. There was an Ammo crash, when PlayCanvas was trying to destroy a rigidbody (due to hierarchy change) before the constraint. There should be a test case to cover that at least.

@willeastcott
Copy link
Contributor Author

willeastcott commented Nov 25, 2024

@LeXXik The main things I'm still unsure of relate to the following:

  1. Should I collapse the X, Y, Z number properties into Vec3 properties? e.g. angularDampingX, angularDampingY and angularDampingZ becomes angularDamping. This will collapse the API into something much simpler, of course. But I'm wondering whether this might be annoying if you only are concerned with configuring a one or maybe two axes. Maybe there'd be other down sides I'm not considering?
  2. The current implementation just wraps the btGeneric6DofSpringConstraint. Ammo has specific classes for handling other joint types (like hinge, ball-socket, etc). I'm wondering if those specialized joint types are more stable than the generic 6dof joint.
  3. At the moment, it is assumed the joint component's entity is neither entityA or entityB (so you have to create a separate entity for joints). But should the JointComponent be placed on entityA and entityB would be connectedEntity perhaps? I could add jointOffset too (with reference to the owner entity's transform).

@Maksims
Copy link
Collaborator

Maksims commented Nov 26, 2024

I think join should be created on any entity, event on third one, and by defining entityA and entityB, which can be self, would work. Otherwise it might be too constraining to the user.
Also, it will make it easier to copy joints and re-use them between different rigidbodies.

* @type {number}
*/
set breakForce(force) {
if (this._constraint && this._breakForce !== force) {
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe this should follow other setters, where the internal value gets updated even if _constraint is null, and only the setBreakingImpulseThreshold does not get called

Comment on lines 624 to 626
this._destroyConstraint();
this._entityA = body;
this._createConstraint();
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the cost of destroying and creating them? If the component gets initially created, would this execute multiple times? For example in case

joint.addComponent('joint', {
            entityA: planks[i],
            entityB: planks[i + 1],
            enableCollision: false
        });

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a good point. When I refactor this stuff, I'll bypass the setters on component creation.

@willeastcott
Copy link
Contributor Author

willeastcott commented Nov 28, 2024

After building this PR, I came to a realization. You often want to attach multiple constraints to a single rigid body. For example, imagine the joints attached to the upper torso of a rag doll: neck, left shoulder, right shoulder, mid-spine. Therefore, on reflection, I think it would be better if the JointComponent worked similarly to the SoundComponent and supported multiple joints to be defined. So I will try to devise an addJoint/removeJoint type of API. Stay tuned for a full refactor.

@LeXXik
Copy link
Contributor

LeXXik commented Nov 28, 2024

I will try to devise an addJoint/removeJoint type of API

Yeah, I did it in a similar fashion here:
https://github.com/Gamebop/physics/blob/master/src/physics/jolt/front/constraint/component.mjs

Note - in my implementation, I do destroy a constraint connecting both bodies, when one of the bodies is destroyed. Because of that I also need to keep track of which joints connect which bodies. If one entity is connected to another, then both entities would get a constraint component. A constraint component in my case is not a joint in itself, but a host of different joints that can be added to a body.

@LeXXik
Copy link
Contributor

LeXXik commented Nov 28, 2024

Should I collapse the X, Y, Z number properties into Vec3 properties?

I use vectors in our implementation. I think the inspector in Editor would look cleaner as well.

The current implementation just wraps the btGeneric6DofSpringConstraint... I'm wondering if those specialized joint types are more stable than the generic 6dof joint.

Not sure. Bullet is using a base typed constraint for all its constraint types. 6dof is just one of its extended classes. I'd assume they would all work the same from stability point of view.

@Maksims
Copy link
Collaborator

Maksims commented Nov 28, 2024

After building this PR, I came to a realization. You often want to attach multiple constraints to a single rigid body. For example, imagine the joints attached to the upper torso of a rag doll: neck, left shoulder, right shoulder, mid-spine. Therefore, on reflection, I think it would be better if the JointComponent worked similarly to the SoundComponent and supported multiple joints to be defined. So I will try to devise an addJoint/removeJoint type of API. Stay tuned for a full refactor.

But why not use one joint per entity as I've suggested?
So that you create multiple Joint entities and reference needed entityA and entityB. Won't need to do complex API & UI like Sound Component. And it reduces the amount of API needed, and depth complexity of joint component.

Removing joint - destroy/disable entity, easy. But with array-based joint component it will require to use some other type of API like: entity.joints.remove(entity.joints.get(jointId)) - this does look overly complex.

Similarly the Compound collision component, uses children, instead of doing array of collision items within collision component.

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.

4 participants