I recently started playing around with Bepu and, coming from PhysX, I have to say, the API so far is really easy to understand and use.
At least for the more simple tests I did so far I could implement them without any problems by just looking at one or two demos.
But when it comes to implementing conveyor belt like objects I'm running into some issues. I am aware that there are already a few questions regarding conveyors in the forum, so I am already aware of the following solutions:
1. Set a velocity but reset the position every frame
Problem: While that actually works great it still feels kind of hacky to me and in a scenario where I want to simulate a large amount of conveyors, iterating over every Body that I want to act this way, this seems to me to become a potential performance issue.
On the upside, the results should be pretty realistic since it kind of accurately simulates a moving surface.
2. Modifying contacts
The other solution is something I already successfully implemented in PhysX but can't really get to work in Bepu. At least not properly.
I added an additional Property called SurfaceVelocity to BodyReference (and the corresponding Buffer in BodySet) and a HasSurfaceVelocity flag that gets set when the linear SurfaceVelocity vector has a length >0 (Since I have to check this every frame for every conveyor but only change the actual SurfaceVelocity ever so often this should be faster then recalculating all the vector lengths every frame).
Thanks to the NarrowPhaseCallback it is super easy to get access to the generated contacts. So in the ConfigureContactManifold callback I try to figure out which body of the pair is the conveyor and which one is the item carried by it. This is relatively easy since conveyors in my case are always kinematic and the items always dynamic.
I then iterate all the contacts, check if the kinematic body has a SurfaceVelocity and if it does, apply an impulse to my item in the direction of the SurfaceVelocity vector (and hopefully at the location of the contact. I'm not so sure about that with the current implementation). In PhysX I had the ability to set a target velocity on a contact and then the solver did the rest. I do no seem to have this ability in Bepu hence the approach with the impulse.
Code: Select all
public bool ConfigureContactManifold<TManifold>(int workerIndex, CollidablePair pair, ref TManifold manifold, out PairMaterialProperties pairMaterial) where TManifold : struct, IContactManifold<TManifold>
{
pairMaterial.FrictionCoefficient = 0.5f;
pairMaterial.MaximumRecoveryVelocity = 2f;
pairMaterial.SpringSettings = new SpringSettings(1, 1.0f);
CollidableReference dynamicCollider, kinematicCollider;
if (pair.A.Mobility == CollidableMobility.Kinematic && pair.B.Mobility != CollidableMobility.Kinematic)
{
dynamicCollider = pair.B;
kinematicCollider = pair.A;
}
else if (pair.B.Mobility == CollidableMobility.Kinematic && pair.A.Mobility != CollidableMobility.Kinematic)
{
dynamicCollider = pair.A;
kinematicCollider = pair.B;
}
else
return true;
BodyReference kinematicBody, dynamicBody;
BodyDescription description;
for (int i = 0; i < manifold.Count; i++)
{
kinematicBody = Simulation.Bodies.GetBodyReference(kinematicCollider.Handle);
kinematicBody.GetDescription(out description);
if (description.HasSurfaceVelocity)
{
dynamicBody = Simulation.Bodies.GetBodyReference(dynamicCollider.Handle);
manifold.GetContact(i, out Vector3 offset, out Vector3 normal, out float depth, out int featureId);
dynamicBody.ApplyImpulse(description.SurfaceVelocity.Linear, dynamicBody.Pose.Position + offset);
dynamicBody.Awake = true;
//dynamicBody.Velocity.Linear = (description.SurfaceVelocity.Linear);
}
}
return true;
}
Now this works to a degree but comes with some issues/questions.
1. First of all, I can't find a SurfaceVelocity vector that moves the items at a correct speed. It either fires them off way too fast or doesn't move them at all. I tried different values for the sleep behaviour as well as friction/springsettings etc. but with no changes in the conveying speed. Any idea what I could do to fix this
2. Secondly, is there something I'm missing here? Is there a generally better approach? Maybe Solution 1 is not as bad as I think it is?
3. Is expanding the BodyReference struct / the BodySet Buffers to add my SurfaceVelocity property a good idea? Do I impact the performance of accessing the other buffers by shifting the layout? Are there better approaches? In PhysX every body had a void* that I could attach any data I wanted to and had access to in various callbacks. Didn't exactly help code readability and/or type safety but got the job done.
(Additional question:
Talking about the buffer layout in BodySet. The comment on top of the struct says the body information is stored in AOS format. It looks more like SOA to me, though. I'm not exactly an expert here so I might be misinterpreting it, just curious if the comment is wrong or I am.
Not really related to my main question, just sneaking it in)
Thanks already in advance.
From what I've seen so far this is a really great physics library and I can't even imagine all the effort put into it by just one single person.
Very well done!
alektron