MADEAPPS / newton-dynamics

Newton Dynamics is an integrated solution for real time simulation of physics environments.
http://www.newtondynamics.com
Other
936 stars 182 forks source link

4.0 Assert ndQuaternion #257

Closed kklouzal closed 2 years ago

kklouzal commented 2 years ago

image Getting this assert when trying to set matrix.m_posit to a value greater than +- 50 on either x y or z axis.

Followed basic 'Test' app for physics setup. Not sure where to being troubleshooting this one..

ndShapeInstance shape(new ndShapeBox(1.0f,1.0f,1.0f));

    dMatrix matrix(dGetIdentityMatrix());
    matrix.m_posit = dVector(0.0f, 60.0f, 0.0f, 1.0f);

    ndBodyDynamic* const body2 = new ndBodyDynamic();

    body2->SetNotifyCallback(new NewtonEntityNotify(MeshNode));
    body2->SetMatrix(matrix);
    body2->SetCollisionShape(shape);
    body2->SetMassMatrix(10.0f, shape);

    _Driver->_ndWorld->AddBody(body2);

Runs fine changing 60 to 50...

kklouzal commented 2 years ago

Pinned it down to this function inside my ndBodyNotify class:

    virtual void OnApplyExternalForce(dInt32 threadIndex, dFloat32 timestep)
    {
        ndBodyDynamic* const dynamicBody = GetBody()->GetAsBodyDynamic();
        if (dynamicBody)
        {
            dVector massMatrix(dynamicBody->GetMassMatrix());
            dVector force(dVector(0.0f, -10.0f, 0.0f, 0.0f).Scale(massMatrix.m_w));
            //dynamicBody->SetForce(force);
            dynamicBody->SetTorque(dVector::m_zero);
        }
    }

Uncommenting dynamicBody->SetForce(force); trips the assert. Is this perhaps a race condition?

kklouzal commented 2 years ago

call stack:

ndNewton_d.dll!dQuaternion::dQuaternion(const dVector & unitAxis, float angle) Line 95 C++ ndNewton_d.dll!ndBodyKinematic::IntegrateVelocity(float timestep) Line 431 C++ ndNewton_d.dll!ndBodyDynamic::IntegrateVelocity(float timestep) Line 287 C++ ndNewton_d.dll!ndDynamicsUpdate::IntegrateBodies'::2'::ndIntegrateBodies::Execute() Line 1362 C++ ndNewton_d.dll!dThreadPool::ExecuteJobs(dThreadPoolJob const jobs) Line 147 C++ ndNewton_d.dll!ndScene::SubmitJobs<ndDynamicsUpdate::IntegrateBodies'::2'::ndIntegrateBodies>(void * const context) Line 262 C++ ndNewton_d.dll!ndDynamicsUpdate::IntegrateBodies() Line 1380 C++ ndNewton_d.dll!ndDynamicsUpdate::Update() Line 2033 C++ ndNewton_d.dll!ndWorld::SubStepUpdate(float timestep) Line 560 C++ ndNewton_d.dll!ndWorld::ThreadFunction() Line 476 C++ ndNewton_d.dll!ndWorldDefaultScene::ThreadFunction() Line 54 C++ ndNewton_d.dll!dThread::ThreadFunctionCallback() Line 111 C++ [External Code]

using code commit https://github.com/MADEAPPS/newton-dynamics/commit/3a9dec636e54ad75b1a3f14465d35e8078ec5173

JulioJerez commented 2 years ago

That should not happen, position and rotation are independent, and not I do not think that's a race condition. is this in the Test cpp or something you write based on that.

kklouzal commented 2 years ago

This is in something I have written based off of test cpp.

The demo sandbox has way way too much going on to try and understand how to implement the library. Need a more basic set of examples to learn how to use the library so I learned what I could from test.

kklouzal commented 2 years ago

After further trial and error I have pinned down the direct cause being the value passed into ndWorld.Update() Too high or too low a value seems to throw this assert. Could be clamped to work around the problem but not sure what the min/max value can be here..

kklouzal commented 2 years ago

For your reference, I finally got the world stable with this main loop... Not sure but I may be calculating delta frame time incorrectly.. Physics simulation feels like it might be a little slow..

std::chrono::time_point<std::chrono::steady_clock> startFrame = std::chrono::high_resolution_clock::now();
std::chrono::time_point<std::chrono::steady_clock> endFrame = std::chrono::high_resolution_clock::now();
float deltaFrame = 0;
std::deque<float> Frames;

void PushFrameDelta(const float F) {
    Frames.push_back(F);
    if (Frames.size() > 30) {
        Frames.pop_front();
    }
}

const float GetDeltaFrames() const {
    float DF = 0;
    for (auto &F : Frames) {
        DF += F;
    }
    return DF / Frames.size();
}

void VulkanDriver::mainLoop() {
    while (!glfwWindowShouldClose(_Window)) {
        //
        //  Mark Frame Start Time and Calculate Previous Frame Statistics
        startFrame = std::chrono::high_resolution_clock::now();
        float DF = GetDeltaFrames();
        float FPS = (1.0f / DF);

        if (_EventReceiver) {
            _EventReceiver->_ConsoleMenu->SetStatusText(Gwen::Utility::Format(L"Stats (60 Frame Average) - FPS: %f - Frame Time: %f - Physics Time: %f - Scene Nodes: %i", FPS, DF, _ndWorld->GetUpdateTime(), _SceneGraph->SceneNodes.size()));
        }
        //
        //  Handle Inputs
        glfwPollEvents();
        //
        //  Perform Inputs
        _EventReceiver->OnUpdate();
        //
        //  Simulate Physics
        //_ndWorld->Update(deltaFrame/1000.0f);
        printf("Dela A %f B %f\n", deltaFrame, 1.0f/60.0f);
        _ndWorld->Update(DF);
        //
        //  Update Shader Uniforms
        updateUniformBufferOffscreen(currentFrame);
        updateUniformBufferComposition(currentFrame);
        _SceneGraph->updateUniformBuffer(currentFrame);
        //
        //  Draw Frame
        Render();
        //
        //  Mark Frame End Time and Calculate Delta
        endFrame = std::chrono::high_resolution_clock::now();
        deltaFrame = std::chrono::duration<double, std::milli>(endFrame - startFrame).count()/1000.f;
        PushFrameDelta(deltaFrame);
    }
    //
    //  Wait for idle before shutting down
    vkDeviceWaitIdle(_VulkanDevice->logicalDevice);
}

Any suggestions here?

kklouzal commented 2 years ago

More information.. Adding more substeps to the simulation also decreases the likelihood that this assert will trip. Setting 2 substeps with my current main loop trips the assert again.. 3 substeps seems fine for now but the more substeps you have the more processing that is required..

JulioJerez commented 2 years ago

try sync again this was generate by a debug code committed by mistake.

kklouzal commented 2 years ago

Pulled latest source, still tripping this assert. Seems to be directly related to the timestep and amount of substeps. image

>   ndNewton_d.dll!ndQuaternion::ndQuaternion(const ndVector & unitAxis, float angle) Line 95   C++
    ndNewton_d.dll!ndBodyKinematic::IntegrateVelocity(float timestep) Line 431  C++
    ndNewton_d.dll!ndBodyPlayerCapsule::ResolveInterpenetrations(ndBodyPlayerCapsuleContactSolver & contactSolver, ndBodyPlayerCapsuleImpulseSolver & impulseSolver) Line 460   C++
    ndNewton_d.dll!ndBodyPlayerCapsule::ResolveCollision(ndBodyPlayerCapsuleContactSolver & contactSolver, float timestep) Line 490 C++
    ndNewton_d.dll!ndBodyPlayerCapsule::IntegrateExternalForce(float timestep) Line 801 C++
    ndNewton_d.dll!`ndDynamicsUpdate::IntegrateUnconstrainedBodies'::`2'::ndIntegrateUnconstrainedBodies::Execute() Line 708    C++
    ndNewton_d.dll!ndThreadPool::ExecuteJobs(ndThreadPoolJob * * const jobs) Line 147   C++
    ndNewton_d.dll!ndScene::SubmitJobs<`ndDynamicsUpdate::IntegrateUnconstrainedBodies'::`2'::ndIntegrateUnconstrainedBodies>(void * const context) Line 262    C++
    ndNewton_d.dll!ndDynamicsUpdate::IntegrateUnconstrainedBodies() Line 718    C++
    ndNewton_d.dll!ndDynamicsUpdate::Update() Line 2022 C++
    ndNewton_d.dll!ndWorld::SubStepUpdate(float timestep) Line 560  C++
    ndNewton_d.dll!ndWorld::ThreadFunction() Line 476   C++
    ndNewton_d.dll!ndWorldDefaultScene::ThreadFunction() Line 54    C++
    ndNewton_d.dll!ndThread::ThreadFunctionCallback() Line 111  C++

Also a new one: image

>   ndNewton_d.dll!ndMatrix::TestOrthogonal(float tol) Line 289 C++
    ndNewton_d.dll!ndBodyKinematic::IntegrateVelocity(float timestep) Line 437  C++
    ndNewton_d.dll!ndBodyDynamic::IntegrateVelocity(float timestep) Line 287    C++
    ndNewton_d.dll!`ndDynamicsUpdate::IntegrateBodies'::`2'::ndIntegrateBodies::Execute() Line 1362 C++
    ndNewton_d.dll!ndThreadPool::ndThreadLockFreeUpdate::Execute() Line 38  C++
    ndNewton_d.dll!ndThreadPool::ndWorkerThread::ThreadFunction() Line 65   C++
    ndNewton_d.dll!ndThread::ThreadFunctionCallback() Line 111  C++
JulioJerez commented 2 years ago

you have two different kind of code here, some that seems the player capsule, and some relate to time step. is this happening on that test demo in the download?

kklouzal commented 2 years ago

It looks like you fixed the original reason why this assert was being called. Now the issue has migrated into the callstack dealing with player capsule. Like before it only happens when I use a variable timestep OR if a dynamicBody comes in contact with my kinematicBody character controller. The character controller can touch static mesh fine, but touch dynamic body and trips assert.

JulioJerez commented 2 years ago

oh I see, it comes from player capsule. I saw it. the crash bug is fixed now.

This was part of the problems of preparing the solve for GPU. what happen in the function integrate body is virtual. and I need to make non virtual so that I can call it form GPU. I removed it from the kinematic body, but the player capsule is now calling.

It is working now but is not correct because player code is moving the body, but also the solver and that is no correct. latter I have to make a special version of ndBodyKinematic::IntegrateVelocity(timestep) for the player.

but for now, is working and you probably won't notice the difference.

please sync again.

kklouzal commented 2 years ago

Looks like everything is running fine now without any asserts. great job! and thank you very much! :)