Help with determinism

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

Help with determinism

Postby Cannos » Tue Jun 01, 2010 11:09 pm

I have a very simple test case that I can't get to replay deterministically. Here is the code for the sample:

Code: Select all
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <Newton.h>
#include <stdio.h>

NewtonWorld* gNewtonWorld = NULL;
const int numPushes = 4;
float resultMatrices[numPushes + 1][16];
bool firstPlay = true;
const float updateStep = 1.0f / 60.0f;
float vel[3] = {5.0f, 0.0f, 0.0f};
float zero[3] = { 0.0f, 0.0f, 0.0f };

////////////////////////////////////////////////////////////////////////////////
void initPhysicsWorld()
{
    gNewtonWorld = NewtonCreate();

    NewtonSetPlatformArchitecture(gNewtonWorld, 0);
    NewtonSetThreadsCount(gNewtonWorld, 1);
    NewtonSetSolverModel(gNewtonWorld, 1);
    //NewtonSetFrictionModel(gNewtonWorld, 0);
 
    // set an initial world size
    float worldMin[3] = { -500.0f,-500.0f,-500.0f };
    float worldMax[3] = { 500.0f,500.0f,500.0f };
    NewtonSetWorldSize(gNewtonWorld, worldMin, worldMax);

    NewtonInvalidateCache(gNewtonWorld);
}

////////////////////////////////////////////////////////////////////////////////
void destroyPhysicsWorld()
{
    if (gNewtonWorld)
    {
        NewtonDestroyAllBodies(gNewtonWorld);
        NewtonDestroy(gNewtonWorld);
        gNewtonWorld = NULL;
    }
}

////////////////////////////////////////////////////////////////////////////////
void applyForceAndTorqueCallback(const NewtonBody* body, float timestep, int threadIndex)
{
    // Get mass / inertia of body
    dFloat Ixx;
    dFloat Iyy;
    dFloat Izz;
    dFloat mass;
    NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);

    // Apply gravity force
    #define GRAVITY -10.0f
    float gravityForce[3] = { 0.0f, mass * GRAVITY, 0.0f };
    NewtonBodySetForce(body, gravityForce);
}

////////////////////////////////////////////////////////////////////////////////
NewtonBody* addRigidBodyToWorld(NewtonCollision* shape, float mtx[16], float mass)
{
    // Create body
    NewtonBody* pRB = NewtonCreateBody(gNewtonWorld, shape);
    NewtonBodySetMatrix(pRB, mtx);

    // Calculate / set inertia and center of mass
    float inertia[3];
    float origin[3] = {0, 0, 0};
    NewtonConvexCollisionCalculateInertialMatrix(shape, inertia, origin);
    NewtonBodySetMassMatrix(pRB, mass, mass * inertia[0], mass * inertia[1], mass * inertia[2]);
    NewtonBodySetCentreOfMass(pRB, origin);
   
    // Set force and transform callbacks
    NewtonBodySetForceAndTorqueCallback(pRB, applyForceAndTorqueCallback);
    //NewtonBodySetTransformCallback(pRB, setTransformCallback);

    return pRB;
}

////////////////////////////////////////////////////////////////////////////////
NewtonBody* gDynBody = NULL;
void addBodies()
{
    // Add static ground body
    int groundID = 0;
    float groundOffsetMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float groundMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float groundMass = 0.0f;

    // Create a tree collision shape with a grid of faces at height 0.5
    NewtonCollision* pGroundShape = NewtonCreateTreeCollision(gNewtonWorld, 0);
    NewtonTreeCollisionBeginBuild(pGroundShape);

    float x0z0[3] = {0.0f, 0.5f, 0.0f};
    int numXQuads = 10;
    int numZQuads = 10;
    float xInc = 50.0f / float(numXQuads);
    float zInc = 50.0f / float(numZQuads);

    for (int i = 0; i < numXQuads; i++)
    {
        for (int j = 0; j < numZQuads; j++)
        {
            float startPt[3] = {x0z0[0] + xInc * i, x0z0[1], x0z0[2] + zInc * j};
            float faceVerts[6][3];
            faceVerts[0][0] = startPt[0];
            faceVerts[0][1] = startPt[1];
            faceVerts[0][2] = startPt[2];
            faceVerts[1][0] = startPt[0];
            faceVerts[1][1] = startPt[1];
            faceVerts[1][2] = startPt[2] + zInc;
            faceVerts[2][0] = startPt[0] + xInc;
            faceVerts[2][1] = startPt[1];
            faceVerts[2][2] = startPt[2];
            faceVerts[3][0] = startPt[0];
            faceVerts[3][1] = startPt[1];
            faceVerts[3][2] = startPt[2] + zInc;
            faceVerts[4][0] = startPt[0] + xInc;
            faceVerts[4][1] = startPt[1];
            faceVerts[4][2] = startPt[2] + zInc;
            faceVerts[5][0] = startPt[0] + xInc;
            faceVerts[5][1] = startPt[1];
            faceVerts[5][2] = startPt[2];
            NewtonTreeCollisionAddFace(pGroundShape, 6, &(faceVerts[0][0]), 12, 0);
        }
    }
    NewtonTreeCollisionEndBuild(pGroundShape, 0);

    addRigidBodyToWorld(pGroundShape, groundMtx, groundMass);

    NewtonReleaseCollision(gNewtonWorld, pGroundShape);

    // Create dynamic cylinder to move along ground
    int dynID = 1;
    float dynOffsetMtx[16] = {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float dynMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.5, 2.0, 5.0, 1};
    float dynMass = 1.0f;

    NewtonCollision* pDynShape = NewtonCreateChamferCylinder(gNewtonWorld, 0.5, 0.1f, dynID, dynOffsetMtx);
    gDynBody = addRigidBodyToWorld(pDynShape, dynMtx, dynMass);
    NewtonReleaseCollision(gNewtonWorld, pDynShape);
}

////////////////////////////////////////////////////////////////////////////////
void printResults(int pushIndex, float mtx[], bool inSync)
{
    // Print out results
    switch (pushIndex)
    {
        case 0:
            printf("Initial - ");
            break;
        case 1:
        case 2:
        case 3:
        case 4:
            printf("After %d - ", pushIndex);
            break;
    }
    printf("%f %f %f", mtx[12], mtx[13], mtx[14]);
    if (!firstPlay)
    {
        if (inSync)
            printf(" --> In Sync\n");
        else
            printf(" --> OUT OF SYNC\n");
    }
    else
        printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
void applyVelocity()
{
    NewtonInvalidateCache(gNewtonWorld);

    NewtonBodySetVelocity(gDynBody, vel);
    NewtonBodySetOmega(gDynBody, zero);
    NewtonBodySetForce(gDynBody, zero);
    NewtonBodySetTorque(gDynBody, zero);
}

////////////////////////////////////////////////////////////////////////////////
void replay(int pushIndex)
{
    while (1)
    {
        // Update
        NewtonUpdate(gNewtonWorld, updateStep);

        // When the body goes to sleep, check resulting matrix and apply new velocity
        int sleepState = NewtonBodyGetSleepState(gDynBody);
        if (sleepState == 1)
        {
            // Get body matrix
            float mtx[16];
            NewtonBodyGetMatrix(gDynBody, mtx);

            // If this is the first playthrough, copy these matrices to check against
            bool inSync = true;
            if (firstPlay)
            {
                memcpy(resultMatrices[pushIndex], mtx, 64);
            }
            // Otherwise, compare the result against the stored matrix
            else
            {
                int compareResult = memcmp(resultMatrices[pushIndex], mtx, 64);
                if (compareResult != 0)
                {
                    inSync = false;
                }
            }

            // Print out results
            printResults(pushIndex, mtx, inSync);

            // Apply new velocity if this isn't the last step
            if (pushIndex < numPushes)
            {
                applyVelocity();
                pushIndex++;
            }
            // Otherwise, break out of the update loop
            else
            {
                break;
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
void setupStep(int stepIndex)
{
    NewtonInvalidateCache(gNewtonWorld);

    // Set body matrix, velocity, omega as prior to step 'stepIndex'
    NewtonBodySetMatrix(gDynBody, resultMatrices[stepIndex]);
    NewtonBodySetVelocity(gDynBody, zero);
    NewtonBodySetOmega(gDynBody, zero);
    NewtonBodySetForce(gDynBody, zero);
    NewtonBodySetTorque(gDynBody, zero);
}

////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
    // Create world
    initPhysicsWorld();

    // Add bodies
    addBodies();

    // Play
    printf("First playthrough\n");
    replay(0);
    firstPlay = false;

    // Replay all
    printf("\nReplay all\n");
    setupStep(0);
    replay(0);

    // Replay 1-4
    printf("\nReplay 1-4\n");
    setupStep(1);
    replay(1);

    // Replay 2-4
    printf("\nReplay 2-4\n");
    setupStep(2);
    replay(2);

    // Replay 3-4
    printf("\nReplay 3-4\n");
    setupStep(3);
    replay(3);

    // Replay all
    printf("\nReplay all\n");
    setupStep(0);
    replay(0);

    // Destroy world
    destroyPhysicsWorld();

    return 1;
}


Basically, I have a dynamic cylinder on a static ground plane. I set its velocity up to 4 times, letting it come to rest between each apply. I am trying to set this up so I can replay the simulation starting from any of the 4 steps (i.e. replay steps 1-4 or 2-4 or 3-4 or 4).

I invalidate the cache before applying velocity each time and when doing initial replay setup. I also zero out omega, force, and torque. This is probably overkill, but I've been trying to initialize everything to get this to work. If I replay all the steps, everything stays in sync. But if I try to replay from anywhere except the beginning, the results are out of sync. Here is what the output of the sample looks like:

Code: Select all
First playthrough
Initial - 19.500000 0.548797 5.000444
After 1 - 21.880404 0.549709 5.000778
After 2 - 24.215870 0.549703 5.000858
After 3 - 26.592001 0.549906 5.001819
After 4 - 28.927483 0.549904 5.001032

Replay all
Initial - 19.500000 0.548797 5.000444 --> In Sync
After 1 - 21.880404 0.549709 5.000778 --> In Sync
After 2 - 24.215870 0.549703 5.000858 --> In Sync
After 3 - 26.592001 0.549906 5.001819 --> In Sync
After 4 - 28.927483 0.549904 5.001032 --> In Sync

Replay 1-4
After 1 - 21.880404 0.549709 5.000778 --> In Sync
After 2 - 24.215881 0.549698 5.000827 --> OUT OF SYNC
After 3 - 26.648815 0.549774 4.985289 --> OUT OF SYNC
After 4 - 28.984291 0.549760 4.985436 --> OUT OF SYNC

Replay 2-4
After 2 - 24.215870 0.549703 5.000858 --> In Sync
After 3 - 26.572697 0.549863 5.000514 --> OUT OF SYNC
After 4 - 28.938858 0.549811 5.001200 --> OUT OF SYNC

Replay 3-4
After 3 - 26.592001 0.549906 5.001819 --> In Sync
After 4 - 28.927486 0.549885 5.000540 --> OUT OF SYNC

Replay all
Initial - 19.500000 0.548797 5.000444 --> In Sync
After 1 - 21.880404 0.549709 5.000778 --> In Sync
After 2 - 24.215870 0.549703 5.000858 --> In Sync
After 3 - 26.592001 0.549906 5.001819 --> In Sync
After 4 - 28.927483 0.549904 5.001032 --> In Sync


If anyone can give me a hint at what may not be set up properly, it would help a ton. The code is pretty simple so hopefully someone can try it out or look at it and spot something. Thanks.
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby Cannos » Wed Jun 02, 2010 12:57 pm

On a hunch I decided to replace my collision tree with a simple box and everything appears to stay in sync. I don't know if this is a bug in the collision tree or in how I have set it up. I am on version 2.15 of Newton. I see there have been some recent fixes for collision trees, might this determinism problem be fixed in a more recent version?
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby JernejL » Wed Jun 02, 2010 1:25 pm

It is very likely, and you should move to newest version to make it easier to debug anyway.
Help improving the Newton Game Dynamics WIKI
User avatar
JernejL
 
Posts: 1587
Joined: Mon Dec 06, 2004 2:00 pm
Location: Slovenia

Re: Help with determinism

Postby Cannos » Wed Jun 02, 2010 3:33 pm

Okay I tried it again with 2.21. It still goes out of sync if replayed from step 2 or later. Here's the test output:

Code: Select all
First playthrough
Initial - 19.500000 0.548809 4.999766
After 1 - 21.838936 0.549238 5.001026
After 2 - 24.182217 0.549299 5.001021
After 3 - 26.539658 0.549453 5.000971
After 4 - 28.880611 0.549393 5.000488

Replay all
Initial - 19.500000 0.548809 4.999766 --> In Sync
After 1 - 21.838936 0.549238 5.001026 --> In Sync
After 2 - 24.182217 0.549299 5.001021 --> In Sync
After 3 - 26.539658 0.549453 5.000971 --> In Sync
After 4 - 28.880611 0.549393 5.000488 --> In Sync

Replay 1-4
After 1 - 21.838936 0.549238 5.001026 --> In Sync
After 2 - 24.182217 0.549299 5.001021 --> In Sync
After 3 - 26.539658 0.549453 5.000971 --> In Sync
After 4 - 28.880611 0.549393 5.000488 --> In Sync

Replay 2-4
After 2 - 24.182217 0.549299 5.001021 --> In Sync
After 3 - 26.580683 0.549442 5.001246 --> OUT OF SYNC
After 4 - 28.916235 0.549389 5.001592 --> OUT OF SYNC

Replay 3-4
After 3 - 26.539658 0.549453 5.000971 --> In Sync
After 4 - 28.881058 0.549378 5.000821 --> OUT OF SYNC

Replay all
Initial - 19.500000 0.548809 4.999766 --> In Sync
After 1 - 21.838936 0.549238 5.001026 --> In Sync
After 2 - 24.182217 0.549299 5.001021 --> In Sync
After 3 - 26.539658 0.549453 5.000971 --> In Sync
After 4 - 28.880611 0.549393 5.000488 --> In Sync


Thoughts?
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby Julio Jerez » Wed Jun 02, 2010 5:57 pm

you hav eto write the funtion liek this

Code: Select all
state
{
body
matrix,
veloc,
rotation
sleepingState
}

// Make the world any want you wnat



SaveState (world)
{
//  itertare ove the list of bodies{
          and save the matrix the state.
      }
     InvalidateCache(world)
}


ResetState (world)
{
   //  itertare ove the list of bodies{
          set the position, and veleocity, and sleep state
   }
   InvalidateCache(world)
}

try that see if it works, make sure you run with a fix step, and simd off.
Many people are using Netwon for deterministic APPs with terrains, it does works.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Help with determinism

Postby Cannos » Wed Jun 02, 2010 8:52 pm

I tried what you suggested but I still have sync issues. I don't see any API for setting the sleep state (only the auto sleep state). And I assume by setting the rotation you mean the angular velocity (i.e. omega). I am saving/restoring the matrix, velocity, and omega for all bodies and invalidating the cache on save and restore. I am running with a fixed step and with platform architecture 0.

Here is updated code:
Code: Select all
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <Newton.h>
#include <stdio.h>

////////////////////////////////////////////////////////////////////////////////
// Global data
NewtonWorld* gNewtonWorld = NULL;
const int numPushes = 4;
float resultMatrices[numPushes + 1][16];
bool firstPlay = true;
const float updateStep = 1.0f / 60.0f;
float vel[3] = {5.0f, 0.0f, 0.0f};
float zero[3] = { 0.0f, 0.0f, 0.0f };
NewtonBody* gGroundBody = NULL;
NewtonBody* gDynBody = NULL;

enum GROUND_TYPE
{
    GROUND_BOX,
    GROUND_TREE
};

enum DYN_OBJ_TYPE
{
    OBJ_BOX,
    OBJ_SPHERE,
    OBJ_CHAMFER_CYLINDER
};

class BodyState
{
    public:
        NewtonBody* pBody;
        float       mtx[16];
        float       velocity[3];
        float       omega[3];
        int         sleepState;
};

class GameState
{
    public:
        BodyState bodyStates[2];
};
GameState gSaveStates[numPushes + 1];

////////////////////////////////////////////////////////////////////////////////
void invalidateCache()
{
    NewtonInvalidateCache(gNewtonWorld);
    //printf("***Invalidate Cache***\n");
}

////////////////////////////////////////////////////////////////////////////////
void saveBody(int stateIndex, int bodyIndex, NewtonBody* pBody)
{
    BodyState& bodyState = gSaveStates[stateIndex].bodyStates[bodyIndex];

    bodyState.pBody = pBody;
    NewtonBodyGetMatrix(pBody, bodyState.mtx);
    NewtonBodyGetVelocity(pBody, bodyState.velocity);
    NewtonBodyGetOmega(pBody, bodyState.omega);
    bodyState.sleepState = NewtonBodyGetSleepState(pBody);
}

////////////////////////////////////////////////////////////////////////////////
void restoreBody(int stateIndex, int bodyIndex)
{
    BodyState& bodyState = gSaveStates[stateIndex].bodyStates[bodyIndex];

    NewtonBody* pBody = bodyState.pBody;
    NewtonBodySetMatrix(pBody, bodyState.mtx);
    NewtonBodySetVelocity(pBody, bodyState.velocity);
    NewtonBodySetOmega(pBody, bodyState.omega);
    //NewtonBodySetSleepState(pBody, bodyState.sleepState); // <--- No api for this
}

////////////////////////////////////////////////////////////////////////////////
void saveGameState(int stateIndex)
{
    // Save state of all bodies
    saveBody(stateIndex, 0, gGroundBody);
    saveBody(stateIndex, 1, gDynBody);

    invalidateCache();
}

////////////////////////////////////////////////////////////////////////////////
void restoreGameState(int stateIndex)
{
    // Restore state of all bodies
    restoreBody(stateIndex, 0);
    restoreBody(stateIndex, 1);

    invalidateCache();
}

////////////////////////////////////////////////////////////////////////////////
void initPhysicsWorld()
{
    gNewtonWorld = NewtonCreate();

    NewtonSetPlatformArchitecture(gNewtonWorld, 0);
    NewtonSetThreadsCount(gNewtonWorld, 1);
    NewtonSetSolverModel(gNewtonWorld, 1);
    //NewtonSetFrictionModel(gNewtonWorld, 0);
    //NewtonSetMultiThreadSolverOnSingleIsland(gNewtonWorld, 0);

    // set an initial world size
    float worldMin[3] = { -500.0f,-500.0f,-500.0f };
    float worldMax[3] = { 500.0f,500.0f,500.0f };
    NewtonSetWorldSize(gNewtonWorld, worldMin, worldMax);

    //invalidateCache();
}

////////////////////////////////////////////////////////////////////////////////
void destroyPhysicsWorld()
{
    if (gNewtonWorld)
    {
        NewtonDestroyAllBodies(gNewtonWorld);
        NewtonDestroy(gNewtonWorld);
        gNewtonWorld = NULL;
    }
}

////////////////////////////////////////////////////////////////////////////////
void applyForceAndTorqueCallback(const NewtonBody* body, float timestep, int threadIndex)
{
    // Get mass / inertia of body
    dFloat Ixx;
    dFloat Iyy;
    dFloat Izz;
    dFloat mass;
    NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);

    // Apply gravity force
    #define GRAVITY -10.0f
    float gravityForce[3] = { 0.0f, mass * GRAVITY, 0.0f };
    NewtonBodySetForce(body, gravityForce);
}

////////////////////////////////////////////////////////////////////////////////
NewtonBody* addRigidBodyToWorld(NewtonCollision* shape, float mtx[16], float mass)
{
    // Create body
    NewtonBody* pRB = NewtonCreateBody(gNewtonWorld, shape);
    NewtonBodySetMatrix(pRB, mtx);

    // Calculate / set inertia and center of mass
    float inertia[3];
    float origin[3] = {0, 0, 0};
    NewtonConvexCollisionCalculateInertialMatrix(shape, inertia, origin);
    NewtonBodySetMassMatrix(pRB, mass, mass * inertia[0], mass * inertia[1], mass * inertia[2]);
    NewtonBodySetCentreOfMass(pRB, origin);
   
    // Set force and transform callbacks
    NewtonBodySetForceAndTorqueCallback(pRB, applyForceAndTorqueCallback);
    //NewtonBodySetTransformCallback(pRB, setTransformCallback);

    return pRB;
}

////////////////////////////////////////////////////////////////////////////////
void addBodies(GROUND_TYPE groundType, DYN_OBJ_TYPE objType)
{
    // Add static ground body
    int groundID = 0;
    float groundOffsetMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float groundMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float groundMass = 0.0f;

    // Create ground collision
    NewtonCollision* pGroundShape = NULL;
    if (groundType == GROUND_BOX)
    {
        pGroundShape = NewtonCreateBox(gNewtonWorld, 400.0f, 2.0f, 400.0f, groundID, groundOffsetMtx);
    }
    else if (groundType == GROUND_TREE)
    {
        // Create a tree collision shape with a grid of faces at height 0.5
        pGroundShape = NewtonCreateTreeCollision(gNewtonWorld, 0);
        NewtonTreeCollisionBeginBuild(pGroundShape);

        float x0z0[3] = {0.0f, 0.5f, 0.0f};
        int numXQuads = 10;
        int numZQuads = 10;
        float xInc = 200.0f / float(numXQuads);
        float zInc = 200.0f / float(numZQuads);

        for (int i = 0; i < numXQuads; i++)
        {
            for (int j = 0; j < numZQuads; j++)
            {
                float startPt[3] = {x0z0[0] + xInc * i, x0z0[1], x0z0[2] + zInc * j};
                float faceVerts[6][3];
                faceVerts[0][0] = startPt[0];
                faceVerts[0][1] = startPt[1];
                faceVerts[0][2] = startPt[2];
                faceVerts[1][0] = startPt[0];
                faceVerts[1][1] = startPt[1];
                faceVerts[1][2] = startPt[2] + zInc;
                faceVerts[2][0] = startPt[0] + xInc;
                faceVerts[2][1] = startPt[1];
                faceVerts[2][2] = startPt[2];
                faceVerts[3][0] = startPt[0];
                faceVerts[3][1] = startPt[1];
                faceVerts[3][2] = startPt[2] + zInc;
                faceVerts[4][0] = startPt[0] + xInc;
                faceVerts[4][1] = startPt[1];
                faceVerts[4][2] = startPt[2] + zInc;
                faceVerts[5][0] = startPt[0] + xInc;
                faceVerts[5][1] = startPt[1];
                faceVerts[5][2] = startPt[2];
                NewtonTreeCollisionAddFace(pGroundShape, 6, &(faceVerts[0][0]), 12, 0);
            }
        }
        NewtonTreeCollisionEndBuild(pGroundShape, 0);
    }
    // Add ground body and release the collision
    gGroundBody = addRigidBodyToWorld(pGroundShape, groundMtx, groundMass);
    NewtonReleaseCollision(gNewtonWorld, pGroundShape);

    // Create dynamic cylinder to move along ground
    int dynID = 1;
    float dynOffsetMtx[16] = {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    //float dynOffsetMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float dynMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.5, 2.0, 5.0, 1};
    float dynMass = 1.0f;

    NewtonCollision* pDynShape = NULL;
    if (objType == OBJ_BOX)
        pDynShape = NewtonCreateBox(gNewtonWorld, 0.5, 0.5f, 0.5f, dynID, dynOffsetMtx);
    else if (objType == OBJ_SPHERE)
        pDynShape = NewtonCreateSphere(gNewtonWorld, 0.5f, 0.5f, 0.5f, dynID, dynOffsetMtx);
    else if (objType == OBJ_CHAMFER_CYLINDER)
        pDynShape = NewtonCreateChamferCylinder(gNewtonWorld, 0.5, 0.1f, dynID, dynOffsetMtx);

    // Add dynamic body and release the collision
    gDynBody = addRigidBodyToWorld(pDynShape, dynMtx, dynMass);
    NewtonReleaseCollision(gNewtonWorld, pDynShape);
}

////////////////////////////////////////////////////////////////////////////////
void printResults(int pushIndex, float mtx[], bool inSync)
{
    // Print out results
    switch (pushIndex)
    {
        case 0:
            printf("Initial - ");
            break;
        case 1:
        case 2:
        case 3:
        case 4:
            printf("After %d - ", pushIndex);
            break;
    }
    printf("%f %f %f", mtx[12], mtx[13], mtx[14]);
    if (!firstPlay)
    {
        if (inSync)
            printf(" --> In Sync\n");
        else
            printf(" --> OUT OF SYNC\n");
    }
    else
        printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
void applyVelocity()
{
    NewtonBodySetVelocity(gDynBody, vel);
    //printf("~~~Apply velocity~~~\n");
}

////////////////////////////////////////////////////////////////////////////////
void replay(int pushIndex)
{
    while (1)
    {
        // Update
        NewtonUpdate(gNewtonWorld, updateStep);

        // When the body goes to sleep, check resulting matrix and apply new velocity
        int sleepState = NewtonBodyGetSleepState(gDynBody);
        if (sleepState == 1)
        {
            // Get body matrix
            float mtx[16];
            NewtonBodyGetMatrix(gDynBody, mtx);

            // If this is the first playthrough, copy these matrices to check against
            bool inSync = true;
            if (firstPlay)
            {
                saveGameState(pushIndex);
            }
            // Otherwise, compare the result against the stored matrix
            else
            {
                int compareResult = memcmp(gSaveStates[pushIndex].bodyStates[1].mtx, mtx, 64);
                if (compareResult != 0)
                {
                    inSync = false;
                }

                // Invalidate the cache here because it was done in the first playthrough when creating the save point
                invalidateCache();
            }

            // Print out results
            printResults(pushIndex, mtx, inSync);

            // Apply new velocity if this isn't the last step
            if (pushIndex < numPushes)
            {
                applyVelocity();
                pushIndex++;
            }
            // Otherwise, break out of the update loop
            else
            {
                break;
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
void Test1(GROUND_TYPE groundType, DYN_OBJ_TYPE objType)
{
    firstPlay = true;

    switch (objType)
    {
        case OBJ_BOX:
            printf("Box on ");
            break;
        case OBJ_SPHERE:
            printf("Sphere on ");
            break;
        case OBJ_CHAMFER_CYLINDER:
            printf("Chamfer Cylinder on ");
            break;
    }
    switch (groundType)
    {
        case GROUND_BOX:
            printf("Box\n");
            break;
        case GROUND_TREE:
            printf("Collision Tree\n");
            break;
    }
    printf("==================================\n");

    // Create world
    initPhysicsWorld();

    // Add bodies
    addBodies(groundType, objType);

    // Play
    printf("First playthrough\n");
    printf("-----------------\n");
    replay(0);
    firstPlay = false;

    // Replay all
    printf("\nReplay all\n");
    printf("------------\n");
    restoreGameState(0);
    replay(0);

    // Replay 1-4
    printf("\nReplay 1-4\n");
    printf("----------\n");
    restoreGameState(1);
    replay(1);

    // Replay 2-4
    printf("\nReplay 2-4\n");
    printf("----------\n");
    restoreGameState(2);
    replay(2);

    // Replay 3-4
    printf("\nReplay 3-4\n");
    printf("----------\n");
    restoreGameState(3);
    replay(3);

    // Replay all
    printf("\nReplay all\n");
    printf("----------\n");
    restoreGameState(0);
    replay(0);

    // Destroy world
    destroyPhysicsWorld();

    printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
    Test1(GROUND_TREE, OBJ_CHAMFER_CYLINDER);
    //Test1(GROUND_BOX, OBJ_CHAMFER_CYLINDER);
    //Test1(GROUND_TREE, OBJ_BOX);
    //Test1(GROUND_BOX, OBJ_BOX);
    //Test1(GROUND_TREE, OBJ_SPHERE);
    //Test1(GROUND_BOX, OBJ_SPHERE);

    return 1;
}


And here are the results:
Code: Select all
Chamfer Cylinder on Collision Tree
==================================
First playthrough
-----------------
Initial - 19.500000 0.548825 5.000000
After 1 - 21.833969 0.549388 4.999840
After 2 - 24.169500 0.549334 4.999844
After 3 - 26.505032 0.549287 4.999801
After 4 - 28.840570 0.549223 4.999690

Replay all
------------
Initial - 19.500000 0.548825 5.000000 --> In Sync
After 1 - 21.833969 0.549388 4.999840 --> In Sync
After 2 - 24.169500 0.549334 4.999844 --> In Sync
After 3 - 26.505032 0.549287 4.999801 --> In Sync
After 4 - 28.840570 0.549223 4.999690 --> In Sync

Replay 1-4
----------
After 1 - 21.833969 0.549388 4.999840 --> In Sync
After 2 - 24.169500 0.549336 4.999950 --> OUT OF SYNC
After 3 - 26.505030 0.549290 4.999987 --> OUT OF SYNC
After 4 - 28.840555 0.549236 4.999965 --> OUT OF SYNC

Replay 2-4
----------
After 2 - 24.169500 0.549334 4.999844 --> In Sync
After 3 - 26.505033 0.549280 4.999749 --> OUT OF SYNC
After 4 - 28.840549 0.549256 4.999638 --> OUT OF SYNC

Replay 3-4
----------
After 3 - 26.505032 0.549287 4.999801 --> In Sync
After 4 - 28.840567 0.549223 4.999744 --> OUT OF SYNC

Replay all
----------
Initial - 19.500000 0.548825 5.000000 --> In Sync
After 1 - 21.833969 0.549388 4.999840 --> In Sync
After 2 - 24.169500 0.549334 4.999844 --> In Sync
After 3 - 26.505032 0.549287 4.999801 --> In Sync
After 4 - 28.840570 0.549223 4.999690 --> In Sync


Assuming there are no bugs, I must still be missing some piece of data to save and restore but I don't know what it could be. Thank you for the help.
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby Cannos » Thu Jun 03, 2010 6:44 pm

Is there any other state that needs to be restored? I've confirmed that the matrix, velocity, and omega are all in sync. I'm calling invalidateCache the same as far as I can tell. I can't restore the sleep state and even if I could invalidateCache seems to clear the sleep state.
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby Julio Jerez » Thu Jun 03, 2010 9:20 pm

yes you do not need to save the sleep state.
you say that this work if teh floor is a Box but not with a terrain?

try make a terrain with only one big face to see if the bug goes away,
that way we know if it is a bug in the collsion tree, altghough I cannot imagine what could be since everything is static in a collision tree.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Help with determinism

Postby Cannos » Thu Jun 03, 2010 9:36 pm

I spoke too soon on the box vs. Collision tree issue. I tested with different combinations of ground and dynamic shape and most of them went out of sync. If you look at the latest code I posted above, there are 6 different tests I have at the bottom. You can uncomment them to see the results, but even the box versions are out of sync.
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby Cannos » Fri Jun 04, 2010 12:51 am

Here is a slightly reworked sample. The results are exactly the same, but the code is a little easier to understand:
Code: Select all
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <Newton.h>
#include <stdio.h>

////////////////////////////////////////////////////////////////////////////////
// Global data
NewtonWorld* gNewtonWorld = NULL;
const int numPushes = 4;
float resultMatrices[numPushes + 1][16];
bool firstPlay = true;
const float updateStep = 1.0f / 60.0f;
float vel[3] = {5.0f, 0.0f, 0.0f};
float zero[3] = { 0.0f, 0.0f, 0.0f };
NewtonBody* gGroundBody = NULL;
NewtonBody* gDynBody = NULL;

enum GROUND_TYPE
{
    GROUND_BOX,
    GROUND_TREE
};

enum DYN_OBJ_TYPE
{
    OBJ_BOX,
    OBJ_SPHERE,
    OBJ_CHAMFER_CYLINDER
};

class BodyState
{
    public:
        NewtonBody* pBody;
        float       mtx[16];
        float       velocity[3];
        float       omega[3];
        int         sleepState;
};

class GameState
{
    public:
        BodyState bodyStates[2];
};
GameState gSaveStates[numPushes + 1]; // initial state + results after each push

////////////////////////////////////////////////////////////////////////////////
void invalidateCache()
{
    NewtonInvalidateCache(gNewtonWorld);
    //printf("***Invalidate Cache***\n");
}

////////////////////////////////////////////////////////////////////////////////
void saveBody(int stateIndex, int bodyIndex, NewtonBody* pBody)
{
    BodyState& bodyState = gSaveStates[stateIndex].bodyStates[bodyIndex];

    NewtonBodyGetMatrix(pBody, bodyState.mtx);
    NewtonBodyGetVelocity(pBody, bodyState.velocity);
    NewtonBodyGetOmega(pBody, bodyState.omega);
    bodyState.sleepState = NewtonBodyGetSleepState(pBody);
}

////////////////////////////////////////////////////////////////////////////////
void restoreBody(int stateIndex, int bodyIndex, NewtonBody* pBody)
{
    BodyState& bodyState = gSaveStates[stateIndex].bodyStates[bodyIndex];

    NewtonBodySetMatrix(pBody, bodyState.mtx);
    NewtonBodySetVelocity(pBody, bodyState.velocity);
    NewtonBodySetOmega(pBody, bodyState.omega);
    //NewtonBodySetSleepState(pBody, bodyState.sleepState); // <--- No api for this
}

////////////////////////////////////////////////////////////////////////////////
void saveGameState(int stateIndex)
{
    // Save state of all bodies
    saveBody(stateIndex, 0, gGroundBody);
    saveBody(stateIndex, 1, gDynBody);

    invalidateCache();
}

////////////////////////////////////////////////////////////////////////////////
void restoreGameState(int stateIndex)
{
    // Restore state of all bodies
    restoreBody(stateIndex, 0, gGroundBody);
    restoreBody(stateIndex, 1, gDynBody);

    invalidateCache();
}

////////////////////////////////////////////////////////////////////////////////
void initPhysicsWorld()
{
    gNewtonWorld = NewtonCreate();

    NewtonSetPlatformArchitecture(gNewtonWorld, 0);
    NewtonSetThreadsCount(gNewtonWorld, 1);
    NewtonSetSolverModel(gNewtonWorld, 1);
    NewtonSetFrictionModel(gNewtonWorld, 1);
    NewtonSetMultiThreadSolverOnSingleIsland(gNewtonWorld, 0);

    // set an initial world size
    float worldMin[3] = { -500.0f,-500.0f,-500.0f };
    float worldMax[3] = { 500.0f,500.0f,500.0f };
    NewtonSetWorldSize(gNewtonWorld, worldMin, worldMax);

    invalidateCache();
}

////////////////////////////////////////////////////////////////////////////////
void destroyPhysicsWorld()
{
    if (gNewtonWorld)
    {
        NewtonDestroyAllBodies(gNewtonWorld);
        NewtonDestroy(gNewtonWorld);
        gNewtonWorld = NULL;
        gGroundBody = NULL;
        gDynBody = NULL;
    }
}

////////////////////////////////////////////////////////////////////////////////
void applyForceAndTorqueCallback(const NewtonBody* body, float timestep, int threadIndex)
{
    // Get mass / inertia of body
    dFloat Ixx;
    dFloat Iyy;
    dFloat Izz;
    dFloat mass;
    NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);

    // Apply gravity force
    #define GRAVITY -10.0f
    float gravityForce[3] = { 0.0f, mass * GRAVITY, 0.0f };
    NewtonBodySetForce(body, gravityForce);
}

////////////////////////////////////////////////////////////////////////////////
NewtonBody* addRigidBodyToWorld(NewtonCollision* shape, float mtx[16], float mass)
{
    // Create body
    NewtonBody* pRB = NewtonCreateBody(gNewtonWorld, shape);
    NewtonBodySetMatrix(pRB, mtx);

    // Calculate / set inertia and center of mass
    float inertia[3];
    float origin[3] = {0, 0, 0};
    NewtonConvexCollisionCalculateInertialMatrix(shape, inertia, origin);
    NewtonBodySetMassMatrix(pRB, mass, mass * inertia[0], mass * inertia[1], mass * inertia[2]);
    NewtonBodySetCentreOfMass(pRB, origin);
   
    // Set force and transform callbacks
    NewtonBodySetForceAndTorqueCallback(pRB, applyForceAndTorqueCallback);
    //NewtonBodySetTransformCallback(pRB, setTransformCallback);

    return pRB;
}

////////////////////////////////////////////////////////////////////////////////
void addBodies(GROUND_TYPE groundType, DYN_OBJ_TYPE objType)
{
    // Add static ground body
    int groundID = 0;
    float groundOffsetMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float groundMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float groundMass = 0.0f;

    // Create ground collision
    NewtonCollision* pGroundShape = NULL;
    if (groundType == GROUND_BOX)
    {
        pGroundShape = NewtonCreateBox(gNewtonWorld, 400.0f, 2.0f, 400.0f, groundID, groundOffsetMtx);
    }
    else if (groundType == GROUND_TREE)
    {
        // Create a tree collision shape with a grid of faces at height 0.5
        pGroundShape = NewtonCreateTreeCollision(gNewtonWorld, 0);
        NewtonTreeCollisionBeginBuild(pGroundShape);

        float x0z0[3] = {0.0f, 0.5f, 0.0f};
        int numXQuads = 10;
        int numZQuads = 10;
        float xInc = 200.0f / float(numXQuads);
        float zInc = 200.0f / float(numZQuads);

        for (int i = 0; i < numXQuads; i++)
        {
            for (int j = 0; j < numZQuads; j++)
            {
                float startPt[3] = {x0z0[0] + xInc * i, x0z0[1], x0z0[2] + zInc * j};
                float faceVerts[6][3];
                faceVerts[0][0] = startPt[0];
                faceVerts[0][1] = startPt[1];
                faceVerts[0][2] = startPt[2];
                faceVerts[1][0] = startPt[0];
                faceVerts[1][1] = startPt[1];
                faceVerts[1][2] = startPt[2] + zInc;
                faceVerts[2][0] = startPt[0] + xInc;
                faceVerts[2][1] = startPt[1];
                faceVerts[2][2] = startPt[2];
                faceVerts[3][0] = startPt[0];
                faceVerts[3][1] = startPt[1];
                faceVerts[3][2] = startPt[2] + zInc;
                faceVerts[4][0] = startPt[0] + xInc;
                faceVerts[4][1] = startPt[1];
                faceVerts[4][2] = startPt[2] + zInc;
                faceVerts[5][0] = startPt[0] + xInc;
                faceVerts[5][1] = startPt[1];
                faceVerts[5][2] = startPt[2];
                NewtonTreeCollisionAddFace(pGroundShape, 6, &(faceVerts[0][0]), 12, 0);
            }
        }
        NewtonTreeCollisionEndBuild(pGroundShape, 0);
    }
    // Add ground body and release the collision
    gGroundBody = addRigidBodyToWorld(pGroundShape, groundMtx, groundMass);
    NewtonReleaseCollision(gNewtonWorld, pGroundShape);

    // Create dynamic cylinder to move along ground
    int dynID = 1;
    float dynOffsetMtx[16] = {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    //float dynOffsetMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    float dynMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.5, 2.0, 5.0, 1};
    float dynMass = 1.0f;

    NewtonCollision* pDynShape = NULL;
    if (objType == OBJ_BOX)
        pDynShape = NewtonCreateBox(gNewtonWorld, 0.5, 0.5f, 0.5f, dynID, dynOffsetMtx);
    else if (objType == OBJ_SPHERE)
        pDynShape = NewtonCreateSphere(gNewtonWorld, 0.5f, 0.5f, 0.5f, dynID, dynOffsetMtx);
    else if (objType == OBJ_CHAMFER_CYLINDER)
        pDynShape = NewtonCreateChamferCylinder(gNewtonWorld, 0.5, 0.1f, dynID, dynOffsetMtx);

    // Add dynamic body and release the collision
    gDynBody = addRigidBodyToWorld(pDynShape, dynMtx, dynMass);
    NewtonReleaseCollision(gNewtonWorld, pDynShape);
}

////////////////////////////////////////////////////////////////////////////////
void applyVelocity()
{
    NewtonBodySetVelocity(gDynBody, vel);
    //printf("~~~Apply velocity~~~\n");
}

////////////////////////////////////////////////////////////////////////////////
void runUntilSleep()
{
    // Call update until the dynamic body goes to sleep
    while (1)
    {
        // Update
        NewtonUpdate(gNewtonWorld, updateStep);

        // When the body goes to sleep, break out of the update loop
        int sleepState = NewtonBodyGetSleepState(gDynBody);
        if (sleepState == 1)
            break;
    }
}

////////////////////////////////////////////////////////////////////////////////
void printGameState(int index)
{
    // Print current position
    float mtx[16];
    NewtonBodyGetMatrix(gDynBody, mtx);
    printf("%d - %f %f %f", index, mtx[12], mtx[13], mtx[14]);

    // If replaying, compare the current results to the recorded ones
    if (!firstPlay)
    {
        // Compare matrix
        bool inSync = true;
        int compareResult = memcmp(gSaveStates[index].bodyStates[1].mtx, mtx, 64);
        if (compareResult != 0)
            inSync = false;

        // Print sync state
        if (inSync)
            printf(" --> In Sync");
        else
            printf(" --> OUT OF SYNC");
       
    }
    printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
void runSimulationFromStep(int startStep)
{
    // Initial setup.  If first playthrough, save the current state, otherwise
    // restore it
    if (firstPlay)
        saveGameState(startStep);
    else
        restoreGameState(startStep);

    // Check and print current sync state
    printGameState(startStep);

    for (int stepIndex = startStep + 1; stepIndex <= numPushes; stepIndex++)
    {
        // Apply velocity to dynamic body
        applyVelocity();

        // Run until bodies are at equilibrium
        runUntilSleep();

        // Save or clear cache
        if (firstPlay)
        {
            // If first playthough, make a new save point
            saveGameState(stepIndex);
        }
        else
        {
            // Otherwise, invalidate the cache during replay to make sure the cache invalidates are in
            // sync with the initial playthrough
            invalidateCache();
        }

        // Check and print current sync state
        printGameState(stepIndex);
    }
}

////////////////////////////////////////////////////////////////////////////////
void Test(GROUND_TYPE groundType, DYN_OBJ_TYPE objType)
{
    printf("==================================\n");
    switch (objType)
    {
        case OBJ_BOX:
            printf("Box on ");
            break;
        case OBJ_SPHERE:
            printf("Sphere on ");
            break;
        case OBJ_CHAMFER_CYLINDER:
            printf("Chamfer Cylinder on ");
            break;
    }
    switch (groundType)
    {
        case GROUND_BOX:
            printf("Box\n");
            break;
        case GROUND_TREE:
            printf("Collision Tree\n");
            break;
    }
    printf("==================================\n");

    // Create world
    initPhysicsWorld();

    // Add bodies
    addBodies(groundType, objType);

    // Run until bodies are at equilibrium
    runUntilSleep();

    // First playthrough - make a save point between every push of the dynamic object
    printf("First playthrough\n");
    printf("-----------------\n");
    firstPlay = true;
    runSimulationFromStep(0);
    firstPlay = false;

    // Replay All
    printf("\nReplay all\n");
    printf("-----------------\n");
    runSimulationFromStep(0);

    // Replay 1-4
    printf("\nReplay 1-4\n");
    printf("-----------------\n");
    runSimulationFromStep(1);

    // Replay 2-4
    printf("\nReplay 2-4\n");
    printf("-----------------\n");
    runSimulationFromStep(2);

    // Replay 3-4
    printf("\nReplay 3-4\n");
    printf("-----------------\n");
    runSimulationFromStep(3);

    // Destroy world
    destroyPhysicsWorld();

    printf("\n\n");
}


////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
    Test(GROUND_TREE, OBJ_CHAMFER_CYLINDER);
    Test(GROUND_BOX, OBJ_CHAMFER_CYLINDER);
    Test(GROUND_TREE, OBJ_BOX);
    Test(GROUND_BOX, OBJ_BOX);
    Test(GROUND_TREE, OBJ_SPHERE);
    Test(GROUND_BOX, OBJ_SPHERE);

    return 1;
}


And here are the results of all the tests. You can see that most of them go out of sync.
Code: Select all
==================================
Chamfer Cylinder on Collision Tree
==================================
First playthrough
-----------------
0 - 19.500000 0.548825 5.000000
1 - 21.833969 0.549388 4.999840
2 - 24.169500 0.549334 4.999844
3 - 26.505032 0.549287 4.999801
4 - 28.840570 0.549223 4.999690

Replay all
-----------------
0 - 19.500000 0.548825 5.000000 --> In Sync
1 - 21.833969 0.549388 4.999840 --> In Sync
2 - 24.169500 0.549334 4.999844 --> In Sync
3 - 26.505032 0.549287 4.999801 --> In Sync
4 - 28.840570 0.549223 4.999690 --> In Sync

Replay 1-4
-----------------
1 - 21.833969 0.549388 4.999840 --> In Sync
2 - 24.169500 0.549336 4.999950 --> OUT OF SYNC
3 - 26.505030 0.549290 4.999987 --> OUT OF SYNC
4 - 28.840555 0.549236 4.999965 --> OUT OF SYNC

Replay 2-4
-----------------
2 - 24.169500 0.549334 4.999844 --> In Sync
3 - 26.505033 0.549280 4.999749 --> OUT OF SYNC
4 - 28.840549 0.549256 4.999638 --> OUT OF SYNC

Replay 3-4
-----------------
3 - 26.505032 0.549287 4.999801 --> In Sync
4 - 28.840567 0.549223 4.999744 --> OUT OF SYNC


==================================
Chamfer Cylinder on Box
==================================
First playthrough
-----------------
0 - 19.500000 1.047998 5.000001
1 - 21.835451 1.048077 4.999904
2 - 24.170908 1.048150 4.999874
3 - 26.506351 1.048236 4.999964
4 - 28.841808 1.048303 4.999964

Replay all
-----------------
0 - 19.500000 1.047998 5.000001 --> In Sync
1 - 21.835451 1.048077 4.999904 --> In Sync
2 - 24.170908 1.048150 4.999874 --> In Sync
3 - 26.506351 1.048236 4.999964 --> In Sync
4 - 28.841808 1.048303 4.999964 --> In Sync

Replay 1-4
-----------------
1 - 21.835451 1.048077 4.999904 --> In Sync
2 - 24.170908 1.048150 4.999874 --> In Sync
3 - 26.506351 1.048236 4.999964 --> In Sync
4 - 28.841808 1.048303 4.999964 --> In Sync

Replay 2-4
-----------------
2 - 24.170908 1.048150 4.999874 --> In Sync
3 - 26.506351 1.048236 4.999964 --> In Sync
4 - 28.841808 1.048303 4.999964 --> In Sync

Replay 3-4
-----------------
3 - 26.506351 1.048236 4.999964 --> In Sync
4 - 28.841808 1.048303 4.999964 --> In Sync


==================================
Box on Collision Tree
==================================
First playthrough
-----------------
0 - 19.500000 0.746551 5.000000
1 - 21.850767 0.746355 5.000000
2 - 24.186392 0.746190 5.000000
3 - 26.522079 0.746009 4.999964
4 - 28.857809 0.745822 4.999928

Replay all
-----------------
0 - 19.500000 0.746551 5.000000 --> In Sync
1 - 21.850767 0.746355 5.000000 --> In Sync
2 - 24.186392 0.746190 5.000000 --> In Sync
3 - 26.522079 0.746009 4.999964 --> In Sync
4 - 28.857809 0.745822 4.999928 --> In Sync

Replay 1-4
-----------------
1 - 21.850767 0.746355 5.000000 --> In Sync
2 - 24.186392 0.746190 5.000000 --> In Sync
3 - 26.522079 0.746009 4.999964 --> In Sync
4 - 28.857809 0.745822 4.999928 --> In Sync

Replay 2-4
-----------------
2 - 24.186392 0.746190 5.000000 --> In Sync
3 - 26.522079 0.746009 4.999964 --> In Sync
4 - 28.857809 0.745822 4.999928 --> In Sync

Replay 3-4
-----------------
3 - 26.522079 0.746009 4.999964 --> In Sync
4 - 28.857809 0.745822 4.999928 --> OUT OF SYNC


==================================
Box on Box
==================================
First playthrough
-----------------
0 - 19.500000 1.247611 5.000000
1 - 21.835604 1.247389 5.000021
2 - 24.171183 1.247285 5.000555
3 - 26.506737 1.247249 5.000770
4 - 28.842348 1.247090 5.001709

Replay all
-----------------
0 - 19.500000 1.247611 5.000000 --> In Sync
1 - 21.835604 1.247389 5.000021 --> In Sync
2 - 24.171183 1.247285 5.000555 --> In Sync
3 - 26.506737 1.247249 5.000770 --> In Sync
4 - 28.842348 1.247090 5.001709 --> In Sync

Replay 1-4
-----------------
1 - 21.835604 1.247389 5.000021 --> In Sync
2 - 24.171183 1.247285 5.000555 --> In Sync
3 - 26.506737 1.247249 5.000770 --> In Sync
4 - 28.842348 1.247090 5.001709 --> In Sync

Replay 2-4
-----------------
2 - 24.171183 1.247285 5.000555 --> In Sync
3 - 26.506735 1.247250 5.000770 --> OUT OF SYNC
4 - 28.842318 1.247145 5.000183 --> OUT OF SYNC

Replay 3-4
-----------------
3 - 26.506737 1.247249 5.000770 --> In Sync
4 - 28.842348 1.247090 5.001709 --> In Sync


==================================
Sphere on Collision Tree
==================================
First playthrough
-----------------
0 - 19.500000 0.993866 5.000000
1 - 47.437523 0.991836 5.000000
2 - 75.346458 0.993160 5.000000
3 - 103.424644 0.994008 5.000000
4 - 131.370529 0.992642 5.000000

Replay all
-----------------
0 - 19.500000 0.993866 5.000000 --> In Sync
1 - 47.437523 0.991836 5.000000 --> In Sync
2 - 75.346458 0.993160 5.000000 --> In Sync
3 - 103.424644 0.994008 5.000000 --> In Sync
4 - 131.370529 0.992642 5.000000 --> In Sync

Replay 1-4
-----------------
1 - 47.437523 0.991836 5.000000 --> In Sync
2 - 75.346458 0.993160 5.000000 --> OUT OF SYNC
3 - 103.424644 0.994008 5.000000 --> OUT OF SYNC
4 - 131.370529 0.992642 5.000000 --> OUT OF SYNC

Replay 2-4
-----------------
2 - 75.346458 0.993160 5.000000 --> In Sync
3 - 103.424644 0.994008 5.000000 --> OUT OF SYNC
4 - 131.370529 0.992642 5.000000 --> OUT OF SYNC

Replay 3-4
-----------------
3 - 103.424644 0.994008 5.000000 --> In Sync
4 - 131.370529 0.992642 5.000000 --> OUT OF SYNC


==================================
Sphere on Box
==================================
First playthrough
-----------------
0 - 19.500000 1.493427 5.000000
1 - 47.436920 1.492052 5.000000
2 - 75.354416 1.492933 5.000000
3 - 103.281456 1.495925 5.000000
4 - 131.256958 1.494550 5.000000

Replay all
-----------------
0 - 19.500000 1.493427 5.000000 --> In Sync
1 - 47.436920 1.492052 5.000000 --> In Sync
2 - 75.354416 1.492933 5.000000 --> In Sync
3 - 103.281456 1.495925 5.000000 --> In Sync
4 - 131.256958 1.494550 5.000000 --> In Sync

Replay 1-4
-----------------
1 - 47.436920 1.492052 5.000000 --> In Sync
2 - 75.354416 1.492933 5.000000 --> OUT OF SYNC
3 - 103.281456 1.495925 5.000000 --> OUT OF SYNC
4 - 131.256958 1.494550 5.000000 --> OUT OF SYNC

Replay 2-4
-----------------
2 - 75.354416 1.492933 5.000000 --> In Sync
3 - 103.281456 1.495925 5.000000 --> OUT OF SYNC
4 - 131.256958 1.494550 5.000000 --> OUT OF SYNC

Replay 3-4
-----------------
3 - 103.281456 1.495925 5.000000 --> In Sync
4 - 131.256958 1.494550 5.000000 --> OUT OF SYNC


If you can run the sample to see if you get the same results, that would be really helpful. It's entirely possible I have a dumb error in the code, but I can't find it and I've been staring at it a while. :)
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby Julio Jerez » Wed Jun 09, 2010 11:02 am

I am testing this now, and yes it seems to be some problem there.

I place the Invalidate cache is the right palce, and I also change the cilynder to a Box to make is simple to debug bu teh bug is still there.
I will now make teh collision tree to be just one face and see if that is the problem.

I did find some other problems wit teh collision mesh you are passing to the collsion tree, this code here is very wrong
Code: Select all
   for (int i = 0; i < numXQuads; i++)
   {
      for (int j = 0; j < numZQuads; j++)
      {
         float startPt[3] = {x0z0[0] + xInc * i, x0z0[1], x0z0[2] + zInc * j};
         float faceVerts[6][3];
         faceVerts[0][0] = startPt[0];
         faceVerts[0][1] = startPt[1];
         faceVerts[0][2] = startPt[2];
         faceVerts[1][0] = startPt[0];
         faceVerts[1][1] = startPt[1];
         faceVerts[1][2] = startPt[2] + zInc;
         faceVerts[2][0] = startPt[0] + xInc;
         faceVerts[2][1] = startPt[1];
         faceVerts[2][2] = startPt[2];
         faceVerts[3][0] = startPt[0];
         faceVerts[3][1] = startPt[1];
         faceVerts[3][2] = startPt[2] + zInc;
         faceVerts[4][0] = startPt[0] + xInc;
         faceVerts[4][1] = startPt[1];
         faceVerts[4][2] = startPt[2] + zInc;
         faceVerts[5][0] = startPt[0] + xInc;
         faceVerts[5][1] = startPt[1];
         faceVerts[5][2] = startPt[2];
         NewtonTreeCollisionAddFace(pGroundShape, 6, &(faceVerts[0][0]), 12, 0);
      }


you can not put many faces in one array and pass then to the engine bacause the engine will not know where one face end and the next begin.
you need to pass one face at a time, I change that code to this, nwo is passed trinagles.

Code: Select all
   float xInc = 50.0f / float(numXQuads);
   float zInc = 50.0f / float(numZQuads);
   for (int i = 0; i < numXQuads; i++)
   {
      for (int j = 0; j < numZQuads; j++)
      {
         float startPt[3] = {x0z0[0] + xInc * i, x0z0[1], x0z0[2] + zInc * j};
//         float faceVerts[6][3];
         float faceVerts[3][3];
         faceVerts[0][0] = startPt[0];
         faceVerts[0][1] = startPt[1];
         faceVerts[0][2] = startPt[2];
         faceVerts[1][0] = startPt[0];
         faceVerts[1][1] = startPt[1];
         faceVerts[1][2] = startPt[2] + zInc;
         faceVerts[2][0] = startPt[0] + xInc;
         faceVerts[2][1] = startPt[1];
         faceVerts[2][2] = startPt[2];
         NewtonTreeCollisionAddFace(pGroundShape, 3, &(faceVerts[0][0]), 12, 0);

         faceVerts[0][0] = startPt[0];
         faceVerts[0][1] = startPt[1];
         faceVerts[0][2] = startPt[2] + zInc;
         faceVerts[1][0] = startPt[0] + xInc;
         faceVerts[1][1] = startPt[1];
         faceVerts[1][2] = startPt[2] + zInc;
         faceVerts[2][0] = startPt[0] + xInc;
         faceVerts[2][1] = startPt[1];
         faceVerts[2][2] = startPt[2];
         NewtonTreeCollisionAddFace(pGroundShape, 3, &(faceVerts[0][0]), 12, 0);
      }
   }
//   NewtonTreeCollisionEndBuild(pGroundShape, 0);
   NewtonTreeCollisionEndBuild(pGroundShape, 1);
 


I also make optimize so that i colide with on flat plane, tha makes it simpel to debug.

The bad news is that teh bug is still there.
I will investigate what is causing this. It seem very simple to malfuntion like that.
BUt I am late for work now, I will continue tomorrow.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Help with determinism

Postby Julio Jerez » Wed Jun 09, 2010 2:01 pm

Ok after testion again I found there are not bug in the engine, tah git me scared but it seemm too big for such simple scene.

I think I know what you want to do, but you are not saving the complete state of the engine.
I will modify the demo tonoght and reposte here so that you can see hwo to do it and build from there.

It is not big deal just a small mistake because of the poor documentation of that engine feature.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Help with determinism

Postby Cannos » Wed Jun 09, 2010 2:09 pm

That's great, thanks! And thanks for the information on building the collision tree too. In my main game I was only adding one face at a time, I'm not sure why I tried to do 2 at a time in this demo.

Also, if it's any help in your testing, it looks to me like the "Sphere vs. Collision Tree" and "Sphere vs. Box" cases in my most recent post went out of sync the easiest and most consistently.
Cannos
 
Posts: 129
Joined: Thu Mar 04, 2010 5:41 pm

Re: Help with determinism

Postby Julio Jerez » Wed Jun 09, 2010 2:21 pm

they go out of sync becuse the simulation loop is not right.
do not worry I will re-write tonight so that it is eassy for you to see, I can not do it now
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Help with determinism

Postby Julio Jerez » Thu Jun 10, 2010 10:27 am

Ok here is the demo, to reproduce determinism


Code: Select all
// deterministm.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <Newton.h>
#include <stdio.h>

NewtonWorld* gNewtonWorld = NULL;
NewtonBody* gDynBody = NULL;


const int numPushes = 4;
const float updateStep = 1.0f / 60.0f;

float vel[3] = {5.0f, 0.0f, 0.0f};
float zero[3] = { 0.0f, 0.0f, 0.0f };


////////////////////////////////////////////////////////////////////////////////
void initPhysicsWorld()
{
   gNewtonWorld = NewtonCreate();

   NewtonSetPlatformArchitecture(gNewtonWorld, 0);
   NewtonSetThreadsCount(gNewtonWorld, 1);
   NewtonSetSolverModel(gNewtonWorld, 1);
   //NewtonSetFrictionModel(gNewtonWorld, 0);

   // set an initial world size
   float worldMin[3] = { -500.0f,-500.0f,-500.0f };
   float worldMax[3] = { 500.0f,500.0f,500.0f };
   NewtonSetWorldSize(gNewtonWorld, worldMin, worldMax);
}

////////////////////////////////////////////////////////////////////////////////
void destroyPhysicsWorld()
{
   if (gNewtonWorld)
   {
      NewtonDestroyAllBodies(gNewtonWorld);
      NewtonDestroy(gNewtonWorld);
      gNewtonWorld = NULL;
   }
}

////////////////////////////////////////////////////////////////////////////////
void applyForceAndTorqueCallback(const NewtonBody* body, float timestep, int threadIndex)
{
   // Get mass / inertia of body
   dFloat Ixx;
   dFloat Iyy;
   dFloat Izz;
   dFloat mass;
   NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);

   // Apply gravity force
#define GRAVITY -10.0f
   float gravityForce[3] = { 0.0f, mass * GRAVITY, 0.0f };
   NewtonBodySetForce(body, gravityForce);
}

////////////////////////////////////////////////////////////////////////////////
NewtonBody* addRigidBodyToWorld(NewtonCollision* shape, float mtx[16], float mass)
{
   // Create body
   NewtonBody* pRB = NewtonCreateBody(gNewtonWorld, shape);
   NewtonBodySetMatrix(pRB, mtx);

   // Calculate / set inertia and center of mass
   float inertia[3];
   float origin[3] = {0, 0, 0};
   NewtonConvexCollisionCalculateInertialMatrix(shape, inertia, origin);
   NewtonBodySetMassMatrix(pRB, mass, mass * inertia[0], mass * inertia[1], mass * inertia[2]);
   NewtonBodySetCentreOfMass(pRB, origin);

   // Set force and transform callbacks
   NewtonBodySetForceAndTorqueCallback(pRB, applyForceAndTorqueCallback);
   //NewtonBodySetTransformCallback(pRB, setTransformCallback);

   return pRB;
}

////////////////////////////////////////////////////////////////////////////////
void addBodies()
{
   // Add static ground body
   int groundID = 0;
   float groundOffsetMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
   float groundMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
   float groundMass = 0.0f;

   // Create a tree collision shape with a grid of faces at height 0.5
   NewtonCollision* pGroundShape = NewtonCreateTreeCollision(gNewtonWorld, 0);
   NewtonTreeCollisionBeginBuild(pGroundShape);

   float x0z0[3] = {0.0f, 0.5f, 0.0f};
   int numXQuads = 10;
   int numZQuads = 10;


   float xInc = 50.0f / float(numXQuads);
   float zInc = 50.0f / float(numZQuads);
   for (int i = 0; i < numXQuads; i++)
   {
      for (int j = 0; j < numZQuads; j++)
      {
         float startPt[3] = {x0z0[0] + xInc * i, x0z0[1], x0z0[2] + zInc * j};
         float faceVerts[3][3];
         faceVerts[0][0] = startPt[0];
         faceVerts[0][1] = startPt[1];
         faceVerts[0][2] = startPt[2];
         faceVerts[1][0] = startPt[0];
         faceVerts[1][1] = startPt[1];
         faceVerts[1][2] = startPt[2] + zInc;
         faceVerts[2][0] = startPt[0] + xInc;
         faceVerts[2][1] = startPt[1];
         faceVerts[2][2] = startPt[2];
         NewtonTreeCollisionAddFace(pGroundShape, 3, &(faceVerts[0][0]), 12, 0);

         faceVerts[0][0] = startPt[0];
         faceVerts[0][1] = startPt[1];
         faceVerts[0][2] = startPt[2] + zInc;
         faceVerts[1][0] = startPt[0] + xInc;
         faceVerts[1][1] = startPt[1];
         faceVerts[1][2] = startPt[2] + zInc;
         faceVerts[2][0] = startPt[0] + xInc;
         faceVerts[2][1] = startPt[1];
         faceVerts[2][2] = startPt[2];
         NewtonTreeCollisionAddFace(pGroundShape, 3, &(faceVerts[0][0]), 12, 0);
      }
   }
   NewtonTreeCollisionEndBuild(pGroundShape, 0);
//   NewtonTreeCollisionEndBuild(pGroundShape, 1);

   addRigidBodyToWorld(pGroundShape, groundMtx, groundMass);

   NewtonReleaseCollision(gNewtonWorld, pGroundShape);

   // Create dynamic cylinder to move along ground
   int dynID = 1;
   float dynOffsetMtx[16] = {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
   float dynMtx[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.5, 2.0, 5.0, 1};
   float dynMass = 1.0f;

//   NewtonCollision* pDynShape = NewtonCreateChamferCylinder(gNewtonWorld, 0.5, 0.1f, dynID, dynOffsetMtx);
   NewtonCollision* pDynShape = NewtonCreateBox(gNewtonWorld, 0.5, 0.5f, 0.5f, dynID, dynOffsetMtx);
   NewtonBody* pDynBody = addRigidBodyToWorld(pDynShape, dynMtx, dynMass);
   NewtonReleaseCollision(gNewtonWorld, pDynShape);

   gDynBody = pDynBody;
}

////////////////////////////////////////////////////////////////////////////////
//void printResults(int pushIndex, float mtx[], bool inSync)
void printResults(int pushIndex, bool inSync)
{
   // Print out results
   switch (pushIndex)
   {
   case 0:
      printf("Initial - ");
      break;
   case 1:
   case 2:
   case 3:
   case 4:
      printf("After %d - ", pushIndex);
      break;
   }
//   printf("%f %f %f", mtx[12], mtx[13], mtx[14]);
   if (inSync)
      printf(" --> In Sync\n");
   else
      printf(" --> OUT OF SYNC\n");
}



////////////////////////////////////////////////////////////////////////////////
void applyVelocity()
{
   NewtonBodySetVelocity(gDynBody, vel);
   NewtonBodySetOmega(gDynBody, zero);
   NewtonBodySetForce(gDynBody, zero);
   NewtonBodySetTorque(gDynBody, zero);
}


// make and array of world states each state to hold M bodies, for this example m = 100
// this should used some kind of  SDT container or equivalents
class WorldState
{
   // the state on one body
   struct BODY_STATE
   {
      NewtonBody* m_body;
      float m_matrix[16];
      float m_veloc[3];
      float m_omega[3];
   };

   // the state of a world is teh state of all its bodies
   struct WORLD_STATE
   {
      int m_bodyCount;
      BODY_STATE m_bodies[100];
   };

   // an animation is an array of many states
   int m_Count;
   WORLD_STATE m_allStates[20];


   public:
   WorldState ()
   {
      m_Count = 0;
   }

   void SaveState ()
   {
      // get the state for this track
      WORLD_STATE* worldState = &m_allStates[m_Count];

      // invalidate the cache in the newton world
      NewtonInvalidateCache(gNewtonWorld);

      int bodyCount = 0;
      // save the state of each body in a newton world
      for (NewtonBody* body = NewtonWorldGetFirstBody(gNewtonWorld); body; body = NewtonWorldGetNextBody(gNewtonWorld, body)) {
         BODY_STATE* bodyState = &worldState->m_bodies[bodyCount];

         bodyState->m_body = body;
         NewtonBodyGetMatrix(body, bodyState->m_matrix);
         NewtonBodyGetVelocity(body, bodyState->m_veloc);
         NewtonBodyGetOmega(body, bodyState->m_omega);
         bodyCount ++;
      }
      worldState->m_bodyCount = bodyCount;

      m_Count ++;
   }

   void RestoreState (int frame)
   {
      WORLD_STATE* worldState = &m_allStates[frame];

      for (int i = 0; i < worldState->m_bodyCount; i ++) {
         BODY_STATE* bodyState = &worldState->m_bodies[i];

         NewtonBodySetMatrix(bodyState->m_body, bodyState->m_matrix);
         NewtonBodySetVelocity(bodyState->m_body, bodyState->m_veloc);
         NewtonBodySetOmega(bodyState->m_body, bodyState->m_omega);
      }
      NewtonInvalidateCache(gNewtonWorld);
   }

   void CompareandAndPrintReport (int frame)
   {
      WORLD_STATE* worldState = &m_allStates[frame];

      int outOfSync = 0;
      for (int i = 0; i < worldState->m_bodyCount; i ++) {
         BODY_STATE* bodyState = &worldState->m_bodies[i];

         // get the body state from the world into a temporary state
         BODY_STATE tmpState;
         tmpState.m_body = bodyState->m_body;
         NewtonBodyGetMatrix(bodyState->m_body, tmpState.m_matrix);
         NewtonBodyGetVelocity(bodyState->m_body, tmpState.m_veloc);
         NewtonBodyGetOmega(bodyState->m_body, tmpState.m_omega);

         // compare the state to the save one
         outOfSync |= memcmp(bodyState, &tmpState, sizeof (BODY_STATE));
      }

      printResults(frame, outOfSync ? false : true);
   }
};


WorldState gWorldState;


void RunSimulation()
{
   // saved the state before start a simulation run and also invalidate the cache
   //   NewtonBodyGetMatrix(gDynBody, initialMatrix);
   gWorldState.SaveState ();
   for (int i = 0; i < numPushes; )
   {
      // Update
      NewtonUpdate(gNewtonWorld, updateStep);

      // When the body goes to sleep, check resulting matrix and apply new velocity
      int sleepState = NewtonBodyGetSleepState(gDynBody);
      if (sleepState == 1)
      {

         // Apply new velocity if this isn't the last step
         applyVelocity();

         // save the world state at this point
         gWorldState.SaveState ();

         // next push
         i ++;
      }
   }

   // save the last state
   gWorldState.SaveState ();
}



void ReplaySimulation (int from)
{
   // saved the state before start a simulation run and also invalidate the cache
   //   NewtonBodyGetMatrix(gDynBody, initialMatrix);
   gWorldState.RestoreState (from);
   for (int i = from; i < numPushes; )
   {
      // Update
      NewtonUpdate(gNewtonWorld, updateStep);

      // When the body goes to sleep, check resulting matrix and apply new velocity
      int sleepState = NewtonBodyGetSleepState(gDynBody);
      if (sleepState == 1)
      {
         // Apply new velocity if this isn't the last step
         applyVelocity();

         // check if the worlds are in sync
         gWorldState.CompareandAndPrintReport (i + 1);


         // Need to Invalidate because at each check point the world was reset.
         //NewtonInvalidateCache(gNewtonWorld);
         gWorldState.RestoreState (i + 1);


         // next push
         i ++;
      }
   }
}


////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
   // Create world
   initPhysicsWorld();

   // Add bodies
   addBodies();


   // play the simulation and save the states
   printf("First playthrough\n");
   RunSimulation();


   // Replay all
   printf("\nReplay all\n");
   ReplaySimulation(0);


   // Replay 1-4
   printf("\nReplay 1-4\n");
   ReplaySimulation(1);


   // Replay 2-4
   printf("\nReplay 2-4\n");
   ReplaySimulation(2);

   // Replay 2-4
   printf("\nReplay 3-4\n");
   ReplaySimulation(3);

   // Replay all
   printf("\nReplay all\n");
   ReplaySimulation(0);

   // Destroy world
   destroyPhysicsWorld();

   return 1;
}



It looks like there is a problem if the run is rest after several frame, there is problably some state that is not save. or I am missing something I will find out.

this the output I am getting, it goes in sync the first tow check point but then some value goes wrong,

First playthrough

Replay all
After 1 - --> In Sync
After 2 - --> In Sync
After 3 - --> OUT OF SYNC
After 4 - --> OUT OF SYNC

Replay 1-4
After 2 - --> In Sync
After 3 - --> OUT OF SYNC
After 4 - --> OUT OF SYNC

Replay 2-4
After 3 - --> OUT OF SYNC
After 4 - --> OUT OF SYNC

Replay all
After 1 - --> In Sync
After 2 - --> In Sync
After 3 - --> OUT OF SYNC
After 4 - --> OUT OF SYNC


I will trace the state in every key frame to see when goe wrong and why. I most be missing something.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Next

Return to General Discussion

Who is online

Users browsing this forum: No registered users and 2 guests