- 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.