From c1fa7b0f501b66057bce6abd858b09e04109846f Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 29 Nov 2014 13:08:11 +0100 Subject: [PATCH] Add raycasting example --- examples/CMakeLists.txt | 1 + examples/common/Box.cpp | 54 ++- examples/common/Box.h | 20 +- examples/common/Capsule.cpp | 47 ++- examples/common/Capsule.h | 25 +- examples/common/Cone.cpp | 47 ++- examples/common/Cone.h | 22 +- examples/common/ConvexMesh.cpp | 56 +++- examples/common/ConvexMesh.h | 22 +- examples/common/Cylinder.cpp | 47 ++- examples/common/Cylinder.h | 22 +- examples/common/Dumbbell.cpp | 73 ++++- examples/common/Dumbbell.h | 19 +- examples/common/Line.cpp | 59 ++++ examples/common/Line.h | 54 +++ examples/common/Sphere.cpp | 51 ++- examples/common/Sphere.h | 22 +- .../common/opengl-framework/src/maths/Color.h | 9 + examples/raycast/CMakeLists.txt | 43 +++ examples/raycast/Raycast.cpp | 155 +++++++++ examples/raycast/Scene.cpp | 309 ++++++++++++++++++ examples/raycast/Scene.h | 198 +++++++++++ 22 files changed, 1301 insertions(+), 54 deletions(-) create mode 100644 examples/common/Line.cpp create mode 100644 examples/common/Line.h create mode 100644 examples/raycast/CMakeLists.txt create mode 100644 examples/raycast/Raycast.cpp create mode 100644 examples/raycast/Scene.cpp create mode 100644 examples/raycast/Scene.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index edc71428..3743dc56 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,3 +8,4 @@ ADD_SUBDIRECTORY(common/) ADD_SUBDIRECTORY(cubes/) ADD_SUBDIRECTORY(joints/) ADD_SUBDIRECTORY(collisionshapes/) +ADD_SUBDIRECTORY(raycast/) diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index 8c75f481..fb2fd04b 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -58,7 +58,7 @@ GLuint Box::mCubeIndices[36] = { 0, 1, 2, // Constructor Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld) + reactphysics3d::CollisionWorld* world) : openglframework::Object3D(), mColor(0.5f, 0.5f, 0.5f, 1.0f) { // Initialize the size of the box @@ -86,16 +86,64 @@ Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &p rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + mRigidBody = world->createCollisionBody(transform); // Add the collision shape to the body - mRigidBody->addCollisionShape(collisionShape, mass); + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); // If the Vertex Buffer object has not been created yet if (!areVBOsCreated) { // Create the Vertex Buffer createVBO(); } + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Constructor +Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &position, + float mass, reactphysics3d::DynamicsWorld* world) + : openglframework::Object3D(), mColor(0.5f, 0.5f, 0.5f, 1.0f) { + + // Initialize the size of the box + mSize[0] = size.x * 0.5f; + mSize[1] = size.y * 0.5f; + mSize[2] = size.z * 0.5f; + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mSize[0], 0, 0, 0, + 0, mSize[1], 0, 0, + 0, 0, mSize[2], 0, + 0, 0, 0, 1); + + // Initialize the position where the cube will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (box shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::BoxShape collisionShape(rp3d::Vector3(mSize[0], mSize[1], mSize[2])); + + // 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 in the dynamics world + rp3d::RigidBody* body = world->createRigidBody(transform); + + // Add the collision shape to the body + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + // If the Vertex Buffer object has not been created yet + if (!areVBOsCreated) { + // Create the Vertex Buffer + createVBO(); + } + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Box.h b/examples/common/Box.h index e89368a2..3231049d 100644 --- a/examples/common/Box.h +++ b/examples/common/Box.h @@ -54,7 +54,7 @@ class Box : public openglframework::Object3D { float mSize[3]; /// Rigid body used to simulate the dynamics of the box - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a cube to obtain the correct box dimensions) openglframework::Matrix4 mScalingMatrix; @@ -88,13 +88,20 @@ class Box : public openglframework::Object3D { /// Constructor Box(const openglframework::Vector3& size, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld); + reactphysics3d::CollisionWorld* world); + + /// Constructor + Box(const openglframework::Vector3& size, const openglframework::Vector3& position, + float mass, reactphysics3d::DynamicsWorld *world); /// Destructor ~Box(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + /// Return a pointer to the rigid body of the box - rp3d::RigidBody* getRigidBody(); + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the box void updateTransform(); @@ -106,9 +113,14 @@ class Box : public openglframework::Object3D { void setColor(const openglframework::Color& color); }; +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Box::getCollisionBody() { + return mRigidBody; +} + // Return a pointer to the rigid body of the box inline rp3d::RigidBody* Box::getRigidBody() { - return mRigidBody; + return dynamic_cast(mRigidBody); } // Set the color of the box diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index 79efeb5a..fdd08543 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -26,6 +26,45 @@ // Libraries #include "Capsule.h" +// Constructor +Capsule::Capsule(float radius, float height, const openglframework::Vector3& position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius), mHeight(height) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "capsule.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, (mHeight + 2.0f * mRadius) / 3.0f, 0,0, + 0, 0, mRadius, 0, + 0, 0, 0, 1.0f); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (sphere shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::CapsuleShape collisionShape(mRadius, mHeight); + + // 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 in the dynamics world + mRigidBody = world->createCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} // Constructor Capsule::Capsule(float radius, float height, const openglframework::Vector3& position, @@ -59,10 +98,14 @@ Capsule::Capsule(float radius, float height, const openglframework::Vector3& pos rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Capsule.h b/examples/common/Capsule.h index 21168f2f..da05d7b3 100644 --- a/examples/common/Capsule.h +++ b/examples/common/Capsule.h @@ -44,7 +44,7 @@ class Capsule : public openglframework::Mesh { float mHeight; /// Rigid body used to simulate the dynamics of the sphere - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; @@ -57,13 +57,21 @@ class Capsule : public openglframework::Mesh { /// Constructor Capsule(float radius, float height, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); + reactphysics3d::CollisionWorld* world, const std::string& meshFolderPath); + + /// Constructor + Capsule(float radius, float height, const openglframework::Vector3& position, + float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath); /// Destructor ~Capsule(); - /// Return a pointer to the rigid body of the sphere - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the sphere void updateTransform(); @@ -73,9 +81,14 @@ class Capsule : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the sphere -inline rp3d::RigidBody* Capsule::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Capsule::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Capsule::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index 29f59f6d..1372ed63 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -26,6 +26,45 @@ // Libraries #include "Cone.h" +// Constructor +Cone::Cone(float radius, float height, const openglframework::Vector3 &position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius), mHeight(height) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cone.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, mHeight, 0, 0, + 0, 0, mRadius, 0, + 0, 0, 0, 1); + + // Initialize the position where the cone will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (cone shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::ConeShape collisionShape(mRadius, mHeight); + + // 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 cone in the dynamics world + mRigidBody = world->createCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} // Constructor Cone::Cone(float radius, float height, const openglframework::Vector3 &position, @@ -59,10 +98,14 @@ Cone::Cone(float radius, float height, const openglframework::Vector3 &position, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cone in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Cone.h b/examples/common/Cone.h index c0053bf9..ad275554 100644 --- a/examples/common/Cone.h +++ b/examples/common/Cone.h @@ -44,7 +44,7 @@ class Cone : public openglframework::Mesh { float mHeight; /// Rigid body used to simulate the dynamics of the cone - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct cone dimensions) openglframework::Matrix4 mScalingMatrix; @@ -55,6 +55,10 @@ class Cone : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + Cone(float radius, float height, const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string& meshFolderPath); + /// Constructor Cone(float radius, float height, const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); @@ -62,8 +66,11 @@ class Cone : public openglframework::Mesh { /// Destructor ~Cone(); - /// Return a pointer to the rigid body of the cone - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the cone void updateTransform(); @@ -73,9 +80,14 @@ class Cone : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the cone -inline rp3d::RigidBody* Cone::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Cone::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Cone::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index ad5d178f..813b2990 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -26,6 +26,56 @@ // Libraries #include "ConvexMesh.h" +// Constructor +ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh() { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "convexmesh.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (convex mesh shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + rp3d::decimal* verticesArray = (rp3d::decimal*) getVerticesPointer(); + rp3d::ConvexMeshShape collisionShape(verticesArray, mVertices.size(), + sizeof(openglframework::Vector3)); + + // Add the edges information of the mesh into the convex mesh collision shape. + // This is optional but it really speed up the convex mesh collision detection at the + // cost of some additional memory to store the edges inside the collision shape. + for (unsigned int i=0; icreateCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the collision shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); +} // Constructor ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, @@ -72,10 +122,12 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the collision shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; } // Destructor diff --git a/examples/common/ConvexMesh.h b/examples/common/ConvexMesh.h index a558c0f5..0f6d91de 100644 --- a/examples/common/ConvexMesh.h +++ b/examples/common/ConvexMesh.h @@ -38,7 +38,7 @@ class ConvexMesh : public openglframework::Mesh { // -------------------- Attributes -------------------- // /// Rigid body used to simulate the dynamics of the mesh - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; // -------------------- Methods -------------------- // @@ -46,6 +46,10 @@ class ConvexMesh : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + ConvexMesh(const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string& meshFolderPath); + /// Constructor ConvexMesh(const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); @@ -53,8 +57,11 @@ class ConvexMesh : public openglframework::Mesh { /// Destructor ~ConvexMesh(); - /// Return a pointer to the rigid body of the mesh - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the mesh void updateTransform(); @@ -64,9 +71,14 @@ class ConvexMesh : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the mesh -inline rp3d::RigidBody* ConvexMesh::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* ConvexMesh::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* ConvexMesh::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index d4540b41..d464ac8f 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -26,6 +26,45 @@ // Libraries #include "Cylinder.h" +// Constructor +Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius), mHeight(height) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cylinder.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, mHeight, 0, 0, + 0, 0, mRadius, 0, + 0, 0, 0, 1); + + // Initialize the position where the cylinder will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (cylinder shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::CylinderShape collisionShape(mRadius, mHeight); + + // 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 cylinder in the dynamics world + mRigidBody = world->createCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} // Constructor Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& position, @@ -59,10 +98,14 @@ Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& p rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cylinder in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; + + mRigidBody = body; } // Destructor diff --git a/examples/common/Cylinder.h b/examples/common/Cylinder.h index 46988286..90817374 100644 --- a/examples/common/Cylinder.h +++ b/examples/common/Cylinder.h @@ -44,7 +44,7 @@ class Cylinder : public openglframework::Mesh { float mHeight; /// Rigid body used to simulate the dynamics of the cylinder - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct cylinder dimensions) openglframework::Matrix4 mScalingMatrix; @@ -55,6 +55,10 @@ class Cylinder : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + Cylinder(float radius, float height, const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string &meshFolderPath); + /// Constructor Cylinder(float radius, float height, const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string &meshFolderPath); @@ -62,8 +66,11 @@ class Cylinder : public openglframework::Mesh { /// Destructor ~Cylinder(); - /// Return a pointer to the rigid body of the cylinder - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the cylinder void updateTransform(); @@ -73,9 +80,14 @@ class Cylinder : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the cylinder -inline rp3d::RigidBody* Cylinder::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Cylinder::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Cylinder::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp index a55da732..a68c20b8 100644 --- a/examples/common/Dumbbell.cpp +++ b/examples/common/Dumbbell.cpp @@ -26,7 +26,6 @@ // Libraries #include "Dumbbell.h" - // Constructor Dumbbell::Dumbbell(const openglframework::Vector3 &position, reactphysics3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath) @@ -75,12 +74,74 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, rp3d::Transform transformCylinderShape(rp3d::Vector3(0, 0, 0), rp3d::Quaternion::identity()); // Create a rigid body corresponding to the dumbbell in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transformBody); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transformBody); // Add the three collision shapes to the body and specify the mass and transform of the shapes - mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape1); - mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape2); - mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); + body->addCollisionShape(sphereCollisionShape, transformSphereShape1, massSphere); + body->addCollisionShape(sphereCollisionShape, transformSphereShape2, massSphere); + body->addCollisionShape(cylinderCollisionShape, transformCylinderShape, massCylinder); + + mBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Constructor +Dumbbell::Dumbbell(const openglframework::Vector3 &position, + reactphysics3d::CollisionWorld* world, const std::string& meshFolderPath) + : openglframework::Mesh() { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "dumbbell.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Identity scaling matrix + mScalingMatrix.setToIdentity(); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create a sphere collision shape for the two ends of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusSphere = rp3d::decimal(1.5); + const rp3d::decimal massSphere = rp3d::decimal(2.0); + const rp3d::SphereShape sphereCollisionShape(radiusSphere); + + // Create a cylinder collision shape for the middle of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusCylinder = rp3d::decimal(0.5); + const rp3d::decimal heightCylinder = rp3d::decimal(8.0); + const rp3d::decimal massCylinder = rp3d::decimal(1.0); + const rp3d::CylinderShape cylinderCollisionShape(radiusCylinder, heightCylinder); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::decimal angleAroundX = 0;//rp3d::PI / 2; + rp3d::Quaternion initOrientation(angleAroundX, 0, 0); + rp3d::Transform transformBody(initPosition, initOrientation); + + // 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()); + + // Initial transform of the second sphere collision shape of the dumbell (in local-space) + rp3d::Transform transformSphereShape2(rp3d::Vector3(0, -4.0, 0), rp3d::Quaternion::identity()); + + // Initial transform of the cylinder collision shape of the dumbell (in local-space) + rp3d::Transform transformCylinderShape(rp3d::Vector3(0, 0, 0), rp3d::Quaternion::identity()); + + // Create a rigid body corresponding to the dumbbell in the dynamics world + mBody = world->createCollisionBody(transformBody); + + // Add the three collision shapes to the body and specify the mass and transform of the shapes + mBody->addCollisionShape(sphereCollisionShape, transformSphereShape1); + mBody->addCollisionShape(sphereCollisionShape, transformSphereShape2); + mBody->addCollisionShape(cylinderCollisionShape, transformCylinderShape); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor @@ -139,7 +200,7 @@ void Dumbbell::render(openglframework::Shader& shader, void Dumbbell::updateTransform() { // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + rp3d::Transform transform = mBody->getInterpolatedTransform(); // Compute the transform used for rendering the sphere rp3d::decimal matrix[16]; diff --git a/examples/common/Dumbbell.h b/examples/common/Dumbbell.h index abcb6c60..0ceafa15 100644 --- a/examples/common/Dumbbell.h +++ b/examples/common/Dumbbell.h @@ -41,7 +41,7 @@ class Dumbbell : public openglframework::Mesh { float mRadius; /// Rigid body used to simulate the dynamics of the sphere - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mBody; /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; @@ -56,12 +56,20 @@ class Dumbbell : public openglframework::Mesh { Dumbbell(const openglframework::Vector3& position, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); + /// Constructor + Dumbbell(const openglframework::Vector3& position, rp3d::CollisionWorld* world, + const std::string& meshFolderPath); + + /// Destructor ~Dumbbell(); - /// Return a pointer to the rigid body of the sphere + /// Return a pointer to the rigid body rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the body + rp3d::CollisionBody* getCollisionBody(); + /// Update the transform matrix of the sphere void updateTransform(); @@ -72,7 +80,12 @@ class Dumbbell : public openglframework::Mesh { // Return a pointer to the rigid body of the sphere inline rp3d::RigidBody* Dumbbell::getRigidBody() { - return mRigidBody; + return dynamic_cast(mBody); +} + +// Return a pointer to the body +inline rp3d::CollisionBody* Dumbbell::getCollisionBody() { + return mBody; } #endif diff --git a/examples/common/Line.cpp b/examples/common/Line.cpp new file mode 100644 index 00000000..751a32a7 --- /dev/null +++ b/examples/common/Line.cpp @@ -0,0 +1,59 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 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 "Line.h" + +// Constructor +Line::Line(const openglframework::Vector3& worldPoint1, + const openglframework::Vector3& worldPoint2) + : mWorldPoint1(worldPoint1), mWorldPoint2(worldPoint2) { + +} + +// Destructor +Line::~Line() { + + +} + +// Render the sphere at the correct position and with the correct orientation +void Line::render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix) { + + // Bind the shader + shader.bind(); + + // Set the model to camera matrix + shader.setMatrix4x4Uniform("localToCameraMatrix", worldToCameraMatrix); + + glBegin(GL_LINES); + glVertex3f(mWorldPoint1.x, mWorldPoint1.y, mWorldPoint1.z); + glVertex3f(mWorldPoint2.x, mWorldPoint2.y, mWorldPoint2.z); + glEnd(); + + // Unbind the shader + shader.unbind(); +} diff --git a/examples/common/Line.h b/examples/common/Line.h new file mode 100644 index 00000000..b226dcf4 --- /dev/null +++ b/examples/common/Line.h @@ -0,0 +1,54 @@ +#ifndef LINE_H +#define LINE_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" + +// Class Line +class Line : public openglframework::Object3D { + + private : + + // -------------------- Attributes -------------------- // + + openglframework::Vector3 mWorldPoint1, mWorldPoint2; + + // -------------------- Methods -------------------- // + + public : + + // -------------------- Methods -------------------- // + + /// Constructor + Line(const openglframework::Vector3& worldPoint1, + const openglframework::Vector3& worldPoint2); + + /// Destructor + ~Line(); + + /// Return the first point of the line + openglframework::Vector3 getPoint1() const; + + /// 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); +}; + +// Return the first point of the line +inline openglframework::Vector3 Line::getPoint1() const { + return mWorldPoint1; +} + +// Return the second point of the line +inline openglframework::Vector3 Line::getPoint2() const { + return mWorldPoint2; +} + +#endif diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index 1274b9d2..6308ca39 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -26,10 +26,9 @@ // Libraries #include "Sphere.h" - // Constructor Sphere::Sphere(float radius, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + reactphysics3d::CollisionWorld* world, const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius) { @@ -59,10 +58,54 @@ Sphere::Sphere(float radius, const openglframework::Vector3 &position, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + mRigidBody = world->createCollisionBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Constructor +Sphere::Sphere(float radius, const openglframework::Vector3 &position, + float mass, reactphysics3d::DynamicsWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "sphere.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, mRadius, 0, 0, + 0, 0, mRadius, 0, + 0, 0, 0, 1); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (sphere shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::SphereShape collisionShape(mRadius); + + // 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 = world->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Sphere.h b/examples/common/Sphere.h index daabfd14..768dfdf1 100644 --- a/examples/common/Sphere.h +++ b/examples/common/Sphere.h @@ -41,7 +41,7 @@ class Sphere : public openglframework::Mesh { float mRadius; /// Rigid body used to simulate the dynamics of the sphere - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; @@ -52,6 +52,10 @@ class Sphere : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + Sphere(float radius, const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string& meshFolderPath); + /// Constructor Sphere(float radius, const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); @@ -59,8 +63,11 @@ class Sphere : public openglframework::Mesh { /// Destructor ~Sphere(); - /// Return a pointer to the rigid body of the sphere - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the sphere void updateTransform(); @@ -70,9 +77,14 @@ class Sphere : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the sphere -inline rp3d::RigidBody* Sphere::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Sphere::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Sphere::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/opengl-framework/src/maths/Color.h b/examples/common/opengl-framework/src/maths/Color.h index a4629f8d..3216a0a7 100644 --- a/examples/common/opengl-framework/src/maths/Color.h +++ b/examples/common/opengl-framework/src/maths/Color.h @@ -59,6 +59,15 @@ struct Color { // Return the white color static Color white() { return Color(1.0f, 1.0f, 1.0f, 1.0f);} + // Return the red color + static Color red() { return Color(1.0f, 0.0f, 0.0f, 1.0f);} + + // Return the green color + static Color green() { return Color(0.0f, 1.0f, 0.0f, 1.0f);} + + // Return the blue color + static Color blue() { return Color(0.0f, 0.0f, 1.0f, 1.0f);} + // = operator Color& operator=(const Color& color) { if (&color != this) { diff --git a/examples/raycast/CMakeLists.txt b/examples/raycast/CMakeLists.txt new file mode 100644 index 00000000..b0305277 --- /dev/null +++ b/examples/raycast/CMakeLists.txt @@ -0,0 +1,43 @@ +# Minimum cmake version required +cmake_minimum_required(VERSION 2.6) + +# Project configuration +PROJECT(Raycast) + +# Where to build the executables +SET(EXECUTABLE_OUTPUT_PATH "${OUR_EXECUTABLE_OUTPUT_PATH}/collisionshapes") +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH}) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${EXECUTABLE_OUTPUT_PATH}) + +# Copy the shaders used for the demo into the build directory +FILE(COPY "${OPENGLFRAMEWORK_DIR}/src/shaders/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/shaders/") + +# Copy the meshes used for the demo into the build directory +FILE(COPY "../common/meshes/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/meshes/") + +# Headers +INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/glfw/include/" "../common/") + +# Source files +SET(RAYCAST_SOURCES + Raycast.cpp + Scene.cpp + Scene.h + "../common/VisualContactPoint.cpp" + "../common/ConvexMesh.cpp" + "../common/Capsule.cpp" + "../common/Sphere.cpp" + "../common/Line.cpp" + "../common/Cylinder.cpp" + "../common/Cone.cpp" + "../common/Dumbbell.cpp" + "../common/Box.cpp" + "../common/Viewer.cpp" +) + +# Create the executable +ADD_EXECUTABLE(raycast ${RAYCAST_SOURCES}) + +# Link with libraries +TARGET_LINK_LIBRARIES(raycast reactphysics3d openglframework glfw ${GLFW_LIBRARIES}) diff --git a/examples/raycast/Raycast.cpp b/examples/raycast/Raycast.cpp new file mode 100644 index 00000000..181d34cd --- /dev/null +++ b/examples/raycast/Raycast.cpp @@ -0,0 +1,155 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 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 "Scene.h" +#include "../common/Viewer.h" + +// Declarations +void simulate(); +void render(); +void update(); +void mouseButton(GLFWwindow* window, int button, int action, int mods); +void mouseMotion(GLFWwindow* window, double x, double y); +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods); +void scroll(GLFWwindow* window, double xAxis, double yAxis); +void init(); + +// Namespaces +using namespace openglframework; + +// Global variables +Viewer* viewer; +Scene* scene; + +// Main function +int main(int argc, char** argv) { + + // Create and initialize the Viewer + viewer = new Viewer(); + Vector2 windowsSize = Vector2(800, 600); + Vector2 windowsPosition = Vector2(100, 100); + viewer->init(argc, argv, "ReactPhysics3D Examples - Raycast", + windowsSize, windowsPosition, true); + + // If the shaders and meshes folders are not specified as an argument + if (argc < 3) { + std::cerr << "Error : You need to specify the shaders folder as the first argument" + << " and the meshes folder as the second argument" << std::endl; + return 1; + } + + // Get the path of the shaders folder + std::string shaderFolderPath(argv[1]); + std::string meshFolderPath(argv[2]); + + // Register callback methods + viewer->registerUpdateFunction(update); + viewer->registerKeyboardCallback(keyboard); + viewer->registerMouseButtonCallback(mouseButton); + viewer->registerMouseCursorCallback(mouseMotion); + viewer->registerScrollingCallback(scroll); + + // Create the scene + scene = new Scene(viewer, shaderFolderPath, meshFolderPath); + + init(); + + viewer->startMainLoop(); + + delete viewer; + delete scene; + + return 0; +} + +// Update function that is called each frame +void update() { + + // Take a simulation step + simulate(); + + // Render + render(); +} + +// Simulate function +void simulate() { + + // Physics simulation + scene->simulate(); + + viewer->computeFPS(); +} + +// Initialization +void init() { + + // Define the background color (black) + glClearColor(0.0, 0.0, 0.0, 1.0); +} + +// Callback method to receive keyboard events +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } + if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) { + scene->changeBody(); + } + if (key == GLFW_KEY_N && action == GLFW_PRESS) { + scene->showHideNormals(); + } +} + +// Callback method to receive scrolling events +void scroll(GLFWwindow* window, double xAxis, double yAxis) { + viewer->scrollingEvent(static_cast(yAxis)); +} + +// Called when a mouse button event occurs +void mouseButton(GLFWwindow* window, int button, int action, int mods) { + viewer->mouseButtonEvent(button, action); +} + +// Called when a mouse motion event occurs +void mouseMotion(GLFWwindow* window, double x, double y) { + viewer->mouseMotionEvent(x, y); +} + +// Display the scene +void render() { + + // Render the scene + scene->render(); + + // Display the FPS + viewer->displayGUI(); + + // Check the OpenGL errors + Viewer::checkOpenGLErrors(); +} + + diff --git a/examples/raycast/Scene.cpp b/examples/raycast/Scene.cpp new file mode 100644 index 00000000..6966f635 --- /dev/null +++ b/examples/raycast/Scene.cpp @@ -0,0 +1,309 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 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 "Scene.h" + +// Namespaces +using namespace openglframework; + +// Constructor +Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::string& meshFolderPath) + : mViewer(viewer), mLight0(0), mCurrentBodyIndex(-1), mAreNormalsDisplayed(false), + mPhongShader(shaderFolderPath + "phong.vert", + shaderFolderPath +"phong.frag") { + + // Move the light 0 + mLight0.translateWorld(Vector3(50, 50, 50)); + + // Compute the radius and the center of the scene + float radiusScene = 30.0f; + openglframework::Vector3 center(0, 0, 0); + + // Set the center of the scene + mViewer->setScenePosition(center, radiusScene); + + // Create the dynamics world for the physics simulation + mCollisionWorld = new rp3d::CollisionWorld(); + + // Create the static data for the visual contact points + VisualContactPoint::createStaticData(meshFolderPath); + + // ---------- Dumbbell ---------- // + openglframework::Vector3 position1(0, 0, 0); + + // Create a convex mesh and a corresponding rigid in the dynamics world + mDumbbell = new Dumbbell(position1, mCollisionWorld, meshFolderPath); + + // ---------- Box ---------- // + openglframework::Vector3 position2(0, 0, 0); + + // Create a sphere and a corresponding rigid in the dynamics world + mBox = new Box(BOX_SIZE, position2, mCollisionWorld); + mBox->getCollisionBody()->setIsActive(false); + + // ---------- Sphere ---------- // + openglframework::Vector3 position3(0, 0, 0); + + // Create a sphere and a corresponding rigid in the dynamics world + mSphere = new Sphere(SPHERE_RADIUS, position3, mCollisionWorld, + meshFolderPath); + + // ---------- Cone ---------- // + openglframework::Vector3 position4(0, 0, 0); + + // Create a cone and a corresponding rigid in the dynamics world + mCone = new Cone(CONE_RADIUS, CONE_HEIGHT, position4, mCollisionWorld, + meshFolderPath); + mCone->getCollisionBody()->setIsActive(false); + + // ---------- Cylinder ---------- // + openglframework::Vector3 position5(0, 0, 0); + + // Create a cylinder and a corresponding rigid in the dynamics world + mCylinder = new Cylinder(CYLINDER_RADIUS, CYLINDER_HEIGHT, position5, + mCollisionWorld, meshFolderPath); + mCylinder->getCollisionBody()->setIsActive(false); + + // ---------- Capsule ---------- // + openglframework::Vector3 position6(0, 0, 0); + + // Create a cylinder and a corresponding rigid in the dynamics world + mCapsule = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, position6 , + mCollisionWorld, meshFolderPath); + + // ---------- Convex Mesh ---------- // + openglframework::Vector3 position7(0, 0, 0); + + // Create a convex mesh and a corresponding rigid in the dynamics world + mConvexMesh = new ConvexMesh(position7, mCollisionWorld, meshFolderPath); + + // Create the lines that will be used for raycasting + createLines(); + + changeBody(); +} + +// Create the raycast lines +void Scene::createLines() { + + int nbRaysOneDimension = sqrt(NB_RAYS); + + for (int i=0; i= NB_BODIES) mCurrentBodyIndex = 0; + + mSphere->getCollisionBody()->setIsActive(false); + mBox->getCollisionBody()->setIsActive(false); + mCone->getCollisionBody()->setIsActive(false); + mCylinder->getCollisionBody()->setIsActive(false); + mCapsule->getCollisionBody()->setIsActive(false); + mConvexMesh->getCollisionBody()->setIsActive(false); + mDumbbell->getCollisionBody()->setIsActive(false); + + switch(mCurrentBodyIndex) { + case 0: mSphere->getCollisionBody()->setIsActive(true); + break; + case 1: mBox->getCollisionBody()->setIsActive(true); + break; + case 2: mCone->getCollisionBody()->setIsActive(true); + break; + case 3: mCylinder->getCollisionBody()->setIsActive(true); + break; + case 4: mCapsule->getCollisionBody()->setIsActive(true); + break; + case 5: mConvexMesh->getCollisionBody()->setIsActive(true); + break; + case 6: mDumbbell->getCollisionBody()->setIsActive(true); + break; + + } +} + +// Destructor +Scene::~Scene() { + + // Destroy the shader + mPhongShader.destroy(); + + // Destroy the box rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mBox->getCollisionBody()); + delete mBox; + + // Destroy the sphere + mCollisionWorld->destroyCollisionBody(mSphere->getCollisionBody()); + delete mSphere; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mCone->getCollisionBody()); + delete mCone; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mCylinder->getCollisionBody()); + + // Destroy the sphere + delete mCylinder; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mCapsule->getCollisionBody()); + + // Destroy the sphere + delete mCapsule; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mConvexMesh->getCollisionBody()); + + // Destroy the convex mesh + delete mConvexMesh; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mDumbbell->getCollisionBody()); + + // Destroy the convex mesh + delete mDumbbell; + + mRaycastManager.resetPoints(); + + // Destroy the static data for the visual contact points + VisualContactPoint::destroyStaticData(); + + // Destroy the collision world + delete mCollisionWorld; + + // Destroy the lines + for (std::vector::iterator it = mLines.begin(); it != mLines.end(); + ++it) { + delete (*it); + } +} + +// Take a step for the simulation +void Scene::simulate() { + + mRaycastManager.resetPoints(); + + // For each line of the scene + for (std::vector::iterator it = mLines.begin(); it != mLines.end(); + ++it) { + + Line* line = *it; + + // Create a ray corresponding to the line + openglframework::Vector3 p1 = line->getPoint1(); + openglframework::Vector3 p2 = line->getPoint2(); + + rp3d::Vector3 point1(p1.x, p1.y, p1.z); + rp3d::Vector3 point2(p2.x, p2.y, p2.z); + rp3d::Ray ray(point1, point2); + + // Perform a raycast query on the physics world by passing a raycast + // callback class in argument. + mCollisionWorld->raycast(ray, &mRaycastManager); + } +} + +// Render the scene +void Scene::render() { + + glEnable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_CULL_FACE); + + // Get the world-space to camera-space matrix + const Camera& camera = mViewer->getCamera(); + const openglframework::Matrix4 worldToCameraMatrix = camera.getTransformMatrix().getInverse(); + + // Bind the shader + mPhongShader.bind(); + + openglframework::Vector4 grey(0.7, 0.7, 0.7, 1); + mPhongShader.setVector4Uniform("vertexColor", grey); + + // Set the variables of the shader + mPhongShader.setMatrix4x4Uniform("projectionMatrix", camera.getProjectionMatrix()); + mPhongShader.setVector3Uniform("light0PosCameraSpace", worldToCameraMatrix * mLight0.getOrigin()); + mPhongShader.setVector3Uniform("lightAmbientColor", Vector3(0.3f, 0.3f, 0.3f)); + const Color& diffColLight0 = mLight0.getDiffuseColor(); + const Color& specColLight0 = mLight0.getSpecularColor(); + mPhongShader.setVector3Uniform("light0DiffuseColor", Vector3(diffColLight0.r, diffColLight0.g, diffColLight0.b)); + mPhongShader.setVector3Uniform("light0SpecularColor", Vector3(specColLight0.r, specColLight0.g, specColLight0.b)); + mPhongShader.setFloatUniform("shininess", 200.0f); + + if (mBox->getCollisionBody()->isActive()) mBox->render(mPhongShader, worldToCameraMatrix); + if (mSphere->getCollisionBody()->isActive()) mSphere->render(mPhongShader, worldToCameraMatrix); + if (mCone->getCollisionBody()->isActive()) mCone->render(mPhongShader, worldToCameraMatrix); + if (mCylinder->getCollisionBody()->isActive()) mCylinder->render(mPhongShader, worldToCameraMatrix); + if (mCapsule->getCollisionBody()->isActive()) mCapsule->render(mPhongShader, worldToCameraMatrix); + if (mConvexMesh->getCollisionBody()->isActive()) mConvexMesh->render(mPhongShader, worldToCameraMatrix); + if (mDumbbell->getCollisionBody()->isActive()) mDumbbell->render(mPhongShader, worldToCameraMatrix); + + mPhongShader.unbind(); + mPhongShader.bind(); + + mPhongShader.setVector3Uniform("light0SpecularColor", Vector3(0, 0, 0)); + openglframework::Vector4 redColor(1, 0, 0, 1); + mPhongShader.setVector4Uniform("vertexColor", redColor); + + // Render all the raycast hit points + mRaycastManager.render(mPhongShader, worldToCameraMatrix, mAreNormalsDisplayed); + + mPhongShader.unbind(); + mPhongShader.bind(); + + openglframework::Vector4 blueColor(0, 0.62, 0.92, 1); + mPhongShader.setVector4Uniform("vertexColor", blueColor); + + // Render the lines + for (std::vector::iterator it = mLines.begin(); it != mLines.end(); + ++it) { + (*it)->render(mPhongShader, worldToCameraMatrix); + } + + // Unbind the shader + mPhongShader.unbind(); +} diff --git a/examples/raycast/Scene.h b/examples/raycast/Scene.h new file mode 100644 index 00000000..fb13bc84 --- /dev/null +++ b/examples/raycast/Scene.h @@ -0,0 +1,198 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 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 SCENE_H +#define SCENE_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" +#include "Sphere.h" +#include "Box.h" +#include "Cone.h" +#include "Cylinder.h" +#include "Capsule.h" +#include "Line.h" +#include "ConvexMesh.h" +#include "Dumbbell.h" +#include "VisualContactPoint.h" +#include "../common/Viewer.h" + +// Constants +const openglframework::Vector3 BOX_SIZE(4, 2, 1); +const float SPHERE_RADIUS = 3.0f; +const float CONE_RADIUS = 3.0f; +const float CONE_HEIGHT = 5.0f; +const float CYLINDER_RADIUS = 3.0f; +const float CYLINDER_HEIGHT = 5.0f; +const float CAPSULE_RADIUS = 3.0f; +const float CAPSULE_HEIGHT = 5.0f; +const float DUMBBELL_HEIGHT = 5.0f; +const int NB_RAYS = 100; +const float RAY_LENGTH = 30.0f; +const int NB_BODIES = 7; + +// Raycast manager +class RaycastManager : public rp3d::RaycastCallback { + + private: + + /// All the visual contact points + std::vector mHitPoints; + + /// All the normals at hit points + std::vector mNormals; + + public: + + virtual rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) { + rp3d::Vector3 hitPos = raycastInfo.worldPoint; + openglframework::Vector3 position(hitPos.x, hitPos.y, hitPos.z); + VisualContactPoint* point = new VisualContactPoint(position); + mHitPoints.push_back(point); + + // Create a line to display the normal at hit point + rp3d::Vector3 n = raycastInfo.worldNormal; + openglframework::Vector3 normal(n.x, n.y, n.z); + Line* normalLine = new Line(position, position + normal); + mNormals.push_back(normalLine); + + return raycastInfo.hitFraction; + } + + void render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix, + bool showNormals) { + + // Render all the raycast hit points + for (std::vector::iterator it = mHitPoints.begin(); + it != mHitPoints.end(); ++it) { + (*it)->render(shader, worldToCameraMatrix); + } + + if (showNormals) { + + // Render all the normals at hit points + for (std::vector::iterator it = mNormals.begin(); + it != mNormals.end(); ++it) { + (*it)->render(shader, worldToCameraMatrix); + } + } + } + + void resetPoints() { + + // Destroy all the visual contact points + for (std::vector::iterator it = mHitPoints.begin(); + it != mHitPoints.end(); ++it) { + delete (*it); + } + mHitPoints.clear(); + + // Destroy all the normals + for (std::vector::iterator it = mNormals.begin(); + it != mNormals.end(); ++it) { + delete (*it); + } + mNormals.clear(); + } +}; + +// Class Scene +class Scene { + + private : + + // -------------------- Attributes -------------------- // + + /// Pointer to the viewer + Viewer* mViewer; + + /// Raycast manager + RaycastManager mRaycastManager; + + /// Light 0 + openglframework::Light mLight0; + + /// Phong shader + openglframework::Shader mPhongShader; + + /// All the raycast lines + std::vector mLines; + + /// Current body index + int mCurrentBodyIndex; + + /// True if the hit points normals are displayed + bool mAreNormalsDisplayed; + + /// Raycast manager + + /// All objects on the scene + Box* mBox; + Sphere* mSphere; + Cone* mCone; + Cylinder* mCylinder; + Capsule* mCapsule; + ConvexMesh* mConvexMesh; + Dumbbell* mDumbbell; + + /// Collision world used for the physics simulation + rp3d::CollisionWorld* mCollisionWorld; + + /// Create the raycast lines + void createLines(); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + Scene(Viewer* viewer, const std::string& shaderFolderPath, + const std::string& meshFolderPath); + + /// Destructor + ~Scene(); + + /// Take a step for the simulation + void simulate(); + + /// Render the scene + void render(); + + /// Change the body to raycast + void changeBody(); + + /// Display or not the surface normals at hit points + void showHideNormals(); +}; + +// Display or not the surface normals at hit points +inline void Scene::showHideNormals() { + mAreNormalsDisplayed = !mAreNormalsDisplayed; +} + + +#endif