So setting velocities in a system that runs between BuildPhysicsWorld and StepPhysicsWorld ends up with velocities being overwritten. Quick glance it looks like motion datas are setup in BuildPhysicsWorld and that’s likely the issue. Is that the case or something else I’m missing?
ExportPhysicsWorld is the system that writes back to the PhysicsVelocity components. You should set velocities either before BuildPhysicsWorld or after ExportPhysicsWorld.
I don’t think there is really a set way of doing things here. Both of your suggestions have pretty big caveats that might or might not matter depending on the game. Run your logic before BuildPhysicsWorld and any significant amount of work will stall the main thread. After export and you are now a frame behind. Throw in interpolation and two frames.
Between build and step is better in several ways. BVH is up to date, BuildPhysicsWorld won’t force complete your work, and it’s before export so immediately visible to gamelogic later in simulation.
protected override void OnUpdate()
{
Dependency = JobHandle.CombineDependencies(m_BuildPhysicsWorldSystem.GetOutputDependency(), Dependency);
float timeStep = Time.DeltaTime;
Entities
.WithAll<Car>()
.ForEach((ref CarNative carNative) =>
{
Native.CX_ProcessCar(carNative.Value, timeStep, math.rcp(timeStep));
})
.ScheduleParallel();
SimulationCallbacks.Callback applyImpulsesCallback = (ref ISimulation simulation, ref PhysicsWorld world, JobHandle inDeps) =>
{
return new ApplyImpulsesJob
{
EntityType = GetEntityTypeHandle(),
NativeCarType = GetComponentTypeHandle<CarNative>(true),
World = world
}
.ScheduleParallel(m_CarsQuery, inDeps);
};
m_StepPhysicsWorld.EnqueueCallback(SimulationCallbacks.Phase.PostSolveJacobians, applyImpulsesCallback, Dependency);
}
[BurstCompile]
struct ApplyImpulsesJob : IJobChunk
{
[ReadOnly] public EntityTypeHandle EntityType;
[ReadOnly] public ComponentTypeHandle<CarNative> NativeCarType;
public PhysicsWorld World;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
{
var entities = chunk.GetNativeArray(EntityType);
var chunkNativeCars = chunk.GetNativeArray(NativeCarType);
for (var i = 0; i < chunk.Count; i++)
{
Native.CX_CarGetTotals(chunkNativeCars[i].Value, out var linearImpulse, out var angularImpulse);
int rigidBodyIndex = World.GetRigidBodyIndex(entities[i]);
if (rigidBodyIndex != - 1 && rigidBodyIndex < World.NumDynamicBodies)
{
MotionData md = World.MotionDatas[rigidBodyIndex];
float3 angularImpulseInertiaSpace = math.rotate(math.inverse(md.WorldFromMotion.rot), angularImpulse);
var motionVelocities = World.MotionVelocities;
MotionVelocity mv = motionVelocities[rigidBodyIndex];
mv.ApplyLinearImpulse(linearImpulse);
mv.ApplyAngularImpulse(angularImpulseInertiaSpace);
motionVelocities[rigidBodyIndex] = mv;
}
}
}
}
but this method is not supported by hawok
That makes me wonder if there is a reason to not just set the motion data before StepPhysicsWorld. That fits the actual flow I have better although the above would definitely work.
Yeah, Havok syncs the velocities after BuildPhysicsWorld and writes back to them as part of the StepPhysicsWorld (at the very end). So in post solve callback you can’t really change motion velocities because that’s not seen by Havok and it will be overwritten.
There is a good reason for not touching motion data before step and after build - BVH is built with velocities in mind, changing them afterwards can result in contact pairs not being detected and tunneling/penetration. The correct place to change velocities is after step and before build. Unfortunately that’s the full list of safe places at the moment.
Did not realize that good to know.