diff --git a/testbed/CMakeLists.txt b/testbed/CMakeLists.txt index b5b2fdd7..9a488e1a 100644 --- a/testbed/CMakeLists.txt +++ b/testbed/CMakeLists.txt @@ -20,7 +20,7 @@ FILE(COPY "shaders/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/shaders/") FILE(COPY "meshes/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/meshes/") # Headers -INCLUDE_DIRECTORIES("src" "opengl-framework/src/" "glfw/include/" "common/" "scenes/") +INCLUDE_DIRECTORIES("src/" "opengl-framework/src/" "glfw/include/" "common/" "scenes/") # Testbed source files SET(TESTBED_SOURCES @@ -31,6 +31,8 @@ SET(TESTBED_SOURCES src/Gui.cpp src/Scene.h src/Scene.cpp + src/Timer.h + src/Timer.cpp ) # Common source files diff --git a/testbed/common/Box.cpp b/testbed/common/Box.cpp index d0c7a1df..4a95aab0 100644 --- a/testbed/common/Box.cpp +++ b/testbed/common/Box.cpp @@ -85,6 +85,8 @@ Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &p rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); + mPreviousTransform = transform; + // Create a rigid body in the dynamics world mRigidBody = world->createCollisionBody(transform); @@ -205,14 +207,19 @@ void Box::render(openglframework::Shader& shader, } // Update the transform matrix of the box -void Box::updateTransform() { +void Box::updateTransform(float interpolationFactor) { - // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + // Get the transform of the rigid body + rp3d::Transform transform = mRigidBody->getTransform(); + + // Interpolate the transform between the previous one and the new one + rp3d::Transform interpolatedTransform = rp3d::Transform::interpolateTransforms(mPreviousTransform, + transform, + interpolationFactor); // Compute the transform used for rendering the box rp3d::decimal matrix[16]; - transform.getOpenGLMatrix(matrix); + interpolatedTransform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], diff --git a/testbed/common/Box.h b/testbed/common/Box.h index 2cc333d8..97c86e5b 100644 --- a/testbed/common/Box.h +++ b/testbed/common/Box.h @@ -56,6 +56,9 @@ class Box : public openglframework::Object3D { /// Rigid body used to simulate the dynamics of the box rp3d::CollisionBody* mRigidBody; + /// Previous transform of the body (for interpolation) + rp3d::Transform mPreviousTransform; + /// Scaling matrix (applied to a cube to obtain the correct box dimensions) openglframework::Matrix4 mScalingMatrix; @@ -104,7 +107,7 @@ class Box : public openglframework::Object3D { reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the box - void updateTransform(); + void updateTransform(float interpolationFactor); /// Render the cube at the correct position and with the correct orientation void render(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix); diff --git a/testbed/common/Capsule.cpp b/testbed/common/Capsule.cpp index faf8484e..7df79f85 100644 --- a/testbed/common/Capsule.cpp +++ b/testbed/common/Capsule.cpp @@ -57,6 +57,8 @@ Capsule::Capsule(float radius, float height, const openglframework::Vector3& pos rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); + mPreviousTransform = transform; + // Create a rigid body corresponding in the dynamics world mRigidBody = world->createCollisionBody(transform); @@ -161,14 +163,19 @@ void Capsule::render(openglframework::Shader& shader, } // Update the transform matrix of the sphere -void Capsule::updateTransform() { +void Capsule::updateTransform(float interpolationFactor) { - // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + // Get the transform of the rigid body + rp3d::Transform transform = mRigidBody->getTransform(); + + // Interpolate the transform between the previous one and the new one + rp3d::Transform interpolatedTransform = rp3d::Transform::interpolateTransforms(mPreviousTransform, + transform, + interpolationFactor); // Compute the transform used for rendering the sphere rp3d::decimal matrix[16]; - transform.getOpenGLMatrix(matrix); + interpolatedTransform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], diff --git a/testbed/common/Capsule.h b/testbed/common/Capsule.h index 2ce438d1..6954fb85 100644 --- a/testbed/common/Capsule.h +++ b/testbed/common/Capsule.h @@ -49,6 +49,9 @@ class Capsule : public openglframework::Mesh { /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; + /// Previous transform (for interpolation) + rp3d::Transform mPreviousTransform; + // -------------------- Methods -------------------- // public : @@ -74,7 +77,7 @@ class Capsule : public openglframework::Mesh { reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the sphere - void updateTransform(); + void updateTransform(float interpolationFactor); /// Render the sphere at the correct position and with the correct orientation void render(openglframework::Shader& shader, diff --git a/testbed/common/Cone.cpp b/testbed/common/Cone.cpp index 9e3f24b6..c6cbc070 100644 --- a/testbed/common/Cone.cpp +++ b/testbed/common/Cone.cpp @@ -57,6 +57,8 @@ Cone::Cone(float radius, float height, const openglframework::Vector3 &position, rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); + mPreviousTransform = transform; + // Create a rigid body corresponding to the cone in the dynamics world mRigidBody = world->createCollisionBody(transform); @@ -161,14 +163,19 @@ void Cone::render(openglframework::Shader& shader, } // Update the transform matrix of the cone -void Cone::updateTransform() { +void Cone::updateTransform(float interpolationFactor) { - // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + // Get the transform of the rigid body + rp3d::Transform transform = mRigidBody->getTransform(); + + // Interpolate the transform between the previous one and the new one + rp3d::Transform interpolatedTransform = rp3d::Transform::interpolateTransforms(mPreviousTransform, + transform, + interpolationFactor); // Compute the transform used for rendering the cone rp3d::decimal matrix[16]; - transform.getOpenGLMatrix(matrix); + interpolatedTransform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], diff --git a/testbed/common/Cone.h b/testbed/common/Cone.h index d3002eab..56e3e9db 100644 --- a/testbed/common/Cone.h +++ b/testbed/common/Cone.h @@ -49,6 +49,9 @@ class Cone : public openglframework::Mesh { /// Scaling matrix (applied to a sphere to obtain the correct cone dimensions) openglframework::Matrix4 mScalingMatrix; + /// Previous transform (for interpolation) + rp3d::Transform mPreviousTransform; + // -------------------- Methods -------------------- // public : @@ -73,7 +76,7 @@ class Cone : public openglframework::Mesh { reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the cone - void updateTransform(); + void updateTransform(float interpolationFactor); /// Render the cone at the correct position and with the correct orientation void render(openglframework::Shader& shader, diff --git a/testbed/common/ConvexMesh.cpp b/testbed/common/ConvexMesh.cpp index dbb2c28a..b7d9a59d 100644 --- a/testbed/common/ConvexMesh.cpp +++ b/testbed/common/ConvexMesh.cpp @@ -79,6 +79,8 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); + mPreviousTransform = transform; + // Create a rigid body corresponding to the sphere in the dynamics world mRigidBody = world->createCollisionBody(transform); @@ -200,14 +202,19 @@ void ConvexMesh::render(openglframework::Shader& shader, } // Update the transform matrix of the sphere -void ConvexMesh::updateTransform() { +void ConvexMesh::updateTransform(float interpolationFactor) { - // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + // Get the transform of the rigid body + rp3d::Transform transform = mRigidBody->getTransform(); + + // Interpolate the transform between the previous one and the new one + rp3d::Transform interpolatedTransform = rp3d::Transform::interpolateTransforms(mPreviousTransform, + transform, + interpolationFactor); // Compute the transform used for rendering the sphere rp3d::decimal matrix[16]; - transform.getOpenGLMatrix(matrix); + interpolatedTransform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], diff --git a/testbed/common/ConvexMesh.h b/testbed/common/ConvexMesh.h index f97ec5ec..8f3457dc 100644 --- a/testbed/common/ConvexMesh.h +++ b/testbed/common/ConvexMesh.h @@ -40,6 +40,9 @@ class ConvexMesh : public openglframework::Mesh { /// Rigid body used to simulate the dynamics of the mesh rp3d::CollisionBody* mRigidBody; + /// Previous transform (for interpolation) + rp3d::Transform mPreviousTransform; + // -------------------- Methods -------------------- // public : @@ -64,7 +67,7 @@ class ConvexMesh : public openglframework::Mesh { reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the mesh - void updateTransform(); + void updateTransform(float interpolationFactor); /// Render the mesh at the correct position and with the correct orientation void render(openglframework::Shader& shader, diff --git a/testbed/common/Cylinder.cpp b/testbed/common/Cylinder.cpp index 7c2b7690..a66d4664 100644 --- a/testbed/common/Cylinder.cpp +++ b/testbed/common/Cylinder.cpp @@ -57,6 +57,8 @@ Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& p rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); + mPreviousTransform = transform; + // Create a rigid body corresponding to the cylinder in the dynamics world mRigidBody = world->createCollisionBody(transform); @@ -161,14 +163,19 @@ void Cylinder::render(openglframework::Shader& shader, } // Update the transform matrix of the cylinder -void Cylinder::updateTransform() { +void Cylinder::updateTransform(float interpolationFactor) { - // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + // Get the transform of the rigid body + rp3d::Transform transform = mRigidBody->getTransform(); + + // Interpolate the transform between the previous one and the new one + rp3d::Transform interpolatedTransform = rp3d::Transform::interpolateTransforms(mPreviousTransform, + transform, + interpolationFactor); // Compute the transform used for rendering the cylinder rp3d::decimal matrix[16]; - transform.getOpenGLMatrix(matrix); + interpolatedTransform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], diff --git a/testbed/common/Cylinder.h b/testbed/common/Cylinder.h index 9236fe20..bfea6f4e 100644 --- a/testbed/common/Cylinder.h +++ b/testbed/common/Cylinder.h @@ -49,6 +49,9 @@ class Cylinder : public openglframework::Mesh { /// Scaling matrix (applied to a sphere to obtain the correct cylinder dimensions) openglframework::Matrix4 mScalingMatrix; + /// Previous transform (for interpolation) + rp3d::Transform mPreviousTransform; + // -------------------- Methods -------------------- // public : @@ -73,7 +76,7 @@ class Cylinder : public openglframework::Mesh { reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the cylinder - void updateTransform(); + void updateTransform(float interpolationFactor); /// Render the cylinder at the correct position and with the correct orientation void render(openglframework::Shader& shader, diff --git a/testbed/common/Dumbbell.cpp b/testbed/common/Dumbbell.cpp index a358db61..3059d974 100644 --- a/testbed/common/Dumbbell.cpp +++ b/testbed/common/Dumbbell.cpp @@ -64,6 +64,8 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, rp3d::Quaternion initOrientation(angleAroundX, 0, 0); rp3d::Transform transformBody(initPosition, initOrientation); + mPreviousTransform = transformBody; + // Initial transform of the first sphere collision shape of the dumbbell (in local-space) rp3d::Transform transformSphereShape1(rp3d::Vector3(0, 4.0, 0), rp3d::Quaternion::identity()); @@ -197,14 +199,19 @@ void Dumbbell::render(openglframework::Shader& shader, } // Update the transform matrix of the sphere -void Dumbbell::updateTransform() { +void Dumbbell::updateTransform(float interpolationFactor) { - // Get the interpolated transform of the rigid body - rp3d::Transform transform = mBody->getInterpolatedTransform(); + // Get the transform of the rigid body + rp3d::Transform transform = mBody->getTransform(); + + // Interpolate the transform between the previous one and the new one + rp3d::Transform interpolatedTransform = rp3d::Transform::interpolateTransforms(mPreviousTransform, + transform, + interpolationFactor); // Compute the transform used for rendering the sphere rp3d::decimal matrix[16]; - transform.getOpenGLMatrix(matrix); + interpolatedTransform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], diff --git a/testbed/common/Dumbbell.h b/testbed/common/Dumbbell.h index ff673951..d2dc0bbd 100644 --- a/testbed/common/Dumbbell.h +++ b/testbed/common/Dumbbell.h @@ -46,6 +46,9 @@ class Dumbbell : public openglframework::Mesh { /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; + /// Previous transform (for interpolation) + rp3d::Transform mPreviousTransform; + // -------------------- Methods -------------------- // public : @@ -71,7 +74,7 @@ class Dumbbell : public openglframework::Mesh { rp3d::CollisionBody* getCollisionBody(); /// Update the transform matrix of the sphere - void updateTransform(); + void updateTransform(float interpolationFactor); /// Render the sphere at the correct position and with the correct orientation void render(openglframework::Shader& shader, diff --git a/testbed/common/Line.h b/testbed/common/Line.h index 41de3266..5f6b0d1f 100644 --- a/testbed/common/Line.h +++ b/testbed/common/Line.h @@ -58,9 +58,6 @@ class Line : public openglframework::Object3D { /// Return the second point of the line openglframework::Vector3 getPoint2() const; - /// Update the transform matrix of the sphere - void updateTransform(); - /// Render the line at the correct position and with the correct orientation void render(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix); diff --git a/testbed/common/Sphere.cpp b/testbed/common/Sphere.cpp index 56882569..280ddd73 100644 --- a/testbed/common/Sphere.cpp +++ b/testbed/common/Sphere.cpp @@ -57,6 +57,8 @@ Sphere::Sphere(float radius, const openglframework::Vector3 &position, rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); + mPreviousTransform = transform; + // Create a rigid body corresponding to the sphere in the dynamics world mRigidBody = world->createCollisionBody(transform); @@ -161,14 +163,19 @@ void Sphere::render(openglframework::Shader& shader, } // Update the transform matrix of the sphere -void Sphere::updateTransform() { +void Sphere::updateTransform(float interpolationFactor) { - // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + // Get the transform of the rigid body + rp3d::Transform transform = mRigidBody->getTransform(); + + // Interpolate the transform between the previous one and the new one + rp3d::Transform interpolatedTransform = rp3d::Transform::interpolateTransforms(mPreviousTransform, + transform, + interpolationFactor); // Compute the transform used for rendering the sphere rp3d::decimal matrix[16]; - transform.getOpenGLMatrix(matrix); + interpolatedTransform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], diff --git a/testbed/common/Sphere.h b/testbed/common/Sphere.h index 08a335f7..84b6739d 100644 --- a/testbed/common/Sphere.h +++ b/testbed/common/Sphere.h @@ -46,6 +46,9 @@ class Sphere : public openglframework::Mesh { /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; + /// Previous transform (for interpolation) + rp3d::Transform mPreviousTransform; + // -------------------- Methods -------------------- // public : @@ -70,7 +73,7 @@ class Sphere : public openglframework::Mesh { reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the sphere - void updateTransform(); + void updateTransform(float interpolationFactor); /// Render the sphere at the correct position and with the correct orientation void render(openglframework::Shader& shader, diff --git a/testbed/scenes/collisionshapes/CollisionShapesScene.cpp b/testbed/scenes/collisionshapes/CollisionShapesScene.cpp index b6bebe79..3dd02d24 100644 --- a/testbed/scenes/collisionshapes/CollisionShapesScene.cpp +++ b/testbed/scenes/collisionshapes/CollisionShapesScene.cpp @@ -53,7 +53,7 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name) rp3d::decimal timeStep = 1.0f / 60.0f; // Create the dynamics world for the physics simulation - mDynamicsWorld = new rp3d::DynamicsWorld(gravity, timeStep); + mDynamicsWorld = new rp3d::DynamicsWorld(gravity); // Set the number of iterations of the constraint solver mDynamicsWorld->setNbIterationsVelocitySolver(15); @@ -216,9 +216,6 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name) // Change the material properties of the rigid body rp3d::Material& material = mFloor->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.2)); - - // Start the simulation - mDynamicsWorld->start(); } // Destructor @@ -309,46 +306,49 @@ CollisionShapesScene::~CollisionShapesScene() { delete mDynamicsWorld; } -// Take a step for the simulation -void CollisionShapesScene::update() { - +// Update the physics world (take a simulation step) +void CollisionShapesScene::updatePhysics() { // Take a simulation step - mDynamicsWorld->update(); + mDynamicsWorld->update(mEngineSettings.timeStep); +} + +// Take a step for the simulation +void CollisionShapesScene::update() { // Update the position and orientation of the boxes for (std::vector::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } // Update the position and orientation of the sphere for (std::vector::iterator it = mSpheres.begin(); it != mSpheres.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } // Update the position and orientation of the cones for (std::vector::iterator it = mCones.begin(); it != mCones.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } // Update the position and orientation of the cylinders for (std::vector::iterator it = mCylinders.begin(); it != mCylinders.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } // Update the position and orientation of the capsules for (std::vector::iterator it = mCapsules.begin(); it != mCapsules.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } // Update the position and orientation of the convex meshes @@ -356,7 +356,7 @@ void CollisionShapesScene::update() { it != mConvexMeshes.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } // Update the position and orientation of the dumbbells @@ -364,10 +364,10 @@ void CollisionShapesScene::update() { it != mDumbbells.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } - mFloor->updateTransform(); + mFloor->updateTransform(mInterpolationFactor); } // Render the scene diff --git a/testbed/scenes/collisionshapes/CollisionShapesScene.h b/testbed/scenes/collisionshapes/CollisionShapesScene.h index a9b79e45..4a4e49b3 100644 --- a/testbed/scenes/collisionshapes/CollisionShapesScene.h +++ b/testbed/scenes/collisionshapes/CollisionShapesScene.h @@ -114,6 +114,10 @@ class CollisionShapesScene : public Scene{ /// Destructor virtual ~CollisionShapesScene(); + /// Update the physics world (take a simulation step) + /// Can be called several times per frame + virtual void updatePhysics(); + /// Take a step for the simulation virtual void update(); diff --git a/testbed/scenes/cubes/CubesScene.cpp b/testbed/scenes/cubes/CubesScene.cpp index eb31d77e..e44d10e1 100644 --- a/testbed/scenes/cubes/CubesScene.cpp +++ b/testbed/scenes/cubes/CubesScene.cpp @@ -52,7 +52,7 @@ CubesScene::CubesScene(const std::string& name) rp3d::decimal timeStep = 1.0f / 60.0f; // Create the dynamics world for the physics simulation - mDynamicsWorld = new rp3d::DynamicsWorld(gravity, timeStep); + mDynamicsWorld = new rp3d::DynamicsWorld(gravity); // Set the number of iterations of the constraint solver mDynamicsWorld->setNbIterationsVelocitySolver(15); @@ -89,18 +89,11 @@ CubesScene::CubesScene(const std::string& name) // Change the material properties of the floor rigid body rp3d::Material& material = mFloor->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.3)); - - // Start the simulation - mDynamicsWorld->start(); - - counter=0; } // Destructor CubesScene::~CubesScene() { - mDynamicsWorld->stop(); - // Destroy the shader mPhongShader.destroy(); @@ -124,25 +117,24 @@ CubesScene::~CubesScene() { delete mDynamicsWorld; } -// Take a step for the simulation -void CubesScene::update() { - - counter++; - if (counter == 400) { - //mIsRunning = false; - } +// Update the physics world (take a simulation step) +void CubesScene::updatePhysics() { // Take a simulation step - mDynamicsWorld->update(); + mDynamicsWorld->update(mEngineSettings.timeStep); +} + +// Update the scene +void CubesScene::update() { // Update the position and orientation of the boxes for (std::vector::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) { // Update the transform used for the rendering - (*it)->updateTransform(); + (*it)->updateTransform(mInterpolationFactor); } - mFloor->updateTransform(); + mFloor->updateTransform(mInterpolationFactor); // Set the color of the awake/sleeping bodies for (uint i=0; isetNbIterationsVelocitySolver(15); @@ -72,17 +72,11 @@ JointsScene::JointsScene(const std::string& name) // Create the floor createFloor(); - - // Start the simulation - mDynamicsWorld->start(); } // Destructor JointsScene::~JointsScene() { - // Stop the physics simulation - mDynamicsWorld->stop(); - // Destroy the shader mPhongShader.destroy(); @@ -122,28 +116,32 @@ JointsScene::~JointsScene() { delete mDynamicsWorld; } -// Take a step for the simulation -void JointsScene::update() { +// Update the physics world (take a simulation step) +void JointsScene::updatePhysics() { // Update the motor speed of the Slider Joint (to move up and down) - long double motorSpeed = 2 * cos(mDynamicsWorld->getPhysicsTime() * 1.5); + long double motorSpeed = 2 * cos(mEngineSettings.elapsedTime * 1.5); mSliderJoint->setMotorSpeed(rp3d::decimal(motorSpeed)); // Take a simulation step - mDynamicsWorld->update(); + mDynamicsWorld->update(mEngineSettings.timeStep); +} + +// Take a step for the simulation +void JointsScene::update() { // Update the position and orientation of the boxes - mSliderJointBottomBox->updateTransform(); - mSliderJointTopBox->updateTransform(); - mPropellerBox->updateTransform(); - mFixedJointBox1->updateTransform(); - mFixedJointBox2->updateTransform(); + mSliderJointBottomBox->updateTransform(mInterpolationFactor); + mSliderJointTopBox->updateTransform(mInterpolationFactor); + mPropellerBox->updateTransform(mInterpolationFactor); + mFixedJointBox1->updateTransform(mInterpolationFactor); + mFixedJointBox2->updateTransform(mInterpolationFactor); for (int i=0; iupdateTransform(); + mBallAndSocketJointChainBoxes[i]->updateTransform(mInterpolationFactor); } // Update the position and orientation of the floor - mFloor->updateTransform(); + mFloor->updateTransform(mInterpolationFactor); } // Render the scene diff --git a/testbed/scenes/joints/JointsScene.h b/testbed/scenes/joints/JointsScene.h index 18920700..a55682e9 100644 --- a/testbed/scenes/joints/JointsScene.h +++ b/testbed/scenes/joints/JointsScene.h @@ -127,6 +127,10 @@ class JointsScene : public Scene { /// Destructor virtual ~JointsScene(); + /// Update the physics world (take a simulation step) + /// Can be called several times per frame + virtual void updatePhysics(); + /// Take a step for the simulation virtual void update(); diff --git a/testbed/scenes/raycast/RaycastScene.cpp b/testbed/scenes/raycast/RaycastScene.cpp index 0eef3411..d3d42eb4 100644 --- a/testbed/scenes/raycast/RaycastScene.cpp +++ b/testbed/scenes/raycast/RaycastScene.cpp @@ -227,6 +227,11 @@ RaycastScene::~RaycastScene() { } } +// Update the physics world (take a simulation step) +void RaycastScene::updatePhysics() { + +} + // Take a step for the simulation void RaycastScene::update() { diff --git a/testbed/scenes/raycast/RaycastScene.h b/testbed/scenes/raycast/RaycastScene.h index fc809731..f3e6ed4d 100644 --- a/testbed/scenes/raycast/RaycastScene.h +++ b/testbed/scenes/raycast/RaycastScene.h @@ -177,6 +177,10 @@ class RaycastScene : public Scene { /// Destructor virtual ~RaycastScene(); + /// Update the physics world (take a simulation step) + /// Can be called several times per frame + virtual void updatePhysics(); + /// Take a step for the simulation virtual void update(); diff --git a/testbed/src/Scene.cpp b/testbed/src/Scene.cpp index 497e79ae..5d832746 100644 --- a/testbed/src/Scene.cpp +++ b/testbed/src/Scene.cpp @@ -30,7 +30,7 @@ using namespace openglframework; // Constructor -Scene::Scene(const std::string& name) : mName(name) { +Scene::Scene(const std::string& name) : mName(name), mInterpolationFactor(0.0f) { } diff --git a/testbed/src/Scene.h b/testbed/src/Scene.h index ebe3476a..501aa970 100644 --- a/testbed/src/Scene.h +++ b/testbed/src/Scene.h @@ -29,6 +29,16 @@ // Libraries #include "openglframework.h" +/// Structure EngineSettings +/// This structure contains several physics engine parameters +struct EngineSettings { + + public: + + float elapsedTime; // Elapsed time (in seconds) + float timeStep; // Current time step (in seconds) +}; + // Class Scene // Abstract class that represents a 3D scene. class Scene { @@ -40,6 +50,9 @@ class Scene { /// Scene name std::string mName; + /// Physics engine settings + EngineSettings mEngineSettings; + /// Camera openglframework::Camera mCamera; @@ -58,6 +71,9 @@ class Scene { /// True if the last point computed on a sphere (for camera rotation) is valid bool mIsLastPointOnSphereValid; + /// Interpolation factor for the bodies in the current frame + float mInterpolationFactor; + // -------------------- Methods -------------------- // /// Set the scene position (where the camera needs to look at) @@ -93,7 +109,11 @@ class Scene { /// Reshape the view virtual void reshape(int width, int height); - /// Update the scene (take a simulation step) + /// Update the physics world (take a simulation step) + /// Can be called several times per frame + virtual void updatePhysics()=0; + + /// Update the scene virtual void update()=0; /// Render the scene @@ -121,6 +141,12 @@ class Scene { /// Return a reference to the camera const openglframework::Camera& getCamera() const; + + /// Set the engine settings + void setEngineSettings(const EngineSettings& settings); + + /// Set the interpolation factor + void setInterpolationFactor(float interpolationFactor); }; // Called when a keyboard event occurs @@ -144,5 +170,14 @@ inline void Scene::setWindowDimension(int width, int height) { mWindowHeight = height; } +// Set the engine settings +inline void Scene::setEngineSettings(const EngineSettings& settings) { + mEngineSettings = settings; +} + +// Set the interpolation factor +inline void Scene::setInterpolationFactor(float interpolationFactor) { + mInterpolationFactor = interpolationFactor; +} #endif diff --git a/testbed/src/TestbedApplication.cpp b/testbed/src/TestbedApplication.cpp index 0b7e8a55..a4ca82f8 100644 --- a/testbed/src/TestbedApplication.cpp +++ b/testbed/src/TestbedApplication.cpp @@ -124,6 +124,8 @@ void TestbedApplication::init() { // Create all the scenes createScenes(); + + mTimer.start(); } // Create all the scenes @@ -159,9 +161,40 @@ void TestbedApplication::destroyScenes() { mCurrentScene = NULL; } +// Update the physics of the current scene +void TestbedApplication::updatePhysics() { + + // Set the engine settings + mEngineSettings.elapsedTime = mTimer.getPhysicsTime(); + mCurrentScene->setEngineSettings(mEngineSettings); + + if (mTimer.isRunning()) { + + // Compute the time since the last update() call and update the timer + mTimer.update(); + + // While the time accumulator is not empty + while(mTimer.isPossibleToTakeStep()) { + + // Take a physics simulation step + mCurrentScene->updatePhysics(); + + // Update the timer + mTimer.nextStep(); + } + } +} + void TestbedApplication::update() { - // Physics simulation + // Compute the interpolation factor + float factor = mTimer.computeInterpolationFactor(mEngineSettings.timeStep); + assert(factor >= 0.0f && factor <= 1.0f); + + // Notify the scene about the interpolation factor + mCurrentScene->setInterpolationFactor(factor); + + // Update the scene mCurrentScene->update(); // Compute the current framerate diff --git a/testbed/src/TestbedApplication.h b/testbed/src/TestbedApplication.h index 7472bbee..e3c5121a 100644 --- a/testbed/src/TestbedApplication.h +++ b/testbed/src/TestbedApplication.h @@ -30,6 +30,7 @@ #include "openglframework.h" #include "GUI.h" #include "Scene.h" +#include "Timer.h" #include /// Class TestbedApplication @@ -50,12 +51,18 @@ class TestbedApplication { /// Graphical User Interface Gui mGUI; + /// Timer + Timer mTimer; + /// List of 3D scenes std::vector mScenes; /// Current 3D scene Scene* mCurrentScene; + /// Physics engine settings + EngineSettings mEngineSettings; + /// Current number of frames per seconds double mFPS; @@ -85,6 +92,9 @@ class TestbedApplication { /// Private assignment operator (for the singleton class) void operator=(TestbedApplication const&); + /// Update the physics of the current scene + void updatePhysics(); + /// Update void update(); diff --git a/testbed/src/Timer.cpp b/testbed/src/Timer.cpp new file mode 100644 index 00000000..a7849534 --- /dev/null +++ b/testbed/src/Timer.cpp @@ -0,0 +1,64 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include "Timer.h" + + +// Constructor +Timer::Timer() : mIsRunning(false) { + +} + +// Destructor +Timer::~Timer() { + +} + +// Return the current time of the system in seconds +long double Timer::getCurrentSystemTime() { + + #if defined(WINDOWS_OS) + LARGE_INTEGER ticksPerSecond; + LARGE_INTEGER ticks; + QueryPerformanceFrequency(&ticksPerSecond); + QueryPerformanceCounter(&ticks); + return (long double(ticks.QuadPart) / long double(ticksPerSecond.QuadPart)); + #else + // Initialize the lastUpdateTime with the current time in seconds + timeval timeValue; + gettimeofday(&timeValue, NULL); + return (timeValue.tv_sec + (timeValue.tv_usec / 1000000.0)); + #endif +} + + + + + + + + + diff --git a/testbed/src/Timer.h b/testbed/src/Timer.h new file mode 100644 index 00000000..f551ec1f --- /dev/null +++ b/testbed/src/Timer.h @@ -0,0 +1,177 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TIMER_H +#define TIMER_H + +// Libraries +#include +#include +#include +#include +#include "configuration.h" + +#if defined(WINDOWS_OS) // For Windows platform + #define NOMINMAX // This is used to avoid definition of max() and min() macros + #include +#else // For Mac OS or Linux platform + #include +#endif + +// Class Timer +/** + * This class will take care of the time in the physics engine. It + * uses functions that depend on the current platform to get the + * current time. + */ +class Timer { + + private : + + // -------------------- Attributes -------------------- // + + /// Timestep dt of the physics engine (timestep > 0.0) + double mTimeStep; + + /// Last time the timer has been updated + long double mLastUpdateTime; + + /// Time difference between the two last timer update() calls + long double mDeltaTime; + + /// Used to fix the time step and avoid strange time effects + double mAccumulator; + + /// True if the timer is running + bool mIsRunning; + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + Timer(const Timer& timer); + + /// Private assignment operator + Timer& operator=(const Timer& timer); + + public : + + // -------------------- Methods -------------------- // + + /// Constructor + Timer(); + + /// Destructor + virtual ~Timer(); + + /// Return the current time of the physics engine + long double getPhysicsTime() const; + + /// Start the timer + void start(); + + /// Stop the timer + void stop(); + + /// Return true if the timer is running + bool isRunning() const; + + /// True if it's possible to take a new step + bool isPossibleToTakeStep() const; + + /// Compute the time since the last update() call and add it to the accumulator + void update(); + + /// Take a new step => update the timer by adding the timeStep value to the current time + void nextStep(); + + /// Compute the interpolation factor + float computeInterpolationFactor(float timeStep); + + /// Return the current time of the system in seconds + static long double getCurrentSystemTime(); +}; + +// Return the current time +inline long double Timer::getPhysicsTime() const { + return mLastUpdateTime; +} + +// Return if the timer is running +inline bool Timer::isRunning() const { + return mIsRunning; +} + +// Start the timer +inline void Timer::start() { + if (!mIsRunning) { + + // Get the current system time + mLastUpdateTime = getCurrentSystemTime(); + + mAccumulator = 0.0; + mIsRunning = true; + } +} + +// Stop the timer +inline void Timer::stop() { + mIsRunning = false; +} + +// True if it's possible to take a new step +inline bool Timer::isPossibleToTakeStep() const { + return (mAccumulator >= mTimeStep); +} + +// Take a new step => update the timer by adding the timeStep value to the current time +inline void Timer::nextStep() { + assert(mIsRunning); + + // Update the accumulator value + mAccumulator -= mTimeStep; +} + +// Compute the interpolation factor +inline float Timer::computeInterpolationFactor(float timeStep) { + return (float(mAccumulator) / timeStep); +} + +// Compute the time since the last update() call and add it to the accumulator +inline void Timer::update() { + + // Get the current system time + long double currentTime = getCurrentSystemTime(); + + // Compute the delta display time between two display frames + mDeltaTime = currentTime - mLastUpdateTime; + + // Update the current display time + mLastUpdateTime = currentTime; + + // Update the accumulator value + mAccumulator += mDeltaTime; +} + + #endif