diff --git a/testbed/CMakeLists.txt b/testbed/CMakeLists.txt index ff1ad9bb..895f0995 100644 --- a/testbed/CMakeLists.txt +++ b/testbed/CMakeLists.txt @@ -69,6 +69,8 @@ SET(COMMON_SOURCES common/Cylinder.cpp common/Dumbbell.h common/Dumbbell.cpp + common/HeightField.h + common/HeightField.cpp common/PhysicsObject.h common/PhysicsObject.cpp common/VisualContactPoint.h @@ -87,6 +89,8 @@ SET(SCENES_SOURCES scenes/collisionshapes/CollisionShapesScene.cpp scenes/concavemesh/ConcaveMeshScene.h scenes/concavemesh/ConcaveMeshScene.cpp + scenes/heightfield/HeightFieldScene.h + scenes/heightfield/HeightFieldScene.cpp ) # Add .user file to set debug path in Visual Studio diff --git a/testbed/common/ConcaveMesh.cpp b/testbed/common/ConcaveMesh.cpp index cf355919..3601e34a 100644 --- a/testbed/common/ConcaveMesh.cpp +++ b/testbed/common/ConcaveMesh.cpp @@ -121,6 +121,8 @@ ConcaveMesh::ConcaveMesh(const openglframework::Vector3 &position, float mass, // do not forget to delete it at the end mConcaveShape = new rp3d::ConcaveMeshShape(&mPhysicsTriangleMesh); + mConcaveShape->setIsSmoothMeshCollisionEnabled(false); + // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); diff --git a/testbed/common/HeightField.cpp b/testbed/common/HeightField.cpp new file mode 100644 index 00000000..d628dce2 --- /dev/null +++ b/testbed/common/HeightField.cpp @@ -0,0 +1,329 @@ +/******************************************************************************** +* 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 "HeightField.h" + +// Constructor +HeightField::HeightField(const openglframework::Vector3 &position, + reactphysics3d::CollisionWorld* world) + : openglframework::Mesh(), mVBOVertices(GL_ARRAY_BUFFER), + mVBONormals(GL_ARRAY_BUFFER), mVBOTextureCoords(GL_ARRAY_BUFFER), + mVBOIndices(GL_ELEMENT_ARRAY_BUFFER) { + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4::identity(); + + // Generate the height field + generateHeightField(); + + // Generate the graphics mesh + generateGraphicsMesh(); + + // Create the collision shape for the rigid body (convex mesh shape) and + // do not forget to delete it at the end + mHeightFieldShape = new rp3d::HeightFieldShape(HEIGHTFIELD_WIDTH, HEIGHTFIELD_LENGTH, 0, 5, + mHeightData, rp3d::HeightFieldShape::HEIGHT_FLOAT_TYPE); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + 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 + mBody = world->createCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the collision shape + mProxyShape = mBody->addCollisionShape(mHeightFieldShape, rp3d::Transform::identity()); + + // Create the VBOs and VAO + createVBOAndVAO(); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Constructor +HeightField::HeightField(const openglframework::Vector3 &position, float mass, + reactphysics3d::DynamicsWorld* dynamicsWorld) + : openglframework::Mesh(), mVBOVertices(GL_ARRAY_BUFFER), + mVBONormals(GL_ARRAY_BUFFER), mVBOTextureCoords(GL_ARRAY_BUFFER), + mVBOIndices(GL_ELEMENT_ARRAY_BUFFER) { + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4::identity(); + + // Generate the height field + generateHeightField(); + + // Generate the graphics mesh + generateGraphicsMesh(); + + // Create the collision shape for the rigid body (convex mesh shape) and + // do not forget to delete it at the end + mHeightFieldShape = new rp3d::HeightFieldShape(HEIGHTFIELD_WIDTH, HEIGHTFIELD_LENGTH, 0, 5, + mHeightData, rp3d::HeightFieldShape::HEIGHT_FLOAT_TYPE); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transform(initPosition, initOrientation); + + // Create a rigid body corresponding to the sphere in the dynamics world + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the collision shape + mProxyShape = body->addCollisionShape(mHeightFieldShape, rp3d::Transform::identity(), mass); + + mBody = body; + + // Create the VBOs and VAO + createVBOAndVAO(); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Destructor +HeightField::~HeightField() { + + // Destroy the mesh + destroy(); + + // Destroy the VBOs and VAO + mVBOIndices.destroy(); + mVBOVertices.destroy(); + mVBONormals.destroy(); + mVBOTextureCoords.destroy(); + mVAO.destroy(); + + delete mHeightFieldShape; +} + +// Render the sphere at the correct position and with the correct orientation +void HeightField::render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix) { + + // Bind the shader + shader.bind(); + + // Set the model to camera matrix + shader.setMatrix4x4Uniform("localToWorldMatrix", mTransformMatrix); + shader.setMatrix4x4Uniform("worldToCameraMatrix", worldToCameraMatrix); + + // Set the normal matrix (inverse transpose of the 3x3 upper-left sub matrix of the + // model-view matrix) + const openglframework::Matrix4 localToCameraMatrix = worldToCameraMatrix * mTransformMatrix; + const openglframework::Matrix3 normalMatrix = + localToCameraMatrix.getUpperLeft3x3Matrix().getInverse().getTranspose(); + shader.setMatrix3x3Uniform("normalMatrix", normalMatrix, false); + + // Set the vertex color + openglframework::Vector4 color(mColor.r, mColor.g, mColor.b, mColor.a); + shader.setVector4Uniform("vertexColor", color, false); + + // Bind the VAO + mVAO.bind(); + + mVBOVertices.bind(); + + // Get the location of shader attribute variables + GLint vertexPositionLoc = shader.getAttribLocation("vertexPosition"); + GLint vertexNormalLoc = shader.getAttribLocation("vertexNormal", false); + + glEnableVertexAttribArray(vertexPositionLoc); + glVertexAttribPointer(vertexPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL); + + mVBONormals.bind(); + + if (vertexNormalLoc != -1) glVertexAttribPointer(vertexNormalLoc, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL); + if (vertexNormalLoc != -1) glEnableVertexAttribArray(vertexNormalLoc); + + // For each part of the mesh + for (unsigned int i=0; i indices; + int vertexId = 0; + + for (int i=0; isetTransform(transform); + + mBody->setIsSleeping(false); + + // Reset the velocity of the rigid body + rp3d::RigidBody* rigidBody = dynamic_cast(mBody); + if (rigidBody != NULL) { + rigidBody->setLinearVelocity(rp3d::Vector3(0, 0, 0)); + rigidBody->setAngularVelocity(rp3d::Vector3(0, 0, 0)); + } + + updateTransform(1.0f); +} + +// Set the scaling of the object +void HeightField::setScaling(const openglframework::Vector3& scaling) { + + // Scale the collision shape + mProxyShape->setLocalScaling(rp3d::Vector3(scaling.x, scaling.y, scaling.z)); + + // Scale the graphics object + mScalingMatrix = openglframework::Matrix4(scaling.x, 0, 0, 0, + 0, scaling.y, 0,0, + 0, 0, scaling.z, 0, + 0, 0, 0, 1.0f); +} + diff --git a/testbed/common/HeightField.h b/testbed/common/HeightField.h new file mode 100644 index 00000000..3424e241 --- /dev/null +++ b/testbed/common/HeightField.h @@ -0,0 +1,120 @@ +/******************************************************************************** +* 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 HEIGHT_FIELD_H +#define HEIGHT_FIELD_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" +#include "PhysicsObject.h" + +// Class HeightField +class HeightField : public openglframework::Mesh, public PhysicsObject { + + private : + + static const int HEIGHTFIELD_WIDTH = 10; + static const int HEIGHTFIELD_LENGTH = 5; + + // -------------------- Attributes -------------------- // + + /// Height field data + float mHeightData[HEIGHTFIELD_WIDTH][HEIGHTFIELD_LENGTH]; + + /// Previous transform (for interpolation) + rp3d::Transform mPreviousTransform; + + /// Collision shape + rp3d::HeightFieldShape* mHeightFieldShape; + rp3d::ProxyShape* mProxyShape; + + /// Scaling matrix + openglframework::Matrix4 mScalingMatrix; + + /// Vertex Buffer Object for the vertices data + openglframework::VertexBufferObject mVBOVertices; + + /// Vertex Buffer Object for the normals data + openglframework::VertexBufferObject mVBONormals; + + /// Vertex Buffer Object for the texture coords + openglframework::VertexBufferObject mVBOTextureCoords; + + /// Vertex Buffer Object for the indices + openglframework::VertexBufferObject mVBOIndices; + + /// Vertex Array Object for the vertex data + openglframework::VertexArrayObject mVAO; + + /// Min/Max height of the height field values + float mMinHeight, mMaxHeight; + + // -------------------- Methods -------------------- // + + // Create the Vertex Buffer Objects used to render with OpenGL. + void createVBOAndVAO(); + + // Compute the heights of the height field + void generateHeightField(); + + // Generate the graphics mesh to render the height field + void generateGraphicsMesh(); + + public : + + // -------------------- Methods -------------------- // + + /// Constructor + HeightField(const openglframework::Vector3& position, + rp3d::CollisionWorld* world); + + /// Constructor + HeightField(const openglframework::Vector3& position, float mass, + rp3d::DynamicsWorld* dynamicsWorld); + + /// Destructor + ~HeightField(); + + /// Render the mesh at the correct position and with the correct orientation + void render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix); + + /// Set the position of the box + void resetTransform(const rp3d::Transform& transform); + + /// Update the transform matrix of the object + virtual void updateTransform(float interpolationFactor); + + /// Set the scaling of the object + void setScaling(const openglframework::Vector3& scaling); +}; + +// Update the transform matrix of the object +inline void HeightField::updateTransform(float interpolationFactor) { + mTransformMatrix = computeTransform(interpolationFactor, mScalingMatrix); +} + +#endif diff --git a/testbed/scenes/heightfield/HeightFieldScene.cpp b/testbed/scenes/heightfield/HeightFieldScene.cpp new file mode 100644 index 00000000..d2132c86 --- /dev/null +++ b/testbed/scenes/heightfield/HeightFieldScene.cpp @@ -0,0 +1,171 @@ + +/******************************************************************************** +* 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 "HeightFieldScene.h" + +// Namespaces +using namespace openglframework; +using namespace heightfieldscene; + +// Constructor +HeightFieldScene::HeightFieldScene(const std::string& name) : SceneDemo(name, SCENE_RADIUS) { + + // Compute the radius and the center of the scene + openglframework::Vector3 center(0, 5, 0); + + // Set the center of the scene + setScenePosition(center, SCENE_RADIUS); + + // Gravity vector in the dynamics world + rp3d::Vector3 gravity(0, rp3d::decimal(-9.81), 0); + + // Create the dynamics world for the physics simulation + mDynamicsWorld = new rp3d::DynamicsWorld(gravity); + + // Set the number of iterations of the constraint solver + mDynamicsWorld->setNbIterationsVelocitySolver(15); + + // ---------- Create the cube ----------- // + + // Position + rp3d::decimal radius = 2.0; + openglframework::Vector3 spherePos(15, 10, 0); + + // Create a sphere and a corresponding rigid in the dynamics world + mBox = new Box(Vector3(3, 3, 3), spherePos, 80.1, mDynamicsWorld); + + // Set the sphere color + mBox->setColor(mDemoColors[1]); + mBox->setSleepingColor(mRedColorDemo); + + // Change the material properties of the rigid body + rp3d::Material& sphereMat = mBox->getRigidBody()->getMaterial(); + sphereMat.setBounciness(rp3d::decimal(0.2)); + + // ---------- Create the height field ---------- // + + // Position + openglframework::Vector3 position(0, 0, 0); + rp3d::decimal mass = 1.0; + + // Create a convex mesh and a corresponding rigid in the dynamics world + mHeightField = new HeightField(position, mass, mDynamicsWorld); + + // Set the mesh as beeing static + mHeightField->getRigidBody()->setType(rp3d::STATIC); + + // Set the color + mHeightField->setColor(mDemoColors[0]); + mHeightField->setSleepingColor(mRedColorDemo); + + // Change the material properties of the rigid body + rp3d::Material& material = mHeightField->getRigidBody()->getMaterial(); + material.setBounciness(rp3d::decimal(0.2)); + material.setFrictionCoefficient(0.1); + + // Get the physics engine parameters + mEngineSettings.isGravityEnabled = mDynamicsWorld->isGravityEnabled(); + rp3d::Vector3 gravityVector = mDynamicsWorld->getGravity(); + mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z); + mEngineSettings.isSleepingEnabled = mDynamicsWorld->isSleepingEnabled(); + mEngineSettings.sleepLinearVelocity = mDynamicsWorld->getSleepLinearVelocity(); + mEngineSettings.sleepAngularVelocity = mDynamicsWorld->getSleepAngularVelocity(); + mEngineSettings.nbPositionSolverIterations = mDynamicsWorld->getNbIterationsPositionSolver(); + mEngineSettings.nbVelocitySolverIterations = mDynamicsWorld->getNbIterationsVelocitySolver(); + mEngineSettings.timeBeforeSleep = mDynamicsWorld->getTimeBeforeSleep(); +} + +// Destructor +HeightFieldScene::~HeightFieldScene() { + + mDynamicsWorld->destroyRigidBody(mBox->getRigidBody()); + // Destroy the corresponding rigid body from the dynamics world + mDynamicsWorld->destroyRigidBody(mHeightField->getRigidBody()); + + delete mBox; + + // Destroy the convex mesh + delete mHeightField; + + // Destroy the dynamics world + delete mDynamicsWorld; +} + +// Update the physics world (take a simulation step) +void HeightFieldScene::updatePhysics() { + + // Update the physics engine parameters + mDynamicsWorld->setIsGratityEnabled(mEngineSettings.isGravityEnabled); + rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y, + mEngineSettings.gravity.z); + mDynamicsWorld->setGravity(gravity); + mDynamicsWorld->enableSleeping(mEngineSettings.isSleepingEnabled); + mDynamicsWorld->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity); + mDynamicsWorld->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity); + mDynamicsWorld->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations); + mDynamicsWorld->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations); + mDynamicsWorld->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep); + + // Take a simulation step + mDynamicsWorld->update(mEngineSettings.timeStep); +} + +// Update the scene +void HeightFieldScene::update() { + + SceneDemo::update(); + + // Update the transform used for the rendering + mHeightField->updateTransform(mInterpolationFactor); + mBox->updateTransform(mInterpolationFactor); +} + +// Render the scene in a single pass +void HeightFieldScene::renderSinglePass(Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) { + + // Bind the shader + shader.bind(); + + mHeightField->render(shader, worldToCameraMatrix); + mBox->render(shader, worldToCameraMatrix); + + // Unbind the shader + shader.unbind(); +} + +// Reset the scene +void HeightFieldScene::reset() { + + // Reset the transform + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transform(rp3d::Vector3(0, 0, 0), initOrientation); + mHeightField->resetTransform(transform); + + rp3d::Vector3 spherePos(2, 15, 0); + rp3d::Transform sphereTransform(spherePos, initOrientation); + mBox->resetTransform(sphereTransform); +} diff --git a/testbed/scenes/heightfield/HeightFieldScene.h b/testbed/scenes/heightfield/HeightFieldScene.h new file mode 100644 index 00000000..dc0a5c44 --- /dev/null +++ b/testbed/scenes/heightfield/HeightFieldScene.h @@ -0,0 +1,91 @@ +/******************************************************************************** +* 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 HEIGHT_FIELD_SCENE_H +#define HEIGHT_FIELD_SCENE_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" +#include "Box.h" +#include "SceneDemo.h" +#include "HeightField.h" + +namespace heightfieldscene { + +// Constants +const float SCENE_RADIUS = 30.0f; + +// Class HeightFieldScene +class HeightFieldScene : public SceneDemo { + + protected : + + // -------------------- Attributes -------------------- // + + Box* mBox; + + /// Height field + HeightField* mHeightField; + + /// Dynamics world used for the physics simulation + rp3d::DynamicsWorld* mDynamicsWorld; + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + HeightFieldScene(const std::string& name); + + /// Destructor + virtual ~HeightFieldScene(); + + /// Update the physics world (take a simulation step) + /// Can be called several times per frame + virtual void updatePhysics(); + + /// Update the scene (take a simulation step) + virtual void update(); + + /// Render the scene in a single pass + virtual void renderSinglePass(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix); + + /// Reset the scene + virtual void reset(); + + /// Return all the contact points of the scene + virtual std::vector getContactPoints() const; +}; + +// Return all the contact points of the scene +inline std::vector HeightFieldScene::getContactPoints() const { + return computeContactPointsOfWorld(mDynamicsWorld); +} + +} + +#endif diff --git a/testbed/src/TestbedApplication.cpp b/testbed/src/TestbedApplication.cpp index ec8ea200..dd31bcc4 100644 --- a/testbed/src/TestbedApplication.cpp +++ b/testbed/src/TestbedApplication.cpp @@ -32,6 +32,7 @@ #include "cubes/CubesScene.h" #include "joints/JointsScene.h" #include "collisionshapes/CollisionShapesScene.h" +#include "heightfield/HeightFieldScene.h" #include "raycast/RaycastScene.h" #include "concavemesh/ConcaveMeshScene.h" @@ -41,6 +42,7 @@ using namespace cubesscene; using namespace raycastscene; using namespace collisionshapesscene; using namespace trianglemeshscene; +using namespace heightfieldscene; // Initialization of static variables const float TestbedApplication::SCROLL_SENSITIVITY = 0.02f; @@ -164,6 +166,10 @@ void TestbedApplication::createScenes() { CollisionShapesScene* collisionShapesScene = new CollisionShapesScene("Collision Shapes"); mScenes.push_back(collisionShapesScene); + // Heightfield shape scene + HeightFieldScene* heightFieldScene = new HeightFieldScene("Heightfield"); + mScenes.push_back(heightFieldScene); + // Raycast scene RaycastScene* raycastScene = new RaycastScene("Raycast"); mScenes.push_back(raycastScene);