Fixed timestep graphics jitter
3. Srpen 2024 v 13:10
I'm trying to implement the https://gafferongames.com/post/fix_your_timestep article but I have jitter on the position interpolation.
I have the following PhysX manager class update method :
const float fixedTimeStep = 1.0f / 60.0f; // 60Hz
float deltaTime = TimeManager::GetInstance()->DeltaTimeF();
if (deltaTime > 0.25f)
deltaTime = 0.25f;
accumulator += deltaTime;
static std::unordered_map<PxRigidDynamic*, PhysXState> statesBefore{};
static std::unordered_map<PxRigidDynamic*, PhysXState> statesAfter{};
if (statesBefore.empty()) {
RetrieveCurrentState(statesBefore);
RetrieveCurrentState(statesAfter);
}
while (accumulator >= fixedTimeStep)
{
statesBefore = statesAfter;
mScene->simulate(fixedTimeStep, nullptr, GSimulateScratchMemory, GSimulateScratchMemorySize);
accumulator = std::max(accumulator - fixedTimeStep, 0.f);
mScene->fetchResults(true);
RetrieveCurrentState(statesAfter);
}
// Calculate the interpolation factor for rendering
float alpha = accumulator / fixedTimeStep;
for (const auto& [body, stateBefore] : statesBefore) {
if (statesAfter.find(body) != statesAfter.end()) {
const auto& stateAfter = statesAfter.at(body);
PhysXState interpolatedState{};
InterpolateStates(stateBefore, stateAfter, alpha, interpolatedState);
// Update the interpolated state in the body userptr moveable body
auto userPtr = static_cast<CollisionParam*>(body->userData);
if (userPtr && userPtr->Body) {
userPtr->Body->SetInterpolatedState(interpolatedState);
}
}
}
This is how I retrieve the current state:
void RetrieveCurrentState(std::unordered_map<PxRigidDynamic*, PhysXState>& states) {
states.clear();
for (auto rigidBody : mRigidBodies) {
PhysXState state;
physx::PxTransform transform = rigidBody->getGlobalPose();
state.Position = glm::vec3(transform.p.x, transform.p.y, transform.p.z);
state.Orientation = glm::quat(transform.q.w, transform.q.x, transform.q.y, transform.q.z);
physx::PxVec3 linearVelocity = rigidBody->getLinearVelocity();
state.Velocity = glm::vec3(linearVelocity.x, linearVelocity.y, linearVelocity.z);
physx::PxVec3 angularVelocity = rigidBody->getAngularVelocity();
state.AngularVelocity = glm::vec3(angularVelocity.x, angularVelocity.y, angularVelocity.z);
states[rigidBody] = state;
}
}
And here is how I interpolate:
void InterpolateStates(const PhysXState& previous, const PhysXState& current, float alpha, PhysXState& interpolated)
{
interpolated.Position = glm::mix(previous.Position, current.Position, alpha);
interpolated.Orientation = glm::slerp(previous.Orientation, current.Orientation, alpha);
interpolated.Velocity = glm::mix(previous.Velocity, current.Velocity, alpha);
interpolated.AngularVelocity = glm::mix(previous.AngularVelocity, current.AngularVelocity, alpha);
}
Finally here is how I retrieve the interpolated position (currently using only the position as a test phase) to feed it into the graphics module:
prop.Transform.setLocalPosition(prop.MoveableBody->GetInterpolatedPosition());
What could be wrong and the movement is shaky/jittery ? Let me know if you need to see more code.