I make further tests with ND4. As I posted on other topics, i have often strange asserts in ND4. Now I found a totally different reason, what could be wrong and its strange. I post my OgreNewt::World update code:
- Code: Select all
void World::flushDeferred()
{
std::vector<std::function<void()>> pending;
{
std::lock_guard<std::mutex> g(m_deferMutex);
pending.swap(m_deferred);
}
for (auto& fn : pending)
{
if (fn) fn();
}
}
void World::update(Ogre::Real t_step)
{
if (m_paused.load())
{
if (!m_doSingleStep.exchange(false))
return;
}
// clamp to avoid spiral-of-death
if (t_step > (m_fixedTimestep * m_maxTicksPerFrames))
t_step = m_fixedTimestep * m_maxTicksPerFrames;
m_timeAccumulator += t_step;
while (m_timeAccumulator >= m_fixedTimestep)
{
// 1) Kick the step (ndWorld::Update will first Sync with any *previous* step,
// then start this step asynchronously via TickOne()).
ndWorld::Update(static_cast<ndFloat32>(m_fixedTimestep)); // starts async work
// Causes weird asserts in ND4
// 2) Wait for the step we just started to finish -> this makes stepping synchronous.
// ndWorld::Sync();
// 3) (Optional) If you kept any deferral queue, you can flush immediately here,
// but with a purely synchronous model you won’t need deferral any more.
flushDeferred();
m_timeAccumulator -= m_fixedTimestep;
if (m_paused.load())
break;
}
const Ogre::Real interp = m_timeAccumulator * m_invFixedTimestep;
postUpdate(interp);
}
void World::postUpdate(Ogre::Real interp)
{
const ndBodyListView& bodyList = GetBodyList();
const ndArray<ndBodyKinematic*>& view = bodyList.GetView();
for (ndInt32 i = ndInt32(view.GetCount()) - 1; i >= 0; --i)
{
ndBodyKinematic* const ndBody = view[i];
if (!ndBody->GetSleepState())
{
if (auto* notify = ndBody->GetNotifyCallback())
{
if (auto* ogreNotify = dynamic_cast<BodyNotify*>(notify))
{
if (auto* ogreBody = ogreNotify->GetOgreNewtBody())
ogreBody->updateNode(interp);
}
}
}
}
}
void World::recover()
{
// Called from logic/render thread -> just schedule
this->deferAfterPhysics([this]()
{
this->recoverInternal();
});
}
void OgreNewt::World::recoverInternal()
{
const ndBodyListView& bodyList = GetBodyList();
const ndArray<ndBodyKinematic*>& view = bodyList.GetView();
for (ndInt32 i = ndInt32(view.GetCount()) - 1; i >= 0; --i)
{
ndBodyKinematic* const b = view[i];
if (!b || b == GetSentinelBody())
continue;
ndBodyDynamic* const dyn = b->GetAsBodyDynamic();
if (!dyn)
continue;
// mark the body/scene as dirty (invalidates contact cache & aabb)
// This is the ND4 way to say "something changed, don’t keep me asleep".
dyn->SetMatrixUpdateScene(b->GetMatrix());
// actually wake it
dyn->SetAutoSleep(true); // keep normal autosleep behavior
dyn->SetSleepState(false); // force out of equilibrium for the next step
}
}
So: I get the asserts if ndWorld::Sync() is set in the main loop. I documentated it out and the asserts are gone. I tested some of my more complex ND4 scenarios and they seem to work so far.
But in the ND4 ndDemoEntityManager this is set to true:
m_synchronousPhysicsUpdate = true;
Hence in your example:
- Code: Select all
void ndPhysicsWorld::AdvanceTime(ndFloat32 timestep)
{
D_TRACKTIME();
const ndFloat32 descreteStep = (1.0f / MAX_PHYSICS_FPS);
if (m_acceleratedUpdate)
{
Update(descreteStep);
RemoveDeadEntities();
}
else
{
ndInt32 maxSteps = MAX_PHYSICS_STEPS;
m_timeAccumulator += timestep;
// if the time step is more than max timestep par frame, throw away the extra steps.
if (m_timeAccumulator > descreteStep * (ndFloat32)maxSteps)
{
ndFloat32 steps = ndFloor(m_timeAccumulator / descreteStep) - (ndFloat32)maxSteps;
ndAssert(steps >= 0.0f);
m_timeAccumulator -= descreteStep * steps;
}
while (m_timeAccumulator > descreteStep)
{
Update(descreteStep);
m_timeAccumulator -= descreteStep;
RemoveDeadEntities();
}
}
{
ndScopeSpinLock Lock(m_lock);
ndFloat32 param = m_timeAccumulator / descreteStep;
m_manager->m_renderer->InterpolateTransforms(param);
}
if (m_manager->m_synchronousPhysicsUpdate)
{
Sync();
}
}
So what is going on? Or is my Physics updates loop wrong? I have no idea what is right or wrong. I orientated on the old OgreNewt3 (ND3) code and added the peaces for ND4. Also I have to use deffered functions. For example: I have a Leveleditor (NOWA-Design). I press the play button -> OgreNewt4 starts running. Loop is processed. Then I press the stop button. OgreNewt4 stops. Then i call recover(). I found out it must be called in a seperate step, after ND4 has processed everything.
Perhaps you can shed some light on the matter.
Thanks!
Best Regards
Lax


