Improve rendering of testbed application (flat shading, 3 light sources, ...)

This commit is contained in:
Daniel Chappuis 2019-10-21 07:22:18 +02:00
parent bcb4febb16
commit 43b818573a
24 changed files with 2588 additions and 2237 deletions

View File

@ -84,12 +84,6 @@ Box::Box(const openglframework::Vector3& size, float mass, reactphysics3d::Dynam
const std::string& meshFolderPath)
: PhysicsObject(meshFolderPath + "cube.obj") {
// Load the mesh from a file
openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cube.obj", *this);
// Calculate the normals of the mesh
calculateNormals();
// Initialize the size of the box
mSize[0] = size.x * 0.5f;
mSize[1] = size.y * 0.5f;
@ -200,8 +194,7 @@ void Box::render(openglframework::Shader& shader, const openglframework::Matrix4
}
// Create the Vertex Buffer Objects used to render to box with OpenGL.
/// We create two VBOs (one for vertices and one for indices) to render all the boxes
/// in the simulation.
/// We create two VBOs (one for vertices and one for indices) to render the box
void Box::createVBOAndVAO() {
// Create the VBO for the vertices data
@ -227,7 +220,7 @@ void Box::createVBOAndVAO() {
mVBOTextureCoords.unbind();
}
// Create th VBO for the indices data
// Create the VBO for the indices data
mVBOIndices.create();
mVBOIndices.bind();
size_t sizeIndices = mIndices[0].size() * sizeof(unsigned int);

View File

@ -25,6 +25,7 @@
// Libraries
#include "ConvexMesh.h"
#include <unordered_set>
// Constructor
ConvexMesh::ConvexMesh(rp3d::CollisionWorld* world, const std::string& meshPath)
@ -39,6 +40,19 @@ ConvexMesh::ConvexMesh(rp3d::CollisionWorld* world, const std::string& meshPath)
mPolygonFaces = new rp3d::PolygonVertexArray::PolygonFace[getNbFaces(0)];
rp3d::PolygonVertexArray::PolygonFace* face = mPolygonFaces;
for (int f=0; f < getNbFaces(0); f++) {
for (int v = 0; v < 3; v++) {
const openglframework::Vector3 vertex = mVertices[mIndices[0][f*3 + v]];
int vIndex = findVertexIndex(mConvexMeshVertices, vertex);
if (vIndex == -1) {
vIndex = mConvexMeshVertices.size();
mConvexMeshVertices.push_back(vertex);
}
mConvexMeshIndices.push_back(vIndex);
}
face->indexBase = f * 3;
face->nbVertices = 3;
face++;
@ -46,8 +60,8 @@ ConvexMesh::ConvexMesh(rp3d::CollisionWorld* world, const std::string& meshPath)
// Create the polygon vertex array
mPolygonVertexArray =
new rp3d::PolygonVertexArray(getNbVertices(), &(mVertices[0]), sizeof(openglframework::Vector3),
&(mIndices[0][0]), sizeof(int),
new rp3d::PolygonVertexArray(mConvexMeshVertices.size(), &(mConvexMeshVertices[0]), sizeof(openglframework::Vector3),
&(mConvexMeshIndices[0]), sizeof(int),
getNbFaces(0), mPolygonFaces,
rp3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE,
rp3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);
@ -86,6 +100,19 @@ ConvexMesh::ConvexMesh(float mass, rp3d::DynamicsWorld* dynamicsWorld, const std
mPolygonFaces = new rp3d::PolygonVertexArray::PolygonFace[getNbFaces(0)];
rp3d::PolygonVertexArray::PolygonFace* face = mPolygonFaces;
for (int f=0; f < getNbFaces(0); f++) {
for (int v = 0; v < 3; v++) {
const openglframework::Vector3 vertex = mVertices[mIndices[0][f*3 + v]];
int vIndex = findVertexIndex(mConvexMeshVertices, vertex);
if (vIndex == -1) {
vIndex = mConvexMeshVertices.size();
mConvexMeshVertices.push_back(vertex);
}
mConvexMeshIndices.push_back(vIndex);
}
face->indexBase = f * 3;
face->nbVertices = 3;
face++;
@ -93,8 +120,8 @@ ConvexMesh::ConvexMesh(float mass, rp3d::DynamicsWorld* dynamicsWorld, const std
// Create the polygon vertex array
mPolygonVertexArray =
new rp3d::PolygonVertexArray(getNbVertices(), &(mVertices[0]), sizeof(openglframework::Vector3),
&(mIndices[0][0]), sizeof(int),
new rp3d::PolygonVertexArray(mConvexMeshVertices.size(), &(mConvexMeshVertices[0]), sizeof(openglframework::Vector3),
&(mConvexMeshIndices[0]), sizeof(int),
getNbFaces(0), mPolygonFaces,
rp3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE,
rp3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);
@ -254,3 +281,16 @@ void ConvexMesh::createVBOAndVAO() {
// Unbind the VAO
mVAO.unbind();
}
// Return the index of a given vertex in the mesh
int ConvexMesh::findVertexIndex(const std::vector<openglframework::Vector3>& vertices, const openglframework::Vector3& vertex) {
for (int i = 0; i < vertices.size(); i++) {
if (vertices[i] == vertex) {
return i;
}
}
return -1;
}

View File

@ -69,11 +69,21 @@ class ConvexMesh : public PhysicsObject {
/// Vertex Array Object for the vertex data
openglframework::VertexArrayObject mVAO;
/// Array with the vertices of the convex mesh
/// (only the vertices used for the physics shape, not duplicate vertices used for rendering)
std::vector<openglframework::Vector3> mConvexMeshVertices;
/// Array with the vertex indices of the convex mesh (used for the physics shape)
std::vector<int> mConvexMeshIndices;
// -------------------- Methods -------------------- //
// Create the Vertex Buffer Objects used to render with OpenGL.
/// Create the Vertex Buffer Objects used to render with OpenGL.
void createVBOAndVAO();
/// Return the index of a given vertex in the mesh
int findVertexIndex(const std::vector<openglframework::Vector3>& vertices, const openglframework::Vector3& vertex);
public :
// -------------------- Methods -------------------- //

View File

@ -40,8 +40,12 @@ PhysicsObject::PhysicsObject(const std::string& meshPath) : PhysicsObject() {
// Load the mesh from a file
openglframework::MeshReaderWriter::loadMeshFromFile(meshPath, *this);
// Calculate the normals of the mesh
calculateNormals();
// If the mesh file do not have normals
if (mNormals.empty()) {
// Calculate the normals of the mesh
calculateNormals();
}
}
// Compute the new transform matrix

View File

@ -1,125 +1,205 @@
# Blender v2.66 (sub 0) OBJ File: ''
# Blender v2.80 (sub 75) OBJ File: ''
# www.blender.org
v 0.000000 -1.000000 0.000000
v 0.723607 -0.447220 0.525725
v -0.276388 -0.447220 0.850649
v -0.894426 -0.447216 0.000000
v -0.276388 -0.447220 -0.850649
v 0.723607 -0.447220 -0.525725
v 0.276388 0.447220 0.850649
v -0.723607 0.447220 0.525725
v -0.723607 0.447220 -0.525725
v 0.276388 0.447220 -0.850649
v 0.894426 0.447216 0.000000
v 0.000000 1.000000 0.000000
v 0.000000 -1.000000 -0.000000
v 0.425323 -0.850654 0.309011
v 0.262869 -0.525738 0.809012
v -0.162456 -0.850654 0.499995
v 0.425323 -0.850654 -0.309011
v 0.850648 -0.525736 0.000000
v -0.688189 -0.525736 0.499997
v -0.525730 -0.850652 0.000000
v -0.688189 -0.525736 -0.499997
v 0.723607 -0.447220 0.525725
v 0.850648 -0.525736 -0.000000
v -0.525730 -0.850652 -0.000000
v -0.162456 -0.850654 -0.499995
v 0.262869 -0.525738 -0.809012
v 0.951058 0.000000 -0.309013
v 0.951058 0.000000 0.309013
v 0.587786 0.000000 0.809017
v 0.000000 0.000000 1.000000
v -0.587786 0.000000 0.809017
v -0.951058 0.000000 0.309013
v -0.951058 0.000000 -0.309013
v 0.425323 -0.850654 -0.309011
v 0.951058 -0.000000 0.309013
v -0.276388 -0.447220 0.850649
v 0.262869 -0.525738 0.809012
v 0.000000 -0.000000 1.000000
v -0.894426 -0.447216 -0.000000
v -0.688189 -0.525736 0.499997
v -0.951058 -0.000000 0.309013
v -0.276388 -0.447220 -0.850649
v -0.688189 -0.525736 -0.499997
v -0.587786 0.000000 -0.809017
v 0.000000 0.000000 -1.000000
v 0.723607 -0.447220 -0.525725
v 0.262869 -0.525738 -0.809012
v 0.587786 0.000000 -0.809017
v 0.587786 -0.000000 0.809017
v -0.587786 -0.000000 0.809017
v -0.951058 0.000000 -0.309013
v 0.000000 0.000000 -1.000000
v 0.951058 0.000000 -0.309013
v 0.276388 0.447220 0.850649
v 0.688189 0.525736 0.499997
v 0.162456 0.850654 0.499995
v -0.723607 0.447220 0.525725
v -0.262869 0.525738 0.809012
v -0.425323 0.850654 0.309011
v -0.723607 0.447220 -0.525725
v -0.850648 0.525736 0.000000
v -0.425323 0.850654 -0.309011
v 0.276388 0.447220 -0.850649
v -0.262869 0.525738 -0.809012
v 0.162456 0.850654 -0.499995
v 0.894426 0.447216 0.000000
v 0.688189 0.525736 -0.499997
v 0.525730 0.850652 0.000000
v 0.162456 0.850654 0.499995
v -0.425323 0.850654 0.309011
v -0.425323 0.850654 -0.309011
v 0.162456 0.850654 -0.499995
v 0.000000 1.000000 0.000000
vn 0.1024 -0.9435 0.3151
vn 0.7002 -0.6617 0.2680
vn -0.2680 -0.9435 0.1947
vn -0.2680 -0.9435 -0.1947
vn 0.1024 -0.9435 -0.3151
vn 0.9050 -0.3304 0.2680
vn 0.0247 -0.3304 0.9435
vn -0.8897 -0.3304 0.3151
vn -0.5746 -0.3304 -0.7488
vn 0.5346 -0.3304 -0.7779
vn 0.8026 -0.1256 0.5831
vn -0.3066 -0.1256 0.9435
vn -0.9921 -0.1256 -0.0000
vn -0.3066 -0.1256 -0.9435
vn 0.8026 -0.1256 -0.5831
vn 0.4089 0.6617 0.6284
vn -0.4713 0.6617 0.5831
vn -0.7002 0.6617 -0.2680
vn 0.0385 0.6617 -0.7488
vn 0.7240 0.6617 -0.1947
vn -0.0385 -0.6617 0.7488
vn 0.1876 -0.7947 0.5773
vn 0.4713 -0.6617 0.5831
vn 0.7002 -0.6617 -0.2680
vn 0.6071 -0.7947 0.0000
vn 0.3313 -0.9435 -0.0000
vn -0.7240 -0.6617 0.1947
vn -0.4911 -0.7947 0.3568
vn -0.4089 -0.6617 0.6284
vn -0.4089 -0.6617 -0.6284
vn -0.4911 -0.7947 -0.3568
vn -0.7240 -0.6617 -0.1947
vn 0.4713 -0.6617 -0.5831
vn 0.1876 -0.7947 -0.5773
vn -0.0385 -0.6617 -0.7488
vn 0.9921 0.1256 0.0000
vn 0.9822 -0.1876 -0.0000
vn 0.9050 -0.3304 -0.2680
vn 0.3066 0.1256 0.9435
vn 0.3035 -0.1876 0.9342
vn 0.5346 -0.3304 0.7779
vn -0.8026 0.1256 0.5831
vn -0.7947 -0.1876 0.5773
vn -0.5746 -0.3304 0.7488
vn -0.8026 0.1256 -0.5831
vn -0.7947 -0.1876 -0.5773
vn -0.8897 -0.3304 -0.3151
vn 0.3066 0.1256 -0.9435
vn 0.3035 -0.1876 -0.9342
vn 0.0247 -0.3304 -0.9435
vn 0.5746 0.3304 0.7488
vn 0.7947 0.1876 0.5773
vn 0.8897 0.3304 0.3151
vn -0.5346 0.3304 0.7779
vn -0.3035 0.1876 0.9342
vn -0.0247 0.3304 0.9435
vn -0.9050 0.3304 -0.2680
vn -0.9822 0.1876 0.0000
vn -0.9050 0.3304 0.2680
vn -0.0247 0.3304 -0.9435
vn -0.3035 0.1876 -0.9342
vn -0.5346 0.3304 -0.7779
vn 0.8897 0.3304 -0.3151
vn 0.7947 0.1876 -0.5773
vn 0.5746 0.3304 -0.7488
vn 0.2680 0.9435 0.1947
vn 0.4911 0.7947 0.3568
vn 0.7240 0.6617 0.1947
vn -0.1024 0.9435 0.3151
vn -0.1876 0.7947 0.5773
vn 0.0385 0.6617 0.7488
vn -0.3313 0.9435 0.0000
vn -0.6071 0.7947 0.0000
vn -0.7002 0.6617 0.2680
vn -0.1024 0.9435 -0.3151
vn -0.1876 0.7947 -0.5773
vn -0.4713 0.6617 -0.5831
vn 0.2680 0.9435 -0.1947
vn 0.4911 0.7947 -0.3568
vn 0.4089 0.6617 -0.6284
s off
f 1 13 15
f 2 13 17
f 1 15 19
f 1 19 21
f 1 21 16
f 2 17 24
f 3 14 26
f 4 18 28
f 5 20 30
f 6 22 32
f 2 24 25
f 3 26 27
f 4 28 29
f 5 30 31
f 6 32 23
f 7 33 39
f 8 34 40
f 9 35 41
f 10 36 42
f 11 37 38
f 15 14 3
f 15 13 14
f 13 2 14
f 17 16 6
f 17 13 16
f 13 1 16
f 19 18 4
f 19 15 18
f 15 3 18
f 21 20 5
f 21 19 20
f 19 4 20
f 16 22 6
f 16 21 22
f 21 5 22
f 24 23 11
f 24 17 23
f 17 6 23
f 26 25 7
f 26 14 25
f 14 2 25
f 28 27 8
f 28 18 27
f 18 3 27
f 30 29 9
f 30 20 29
f 20 4 29
f 32 31 10
f 32 22 31
f 22 5 31
f 25 33 7
f 25 24 33
f 24 11 33
f 27 34 8
f 27 26 34
f 26 7 34
f 29 35 9
f 29 28 35
f 28 8 35
f 31 36 10
f 31 30 36
f 30 9 36
f 23 37 11
f 23 32 37
f 32 10 37
f 39 38 12
f 39 33 38
f 33 11 38
f 40 39 12
f 40 34 39
f 34 7 39
f 41 40 12
f 41 35 40
f 35 8 40
f 42 41 12
f 42 36 41
f 36 9 41
f 38 42 12
f 38 37 42
f 37 10 42
f 1//1 2//1 3//1
f 4//2 2//2 5//2
f 1//3 3//3 6//3
f 1//4 6//4 7//4
f 1//5 7//5 8//5
f 4//6 5//6 9//6
f 10//7 11//7 12//7
f 13//8 14//8 15//8
f 16//9 17//9 18//9
f 19//10 20//10 21//10
f 4//11 9//11 22//11
f 10//12 12//12 23//12
f 13//13 15//13 24//13
f 16//14 18//14 25//14
f 19//15 21//15 26//15
f 27//16 28//16 29//16
f 30//17 31//17 32//17
f 33//18 34//18 35//18
f 36//19 37//19 38//19
f 39//20 40//20 41//20
f 3//21 11//21 10//21
f 3//22 2//22 11//22
f 2//23 4//23 11//23
f 5//24 8//24 19//24
f 5//25 2//25 8//25
f 2//26 1//26 8//26
f 6//27 14//27 13//27
f 6//28 3//28 14//28
f 3//29 10//29 14//29
f 7//30 17//30 16//30
f 7//31 6//31 17//31
f 6//32 13//32 17//32
f 8//33 20//33 19//33
f 8//34 7//34 20//34
f 7//35 16//35 20//35
f 9//36 26//36 39//36
f 9//37 5//37 26//37
f 5//38 19//38 26//38
f 12//39 22//39 27//39
f 12//40 11//40 22//40
f 11//41 4//41 22//41
f 15//42 23//42 30//42
f 15//43 14//43 23//43
f 14//44 10//44 23//44
f 18//45 24//45 33//45
f 18//46 17//46 24//46
f 17//47 13//47 24//47
f 21//48 25//48 36//48
f 21//49 20//49 25//49
f 20//50 16//50 25//50
f 22//51 28//51 27//51
f 22//52 9//52 28//52
f 9//53 39//53 28//53
f 23//54 31//54 30//54
f 23//55 12//55 31//55
f 12//56 27//56 31//56
f 24//57 34//57 33//57
f 24//58 15//58 34//58
f 15//59 30//59 34//59
f 25//60 37//60 36//60
f 25//61 18//61 37//61
f 18//62 33//62 37//62
f 26//63 40//63 39//63
f 26//64 21//64 40//64
f 21//65 36//65 40//65
f 29//66 41//66 42//66
f 29//67 28//67 41//67
f 28//68 39//68 41//68
f 32//69 29//69 42//69
f 32//70 31//70 29//70
f 31//71 27//71 29//71
f 35//72 32//72 42//72
f 35//73 34//73 32//73
f 34//74 30//74 32//74
f 38//75 35//75 42//75
f 38//76 37//76 35//76
f 37//77 33//77 35//77
f 41//78 38//78 42//78
f 41//79 40//79 38//79
f 40//80 36//80 38//80

View File

@ -1,17 +1,43 @@
# Blender v2.72 (sub 0) OBJ File: ''
# Blender v2.80 (sub 75) OBJ File: ''
# www.blender.org
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.375000 0.750000
vt 0.125000 0.750000
vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
s off
f 5 6 2 1
f 6 7 3 2
f 7 8 4 3
f 8 5 1 4
f 1 2 3 4
f 8 7 6 5
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/6/2 7/7/2 8/8/2
f 8/8/3 7/7/3 5/9/3 6/10/3
f 6/10/4 2/11/4 4/12/4 8/13/4
f 2/14/5 1/15/5 3/16/5 4/17/5
f 6/18/6 5/19/6 1/20/6 2/11/6

View File

@ -31,6 +31,8 @@
#include <cctype>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <tuple>
using namespace openglframework;
using namespace std;
@ -112,6 +114,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
std::vector<uint> normalsIndices;
std::vector<uint> uvsIndices;
// ---------- Collect the data from the file ---------- //
// For each line of the file
@ -142,7 +145,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
line = buffer;
found1 = (int)line.find("/");
bool isFaceQuad = false;
int foundNext = (int)line.substr(found1+1).find("/");
found2 = (int)line.substr(found1+1).find("/");
// If the face definition is of the form "f v1 v2 v3 v4"
if(found1 == string::npos) {
@ -150,11 +153,21 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
if (nbVertices == 4) isFaceQuad = true;
}
// If the face definition is of the form "f v1// v2// v3// v4//"
else if (foundNext == 0) {
else if (found2 == 0 && (int)line.substr(found1+found2+1).find(" ") == 0) {
int nbVertices = sscanf(buffer.c_str(), "%*s %d// %d// %d// %d//", &id1, &id2, &id3, &id4);
if (nbVertices == 4) isFaceQuad = true;
}
else { // If the face definition contains vertices and texture coordinates
else { // If the face definition contains vertices and (texture coordinates or normals)
tId1 = -1;
tId2 = -1;
tId3 = -1;
tId4 = -1;
nId1 = -1;
nId2 = -1;
nId3 = -1;
nId4 = -1;
//get the part of the string until the second index
tmp = line.substr(found1+1);
@ -166,6 +179,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
if(found2 == string::npos) {
int n = sscanf(buffer.c_str(), "%*s %d/%d %d/%d %d/%d %d/%d", &id1, &tId1, &id2, &tId2, &id3, &tId3, &id4, &tId4);
if (n == 8) isFaceQuad = true;
uvsIndices.push_back(tId1-1);
uvsIndices.push_back(tId2-1);
uvsIndices.push_back(tId3-1);
@ -174,8 +188,11 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
else {
tmp = line.substr(found1+1);
found2 = (int)tmp.find("/");
if (found2 > 1000) {
int test = 2;
}
// If the face definition is of the form "f vert1/normal1 vert2/normal2 ..."
// If the face definition is of the form "f vert1//normal1 vert2//normal2 ..."
if(found2 == 0) {
int n = sscanf(buffer.c_str(), "%*s %d//%d %d//%d %d//%d %d//%d", &id1, &nId1, &id2, &nId2, &id3, &nId3, &id4, &nId4);
if (n == 8) isFaceQuad = true;
@ -213,39 +230,84 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
// Destroy the current mesh
meshToCreate.destroy();
// This is used to create duplicate vertices if a vertex with index "i" from a face does not
// have same texture coordinates or normals as a previous vertex with index "i".
unordered_map<tuple<int, int, int>, uint> mapVertNormTexToVertexIndex;
// Mesh data
vector<std::vector<uint> > meshIndices;
vector<Vector3> meshVertices;
vector<Vector3> meshNormals;
if (!normals.empty()) meshNormals = vector<Vector3>(vertices.size(), Vector3(0, 0, 0));
//if (!normals.empty()) meshNormals = vector<Vector3>(vertices.size(), Vector3(0, 0, 0));
vector<Vector2> meshUVs;
if (!uvs.empty()) meshUVs = vector<Vector2>(vertices.size(), Vector2(0, 0));
//if (!uvs.empty()) meshUVs = vector<Vector2>(vertices.size(), Vector2(0, 0));
// We cannot load mesh with several parts for the moment
uint meshPart = 0;
const bool hasNormals = !normalsIndices.empty() && !normals.empty();
const bool hasUvs = !uvsIndices.empty() && !uvs.empty();
// Fill in the vertex indices
// We also triangulate each quad face
meshIndices.push_back(std::vector<uint>());
for(size_t i = 0, j = 0; i < verticesIndices.size(); j++) {
// Get the current vertex IDs
uint i1 = verticesIndices[i];
uint i2 = verticesIndices[i+1];
uint i3 = verticesIndices[i+2];
// 3 if the current vertices form a triangle and 4 if they form a quad
const int nbVertices = isQuad[j] ? 4 : 3;
int newVerticesIndices[4] = { -1, -1, -1, -1 };
// For each vertex, we check if there is already a vertex with same UV and normals.
for (int v = 0; v < nbVertices; v++) {
int normalIndex = hasNormals ? normalsIndices[i + v] : -1;
int uvIndex = hasUvs ? uvsIndices[i + v] : -1;
// If the vertex with same UV and normal doesn't exist yet in the map
tuple<int, int, int> key = std::make_tuple(verticesIndices[i+v], normalIndex, uvIndex);
auto itFound = mapVertNormTexToVertexIndex.find(key);
if (itFound == mapVertNormTexToVertexIndex.end()) {
// Create a new vertex
newVerticesIndices[v]= meshVertices.size();
meshVertices.push_back(vertices[verticesIndices[i+v]]);
if (hasNormals) {
meshNormals.push_back(normals[normalsIndices[i+v]]);
}
if (hasUvs) {
meshUVs.push_back(uvs[uvsIndices[i+v]]);
}
mapVertNormTexToVertexIndex.insert(std::make_pair(key, newVerticesIndices[v]));
}
else {
// Get the vertex index to use
newVerticesIndices[v] = itFound->second;
}
}
// Get the current vertex IDs
uint i1 = newVerticesIndices[0];
uint i2 = newVerticesIndices[1];
uint i3 = newVerticesIndices[2];
uint i4 = newVerticesIndices[3];
/*
// Add the vertex normal
if (!normalsIndices.empty() && !normals.empty()) {
if (hasNormals) {
meshNormals[i1] = normals[normalsIndices[i]];
meshNormals[i2] = normals[normalsIndices[i+1]];
meshNormals[i3] = normals[normalsIndices[i+2]];
}
// Add the vertex UV texture coordinates
if (!uvsIndices.empty() && !uvs.empty()) {
if (hasUvs) {
meshUVs[i1] = uvs[uvsIndices[i]];
meshUVs[i2] = uvs[uvsIndices[i+1]];
meshUVs[i3] = uvs[uvsIndices[i+2]];
}
*/
// If the current vertex not in a quad (it is part of a triangle)
if (!isQuad[j]) {
@ -259,11 +321,10 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
}
else { // If the current vertex is in a quad
Vector3 v1 = vertices[i1];
Vector3 v2 = vertices[i2];
Vector3 v3 = vertices[i3];
uint i4 = verticesIndices[i+3];
Vector3 v4 = vertices[i4];
Vector3 v1 = meshVertices[i1];
Vector3 v2 = meshVertices[i2];
Vector3 v3 = meshVertices[i3];
Vector3 v4 = meshVertices[i4];
Vector3 v13 = v3-v1;
Vector3 v12 = v2-v1;
@ -288,6 +349,7 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
meshIndices[meshPart].push_back(i4);
}
/*
// Add the vertex normal
if (!normalsIndices.empty() && !normals.empty()) {
meshNormals[i4] = normals[normalsIndices[i]];
@ -297,17 +359,18 @@ void MeshReaderWriter::loadOBJFile(const string &filename, Mesh& meshToCreate) {
if (!uvsIndices.empty() && !uvs.empty()) {
meshUVs[i4] = uvs[uvsIndices[i]];
}
*/
i+=4;
}
}
assert(meshNormals.empty() || meshNormals.size() == vertices.size());
assert(meshUVs.empty() || meshUVs.size() == vertices.size());
assert(meshNormals.empty() || meshNormals.size() == meshVertices.size());
assert(meshUVs.empty() || meshUVs.size() == meshVertices.size());
// Set the data to the mesh
meshToCreate.setIndices(meshIndices);
meshToCreate.setVertices(vertices);
meshToCreate.setVertices(meshVertices);
meshToCreate.setNormals(meshNormals);
meshToCreate.setUVs(meshUVs);
}

View File

@ -93,4 +93,15 @@ class VertexMergingDataComparison {
}
namespace std {
template<>
struct hash<std::tuple<int, int, int>>
{
size_t operator()(const std::tuple<int, int, int>& key) const
{
return std::get<0>(key) ^ std::get<1>(key) ^ std::get<2>(key);
}
};
}
#endif

View File

@ -95,6 +95,11 @@ class Shader {
// to set it, an assert will occur)
void setIntUniform(const std::string& variableName, int value, bool errorIfMissing = true) const;
// Set an array of int uniform values to this shader (be careful if the uniform is not
// used in the shader, the compiler will remove it, then when you will try
// to set it, an assert will occur)
void setIntArrayUniform(const std::string& variableName, GLint* values, int nbValues, bool errorIfMissing = true) const;
// Set a vector 2 uniform value to this shader (be careful if the uniform is not
// used in the shader, the compiler will remove it, then when you will try
// to set it, an assert will occur)
@ -159,7 +164,7 @@ inline GLint Shader::getUniformLocation(const std::string& variableName, bool er
std::cerr << "Error in vertex shader " << mFilenameVertexShader << " or in fragment shader"
<< mFilenameFragmentShader << " : No Uniform variable : " << variableName
<< std::endl;
throw std::logic_error("Error in Shader");
//throw std::logic_error("Error in Shader");
}
return location;
@ -209,6 +214,16 @@ inline void Shader::setIntUniform(const std::string& variableName, int value, bo
}
}
// Set an array of int uniform values to this shader (be careful if the uniform is not
// used in the shader, the compiler will remove it, then when you will try
// to set it, an assert will occur)
inline void Shader::setIntArrayUniform(const std::string& variableName, GLint* values, int nbValues, bool errorIfMissing) const {
assert(mProgramObjectID != 0);
GLint location = getUniformLocation(variableName, errorIfMissing);
if (location != -1) {
glUniform1iv(location, nbValues, values);
}
}
// Set a vector 2 uniform value to this shader (be careful if the uniform is not
// used in the shader, the compiler will remove it, then when you will try
// to set it, an assert will occur)

View File

@ -1,350 +1,350 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "CollisionDetectionScene.h"
#include "constraint/ContactPoint.h"
#include "collision/ContactManifold.h"
// Namespaces
using namespace openglframework;
using namespace collisiondetectionscene;
// Constructor
CollisionDetectionScene::CollisionDetectionScene(const std::string& name, EngineSettings& settings)
: SceneDemo(name, settings, SCENE_RADIUS, false), mMeshFolderPath("meshes/"),
mContactManager(mPhongShader, mMeshFolderPath),
mAreNormalsDisplayed(false) {
mSelectedShapeIndex = 0;
mIsContactPointsDisplayed = true;
mIsWireframeEnabled = true;
// Compute the radius and the center of the scene
openglframework::Vector3 center(0, 0, 0);
// Set the center of the scene
setScenePosition(center, SCENE_RADIUS);
rp3d::WorldSettings worldSettings;
worldSettings.worldName = name;
// Create the dynamics world for the physics simulation
mPhysicsWorld = new rp3d::CollisionWorld(worldSettings);
// ---------- Sphere 1 ---------- //
// Create a sphere and a corresponding collision body in the dynamics world
mSphere1 = new Sphere(4, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mSphere1);
// Set the color
mSphere1->setColor(mGreyColorDemo);
mSphere1->setSleepingColor(mRedColorDemo);
//mSphere1->setScaling(0.5f);
mPhysicsObjects.push_back(mSphere1);
// ---------- Sphere 2 ---------- //
// Create a sphere and a corresponding collision body in the dynamics world
mSphere2 = new Sphere(2, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mSphere2);
// Set the color
mSphere2->setColor(mGreyColorDemo);
mSphere2->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mSphere2);
// ---------- Capsule 1 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mCapsule1 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mCapsule1);
// Set the color
mCapsule1->setColor(mGreyColorDemo);
mCapsule1->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mCapsule1);
// ---------- Capsule 2 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mCapsule2 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mCapsule2);
// Set the color
mCapsule2->setColor(mGreyColorDemo);
mCapsule2->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mCapsule2);
// ---------- Concave Mesh ---------- //
// Create a convex mesh and a corresponding collision body in the dynamics world
mConcaveMesh = new ConcaveMesh(mPhysicsWorld, mMeshFolderPath + "city.obj");
mAllShapes.push_back(mConcaveMesh);
// Set the color
mConcaveMesh->setColor(mGreyColorDemo);
mConcaveMesh->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mConcaveMesh);
// ---------- Box 1 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mBox1 = new Box(BOX_SIZE, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mBox1);
// Set the color
mBox1->setColor(mGreyColorDemo);
mBox1->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mBox1);
// ---------- Box 2 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mBox2 = new Box(openglframework::Vector3(3, 2, 5), mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mBox2);
// Set the color
mBox2->setColor(mGreyColorDemo);
mBox2->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mBox2);
// ---------- Convex Mesh ---------- //
// Create a convex mesh and a corresponding collision body in the dynamics world
mConvexMesh = new ConvexMesh(mPhysicsWorld, mMeshFolderPath + "convexmesh.obj");
mAllShapes.push_back(mConvexMesh);
// Set the color
mConvexMesh->setColor(mGreyColorDemo);
mConvexMesh->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mConvexMesh);
// ---------- Heightfield ---------- //
// Create a convex mesh and a corresponding collision body in the dynamics world
mHeightField = new HeightField(mPhysicsWorld);
// Set the color
mHeightField->setColor(mGreyColorDemo);
mHeightField->setSleepingColor(mRedColorDemo);
mPhysicsObjects.push_back(mHeightField);
mAllShapes[mSelectedShapeIndex]->setColor(mBlueColorDemo);
}
// Reset the scene
void CollisionDetectionScene::reset() {
mSphere1->setTransform(rp3d::Transform(rp3d::Vector3(15, 5, 0), rp3d::Quaternion::identity()));
mSphere2->setTransform(rp3d::Transform(rp3d::Vector3(0, 6, 0), rp3d::Quaternion::identity()));
mCapsule1->setTransform(rp3d::Transform(rp3d::Vector3(-8, 7, 0), rp3d::Quaternion::identity()));
mCapsule2->setTransform(rp3d::Transform(rp3d::Vector3(11, -8, 0), rp3d::Quaternion::identity()));
mBox1->setTransform(rp3d::Transform(rp3d::Vector3(-4, -7, 0), rp3d::Quaternion::identity()));
mBox2->setTransform(rp3d::Transform(rp3d::Vector3(0, 9, 0), rp3d::Quaternion::identity()));
mConvexMesh->setTransform(rp3d::Transform(rp3d::Vector3(-5, 0, 0), rp3d::Quaternion::identity()));
mConcaveMesh->setTransform(rp3d::Transform(rp3d::Vector3(0, 15, 0), rp3d::Quaternion::identity()));
mHeightField->setTransform(rp3d::Transform(rp3d::Vector3(0, -22, 0), rp3d::Quaternion::identity()));
}
// Destructor
CollisionDetectionScene::~CollisionDetectionScene() {
// Destroy the box rigid body from the dynamics world
//mPhysicsWorld->destroyCollisionBody(mBox->getCollisionBody());
//delete mBox;
// Destroy the spheres
mPhysicsWorld->destroyCollisionBody(mSphere1->getCollisionBody());
delete mSphere1;
mPhysicsWorld->destroyCollisionBody(mSphere2->getCollisionBody());
delete mSphere2;
mPhysicsWorld->destroyCollisionBody(mCapsule1->getCollisionBody());
delete mCapsule1;
mPhysicsWorld->destroyCollisionBody(mCapsule2->getCollisionBody());
delete mCapsule2;
mPhysicsWorld->destroyCollisionBody(mBox1->getCollisionBody());
delete mBox1;
mPhysicsWorld->destroyCollisionBody(mBox2->getCollisionBody());
delete mBox2;
mPhysicsWorld->destroyCollisionBody(mConvexMesh->getCollisionBody());
delete mConvexMesh;
mPhysicsWorld->destroyCollisionBody(mConcaveMesh->getCollisionBody());
delete mConcaveMesh;
mPhysicsWorld->destroyCollisionBody(mHeightField->getCollisionBody());
delete mHeightField;
mContactManager.resetPoints();
// Destroy the static data for the visual contact points
VisualContactPoint::destroyStaticData();
// Destroy the collision world
delete mPhysicsWorld;
}
// Take a step for the simulation
void CollisionDetectionScene::update() {
mContactManager.resetPoints();
mPhysicsWorld->testCollision(&mContactManager);
SceneDemo::update();
}
void CollisionDetectionScene::selectNextShape() {
uint previousIndex = mSelectedShapeIndex;
mSelectedShapeIndex++;
if (mSelectedShapeIndex >= mAllShapes.size()) {
mSelectedShapeIndex = 0;
}
mAllShapes[previousIndex]->setColor(mGreyColorDemo);
mAllShapes[mSelectedShapeIndex]->setColor(mBlueColorDemo);
}
// Called when a keyboard event occurs
bool CollisionDetectionScene::keyboardEvent(int key, int scancode, int action, int mods) {
// If the space key has been pressed
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) {
selectNextShape();
return true;
}
float stepDist = 0.2f;
float stepAngle = 15 * (3.14f / 180.0f);
if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(stepDist, 0, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_LEFT && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(-stepDist, 0, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_UP && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, stepDist, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_DOWN && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, -stepDist, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_Z && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, stepDist));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_H && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, -stepDist));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_A && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, stepAngle, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_D && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, -stepAngle, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_W && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(stepAngle, 0, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_S && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(-stepAngle, 0, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_F && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, stepAngle) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_G && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, -stepAngle) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
return false;
}
// This method will be called for each reported contact point
void ContactManager::notifyContact(const CollisionCallbackInfo& collisionCallbackInfo) {
// For each contact manifold
rp3d::ContactManifoldListElement* manifoldElement = collisionCallbackInfo.contactManifoldElements;
while (manifoldElement != nullptr) {
// Get the contact manifold
rp3d::ContactManifold* contactManifold = manifoldElement->getContactManifold();
// For each contact point
rp3d::ContactPoint* contactPoint = contactManifold->getContactPoints();
while (contactPoint != nullptr) {
// Contact normal
rp3d::Vector3 normal = contactPoint->getNormal();
openglframework::Vector3 contactNormal(normal.x, normal.y, normal.z);
rp3d::Vector3 point1 = contactPoint->getLocalPointOnShape1();
point1 = collisionCallbackInfo.proxyShape1->getLocalToWorldTransform() * point1;
openglframework::Vector3 position1(point1.x, point1.y, point1.z);
mContactPoints.push_back(ContactPoint(position1, contactNormal, openglframework::Color::red()));
rp3d::Vector3 point2 = contactPoint->getLocalPointOnShape2();
point2 = collisionCallbackInfo.proxyShape2->getLocalToWorldTransform() * point2;
openglframework::Vector3 position2(point2.x, point2.y, point2.z);
mContactPoints.push_back(ContactPoint(position2, contactNormal, openglframework::Color::blue()));
contactPoint = contactPoint->getNext();
}
manifoldElement = manifoldElement->getNext();
}
}
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "CollisionDetectionScene.h"
#include "constraint/ContactPoint.h"
#include "collision/ContactManifold.h"
// Namespaces
using namespace openglframework;
using namespace collisiondetectionscene;
// Constructor
CollisionDetectionScene::CollisionDetectionScene(const std::string& name, EngineSettings& settings)
: SceneDemo(name, settings, SCENE_RADIUS, false), mMeshFolderPath("meshes/"),
mContactManager(mPhongShader, mMeshFolderPath),
mAreNormalsDisplayed(false) {
mSelectedShapeIndex = 0;
mIsContactPointsDisplayed = true;
mIsWireframeEnabled = true;
// Compute the radius and the center of the scene
openglframework::Vector3 center(0, 0, 0);
// Set the center of the scene
setScenePosition(center, SCENE_RADIUS);
rp3d::WorldSettings worldSettings;
worldSettings.worldName = name;
// Create the dynamics world for the physics simulation
mPhysicsWorld = new rp3d::CollisionWorld(worldSettings);
// ---------- Sphere 1 ---------- //
// Create a sphere and a corresponding collision body in the dynamics world
mSphere1 = new Sphere(4, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mSphere1);
// Set the color
mSphere1->setColor(mObjectColorDemo);
mSphere1->setSleepingColor(mSleepingColorDemo);
//mSphere1->setScaling(0.5f);
mPhysicsObjects.push_back(mSphere1);
// ---------- Sphere 2 ---------- //
// Create a sphere and a corresponding collision body in the dynamics world
mSphere2 = new Sphere(2, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mSphere2);
// Set the color
mSphere2->setColor(mObjectColorDemo);
mSphere2->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mSphere2);
// ---------- Capsule 1 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mCapsule1 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mCapsule1);
// Set the color
mCapsule1->setColor(mObjectColorDemo);
mCapsule1->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mCapsule1);
// ---------- Capsule 2 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mCapsule2 = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mCapsule2);
// Set the color
mCapsule2->setColor(mObjectColorDemo);
mCapsule2->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mCapsule2);
// ---------- Concave Mesh ---------- //
// Create a convex mesh and a corresponding collision body in the dynamics world
mConcaveMesh = new ConcaveMesh(mPhysicsWorld, mMeshFolderPath + "city.obj");
mAllShapes.push_back(mConcaveMesh);
// Set the color
mConcaveMesh->setColor(mObjectColorDemo);
mConcaveMesh->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mConcaveMesh);
// ---------- Box 1 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mBox1 = new Box(BOX_SIZE, mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mBox1);
// Set the color
mBox1->setColor(mObjectColorDemo);
mBox1->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mBox1);
// ---------- Box 2 ---------- //
// Create a cylinder and a corresponding collision body in the dynamics world
mBox2 = new Box(openglframework::Vector3(3, 2, 5), mPhysicsWorld, mMeshFolderPath);
mAllShapes.push_back(mBox2);
// Set the color
mBox2->setColor(mObjectColorDemo);
mBox2->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mBox2);
// ---------- Convex Mesh ---------- //
// Create a convex mesh and a corresponding collision body in the dynamics world
mConvexMesh = new ConvexMesh(mPhysicsWorld, mMeshFolderPath + "convexmesh.obj");
mAllShapes.push_back(mConvexMesh);
// Set the color
mConvexMesh->setColor(mObjectColorDemo);
mConvexMesh->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mConvexMesh);
// ---------- Heightfield ---------- //
// Create a convex mesh and a corresponding collision body in the dynamics world
mHeightField = new HeightField(mPhysicsWorld);
// Set the color
mHeightField->setColor(mObjectColorDemo);
mHeightField->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mHeightField);
mAllShapes[mSelectedShapeIndex]->setColor(mObjectColorDemo);
}
// Reset the scene
void CollisionDetectionScene::reset() {
mSphere1->setTransform(rp3d::Transform(rp3d::Vector3(15, 5, 0), rp3d::Quaternion::identity()));
mSphere2->setTransform(rp3d::Transform(rp3d::Vector3(0, 6, 0), rp3d::Quaternion::identity()));
mCapsule1->setTransform(rp3d::Transform(rp3d::Vector3(-8, 7, 0), rp3d::Quaternion::identity()));
mCapsule2->setTransform(rp3d::Transform(rp3d::Vector3(11, -8, 0), rp3d::Quaternion::identity()));
mBox1->setTransform(rp3d::Transform(rp3d::Vector3(-4, -7, 0), rp3d::Quaternion::identity()));
mBox2->setTransform(rp3d::Transform(rp3d::Vector3(0, 9, 0), rp3d::Quaternion::identity()));
mConvexMesh->setTransform(rp3d::Transform(rp3d::Vector3(-5, 0, 0), rp3d::Quaternion::identity()));
mConcaveMesh->setTransform(rp3d::Transform(rp3d::Vector3(0, 15, 0), rp3d::Quaternion::identity()));
mHeightField->setTransform(rp3d::Transform(rp3d::Vector3(0, -22, 0), rp3d::Quaternion::identity()));
}
// Destructor
CollisionDetectionScene::~CollisionDetectionScene() {
// Destroy the box rigid body from the dynamics world
//mPhysicsWorld->destroyCollisionBody(mBox->getCollisionBody());
//delete mBox;
// Destroy the spheres
mPhysicsWorld->destroyCollisionBody(mSphere1->getCollisionBody());
delete mSphere1;
mPhysicsWorld->destroyCollisionBody(mSphere2->getCollisionBody());
delete mSphere2;
mPhysicsWorld->destroyCollisionBody(mCapsule1->getCollisionBody());
delete mCapsule1;
mPhysicsWorld->destroyCollisionBody(mCapsule2->getCollisionBody());
delete mCapsule2;
mPhysicsWorld->destroyCollisionBody(mBox1->getCollisionBody());
delete mBox1;
mPhysicsWorld->destroyCollisionBody(mBox2->getCollisionBody());
delete mBox2;
mPhysicsWorld->destroyCollisionBody(mConvexMesh->getCollisionBody());
delete mConvexMesh;
mPhysicsWorld->destroyCollisionBody(mConcaveMesh->getCollisionBody());
delete mConcaveMesh;
mPhysicsWorld->destroyCollisionBody(mHeightField->getCollisionBody());
delete mHeightField;
mContactManager.resetPoints();
// Destroy the static data for the visual contact points
VisualContactPoint::destroyStaticData();
// Destroy the collision world
delete mPhysicsWorld;
}
// Take a step for the simulation
void CollisionDetectionScene::update() {
mContactManager.resetPoints();
mPhysicsWorld->testCollision(&mContactManager);
SceneDemo::update();
}
void CollisionDetectionScene::selectNextShape() {
uint previousIndex = mSelectedShapeIndex;
mSelectedShapeIndex++;
if (mSelectedShapeIndex >= mAllShapes.size()) {
mSelectedShapeIndex = 0;
}
mAllShapes[previousIndex]->setColor(mObjectColorDemo);
mAllShapes[mSelectedShapeIndex]->setColor(mSelectedObjectColorDemo);
}
// Called when a keyboard event occurs
bool CollisionDetectionScene::keyboardEvent(int key, int scancode, int action, int mods) {
// If the space key has been pressed
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) {
selectNextShape();
return true;
}
float stepDist = 0.2f;
float stepAngle = 15 * (3.14f / 180.0f);
if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(stepDist, 0, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_LEFT && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(-stepDist, 0, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_UP && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, stepDist, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_DOWN && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, -stepDist, 0));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_Z && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, stepDist));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_H && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setPosition(transform.getPosition() + rp3d::Vector3(0, 0, -stepDist));
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_A && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, stepAngle, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_D && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, -stepAngle, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_W && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(stepAngle, 0, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_S && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(-stepAngle, 0, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_F && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, stepAngle) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
else if (key == GLFW_KEY_G && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, -stepAngle) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform);
}
return false;
}
// This method will be called for each reported contact point
void ContactManager::notifyContact(const CollisionCallbackInfo& collisionCallbackInfo) {
// For each contact manifold
rp3d::ContactManifoldListElement* manifoldElement = collisionCallbackInfo.contactManifoldElements;
while (manifoldElement != nullptr) {
// Get the contact manifold
rp3d::ContactManifold* contactManifold = manifoldElement->getContactManifold();
// For each contact point
rp3d::ContactPoint* contactPoint = contactManifold->getContactPoints();
while (contactPoint != nullptr) {
// Contact normal
rp3d::Vector3 normal = contactPoint->getNormal();
openglframework::Vector3 contactNormal(normal.x, normal.y, normal.z);
rp3d::Vector3 point1 = contactPoint->getLocalPointOnShape1();
point1 = collisionCallbackInfo.proxyShape1->getLocalToWorldTransform() * point1;
openglframework::Vector3 position1(point1.x, point1.y, point1.z);
mContactPoints.push_back(ContactPoint(position1, contactNormal, openglframework::Color::red()));
rp3d::Vector3 point2 = contactPoint->getLocalPointOnShape2();
point2 = collisionCallbackInfo.proxyShape2->getLocalToWorldTransform() * point2;
openglframework::Vector3 position2(point2.x, point2.y, point2.z);
mContactPoints.push_back(ContactPoint(position2, contactNormal, openglframework::Color::blue()));
contactPoint = contactPoint->getNext();
}
manifoldElement = manifoldElement->getNext();
}
}

View File

@ -57,8 +57,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin
Dumbbell* dumbbell = new Dumbbell(getDynamicsWorld(), meshFolderPath);
// Set the box color
dumbbell->setColor(mDemoColors[i % mNbDemoColors]);
dumbbell->setSleepingColor(mRedColorDemo);
dumbbell->setColor(mObjectColorDemo);
dumbbell->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = dumbbell->getRigidBody()->getMaterial();
@ -76,8 +76,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin
Box* box = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath);
// Set the box color
box->setColor(mDemoColors[i % mNbDemoColors]);
box->setSleepingColor(mRedColorDemo);
box->setColor(mObjectColorDemo);
box->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = box->getRigidBody()->getMaterial();
@ -98,8 +98,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin
sphere->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08));
// Set the box color
sphere->setColor(mDemoColors[i % mNbDemoColors]);
sphere->setSleepingColor(mRedColorDemo);
sphere->setColor(mObjectColorDemo);
sphere->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = sphere->getRigidBody()->getMaterial();
@ -120,8 +120,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin
capsule->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08f));
// Set the box color
capsule->setColor(mDemoColors[i % mNbDemoColors]);
capsule->setSleepingColor(mRedColorDemo);
capsule->setColor(mObjectColorDemo);
capsule->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = capsule->getRigidBody()->getMaterial();
@ -139,8 +139,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin
ConvexMesh* mesh = new ConvexMesh(MESH_MASS, getDynamicsWorld(), meshFolderPath + "convexmesh.obj");
// Set the box color
mesh->setColor(mDemoColors[i % mNbDemoColors]);
mesh->setSleepingColor(mRedColorDemo);
mesh->setColor(mObjectColorDemo);
mesh->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = mesh->getRigidBody()->getMaterial();
@ -157,8 +157,8 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name, EngineSettin
mPhysicsObjects.push_back(mFloor);
// Set the box color
mFloor->setColor(mGreyColorDemo);
mFloor->setSleepingColor(mGreyColorDemo);
mFloor->setColor(mFloorColorDemo);
mFloor->setSleepingColor(mFloorColorDemo);
// The floor must be a static rigid body
mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC);

View File

@ -58,8 +58,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett
Dumbbell* dumbbell = new Dumbbell(getDynamicsWorld(), meshFolderPath);
// Set the box color
dumbbell->setColor(mDemoColors[i % mNbDemoColors]);
dumbbell->setSleepingColor(mRedColorDemo);
dumbbell->setColor(mObjectColorDemo);
dumbbell->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = dumbbell->getRigidBody()->getMaterial();
@ -77,8 +77,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett
Box* box = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath);
// Set the box color
box->setColor(mDemoColors[i % mNbDemoColors]);
box->setSleepingColor(mRedColorDemo);
box->setColor(mObjectColorDemo);
box->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = box->getRigidBody()->getMaterial();
@ -99,8 +99,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett
sphere->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08));
// Set the box color
sphere->setColor(mDemoColors[i % mNbDemoColors]);
sphere->setSleepingColor(mRedColorDemo);
sphere->setColor(mObjectColorDemo);
sphere->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = sphere->getRigidBody()->getMaterial();
@ -121,8 +121,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett
capsule->getRigidBody()->getMaterial().setRollingResistance(rp3d::decimal(0.08));
// Set the box color
capsule->setColor(mDemoColors[i % mNbDemoColors]);
capsule->setSleepingColor(mRedColorDemo);
capsule->setColor(mObjectColorDemo);
capsule->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = capsule->getRigidBody()->getMaterial();
@ -140,8 +140,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett
ConvexMesh* mesh = new ConvexMesh(MESH_MASS, getDynamicsWorld(), meshFolderPath + "convexmesh.obj");
// Set the box color
mesh->setColor(mDemoColors[i % mNbDemoColors]);
mesh->setSleepingColor(mRedColorDemo);
mesh->setColor(mObjectColorDemo);
mesh->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = mesh->getRigidBody()->getMaterial();
@ -164,8 +164,8 @@ ConcaveMeshScene::ConcaveMeshScene(const std::string& name, EngineSettings& sett
mConcaveMesh->getRigidBody()->setType(rp3d::BodyType::STATIC);
// Set the box color
mConcaveMesh->setColor(mGreyColorDemo);
mConcaveMesh->setSleepingColor(mGreyColorDemo);
mConcaveMesh->setColor(mFloorColorDemo);
mConcaveMesh->setSleepingColor(mFloorColorDemo);
mPhysicsObjects.push_back(mConcaveMesh);

View File

@ -1,139 +1,139 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "CubesScene.h"
// Namespaces
using namespace openglframework;
using namespace cubesscene;
// Constructor
CubesScene::CubesScene(const std::string& name, EngineSettings& settings)
: SceneDemo(name, settings, 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);
rp3d::WorldSettings worldSettings;
worldSettings.worldName = name;
// Create the dynamics world for the physics simulation
mPhysicsWorld = new rp3d::DynamicsWorld(gravity, worldSettings);
// Create all the cubes of the scene
for (int i=0; i<NB_CUBES; i++) {
// Create a cube and a corresponding rigid in the dynamics world
Box* cube = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath);
// Set the box color
cube->setColor(mDemoColors[i % mNbDemoColors]);
cube->setSleepingColor(mRedColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = cube->getRigidBody()->getMaterial();
material.setBounciness(rp3d::decimal(0.4));
// Add the box the list of box in the scene
mBoxes.push_back(cube);
mPhysicsObjects.push_back(cube);
}
// ------------------------- FLOOR ----------------------- //
// Create the floor
mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath);
mFloor->setColor(mGreyColorDemo);
mFloor->setSleepingColor(mGreyColorDemo);
// The floor must be a static rigid body
mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC);
mPhysicsObjects.push_back(mFloor);
// Get the physics engine parameters
mEngineSettings.isGravityEnabled = getDynamicsWorld()->isGravityEnabled();
rp3d::Vector3 gravityVector = getDynamicsWorld()->getGravity();
mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z);
mEngineSettings.isSleepingEnabled = getDynamicsWorld()->isSleepingEnabled();
mEngineSettings.sleepLinearVelocity = getDynamicsWorld()->getSleepLinearVelocity();
mEngineSettings.sleepAngularVelocity = getDynamicsWorld()->getSleepAngularVelocity();
mEngineSettings.nbPositionSolverIterations = getDynamicsWorld()->getNbIterationsPositionSolver();
mEngineSettings.nbVelocitySolverIterations = getDynamicsWorld()->getNbIterationsVelocitySolver();
mEngineSettings.timeBeforeSleep = getDynamicsWorld()->getTimeBeforeSleep();
}
// Destructor
CubesScene::~CubesScene() {
// Destroy all the cubes of the scene
for (std::vector<Box*>::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) {
// Destroy the corresponding rigid body from the dynamics world
getDynamicsWorld()->destroyRigidBody((*it)->getRigidBody());
// Destroy the cube
delete (*it);
}
// Destroy the rigid body of the floor
getDynamicsWorld()->destroyRigidBody(mFloor->getRigidBody());
// Destroy the floor
delete mFloor;
// Destroy the dynamics world
delete getDynamicsWorld();
}
// Reset the scene
void CubesScene::reset() {
float radius = 2.0f;
// Create all the cubes of the scene
std::vector<Box*>::iterator it;
int i = 0;
for (it = mBoxes.begin(); it != mBoxes.end(); ++it) {
// Position of the cubes
float angle = i * 30.0f;
rp3d::Vector3 position(radius * std::cos(angle),
10 + i * (BOX_SIZE.y + 0.3f),
0);
(*it)->setTransform(rp3d::Transform(position, rp3d::Quaternion::identity()));
i++;
}
mFloor->setTransform(rp3d::Transform(rp3d::Vector3::zero(), rp3d::Quaternion::identity()));
}
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "CubesScene.h"
// Namespaces
using namespace openglframework;
using namespace cubesscene;
// Constructor
CubesScene::CubesScene(const std::string& name, EngineSettings& settings)
: SceneDemo(name, settings, 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);
rp3d::WorldSettings worldSettings;
worldSettings.worldName = name;
// Create the dynamics world for the physics simulation
mPhysicsWorld = new rp3d::DynamicsWorld(gravity, worldSettings);
// Create all the cubes of the scene
for (int i=0; i<NB_CUBES; i++) {
// Create a cube and a corresponding rigid in the dynamics world
Box* cube = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath);
// Set the box color
cube->setColor(mObjectColorDemo);
cube->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = cube->getRigidBody()->getMaterial();
material.setBounciness(rp3d::decimal(0.4));
// Add the box the list of box in the scene
mBoxes.push_back(cube);
mPhysicsObjects.push_back(cube);
}
// ------------------------- FLOOR ----------------------- //
// Create the floor
mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath);
mFloor->setColor(mFloorColorDemo);
mFloor->setSleepingColor(mFloorColorDemo);
// The floor must be a static rigid body
mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC);
mPhysicsObjects.push_back(mFloor);
// Get the physics engine parameters
mEngineSettings.isGravityEnabled = getDynamicsWorld()->isGravityEnabled();
rp3d::Vector3 gravityVector = getDynamicsWorld()->getGravity();
mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z);
mEngineSettings.isSleepingEnabled = getDynamicsWorld()->isSleepingEnabled();
mEngineSettings.sleepLinearVelocity = getDynamicsWorld()->getSleepLinearVelocity();
mEngineSettings.sleepAngularVelocity = getDynamicsWorld()->getSleepAngularVelocity();
mEngineSettings.nbPositionSolverIterations = getDynamicsWorld()->getNbIterationsPositionSolver();
mEngineSettings.nbVelocitySolverIterations = getDynamicsWorld()->getNbIterationsVelocitySolver();
mEngineSettings.timeBeforeSleep = getDynamicsWorld()->getTimeBeforeSleep();
}
// Destructor
CubesScene::~CubesScene() {
// Destroy all the cubes of the scene
for (std::vector<Box*>::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) {
// Destroy the corresponding rigid body from the dynamics world
getDynamicsWorld()->destroyRigidBody((*it)->getRigidBody());
// Destroy the cube
delete (*it);
}
// Destroy the rigid body of the floor
getDynamicsWorld()->destroyRigidBody(mFloor->getRigidBody());
// Destroy the floor
delete mFloor;
// Destroy the dynamics world
delete getDynamicsWorld();
}
// Reset the scene
void CubesScene::reset() {
float radius = 2.0f;
// Create all the cubes of the scene
std::vector<Box*>::iterator it;
int i = 0;
for (it = mBoxes.begin(); it != mBoxes.end(); ++it) {
// Position of the cubes
float angle = i * 30.0f;
rp3d::Vector3 position(radius * std::cos(angle),
10 + i * (BOX_SIZE.y + 0.3f),
0);
(*it)->setTransform(rp3d::Transform(position, rp3d::Quaternion::identity()));
i++;
}
mFloor->setTransform(rp3d::Transform(rp3d::Vector3::zero(), rp3d::Quaternion::identity()));
}

View File

@ -58,8 +58,8 @@ CubeStackScene::CubeStackScene(const std::string& name, EngineSettings& settings
Box* cube = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath);
// Set the box color
cube->setColor(mDemoColors[i % mNbDemoColors]);
cube->setSleepingColor(mRedColorDemo);
cube->setColor(mObjectColorDemo);
cube->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = cube->getRigidBody()->getMaterial();
@ -75,8 +75,8 @@ CubeStackScene::CubeStackScene(const std::string& name, EngineSettings& settings
// Create the floor
mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath);
mFloor->setColor(mGreyColorDemo);
mFloor->setSleepingColor(mGreyColorDemo);
mFloor->setColor(mFloorColorDemo);
mFloor->setSleepingColor(mFloorColorDemo);
// The floor must be a static rigid body
mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC);

View File

@ -57,8 +57,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett
Dumbbell* dumbbell = new Dumbbell(getDynamicsWorld(), meshFolderPath);
// Set the box color
dumbbell->setColor(mDemoColors[i % mNbDemoColors]);
dumbbell->setSleepingColor(mRedColorDemo);
dumbbell->setColor(mObjectColorDemo);
dumbbell->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = dumbbell->getRigidBody()->getMaterial();
@ -76,8 +76,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett
Box* box = new Box(BOX_SIZE, BOX_MASS, getDynamicsWorld(), mMeshFolderPath);
// Set the box color
box->setColor(mDemoColors[i % mNbDemoColors]);
box->setSleepingColor(mRedColorDemo);
box->setColor(mObjectColorDemo);
box->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = box->getRigidBody()->getMaterial();
@ -98,8 +98,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett
sphere->getRigidBody()->getMaterial().setRollingResistance(0.08f);
// Set the box color
sphere->setColor(mDemoColors[i % mNbDemoColors]);
sphere->setSleepingColor(mRedColorDemo);
sphere->setColor(mObjectColorDemo);
sphere->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = sphere->getRigidBody()->getMaterial();
@ -120,8 +120,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett
capsule->getRigidBody()->getMaterial().setRollingResistance(0.08f);
// Set the box color
capsule->setColor(mDemoColors[i % mNbDemoColors]);
capsule->setSleepingColor(mRedColorDemo);
capsule->setColor(mObjectColorDemo);
capsule->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = capsule->getRigidBody()->getMaterial();
@ -139,8 +139,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett
ConvexMesh* mesh = new ConvexMesh(MESH_MASS, getDynamicsWorld(), meshFolderPath + "convexmesh.obj");
// Set the box color
mesh->setColor(mDemoColors[i % mNbDemoColors]);
mesh->setSleepingColor(mRedColorDemo);
mesh->setColor(mObjectColorDemo);
mesh->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = mesh->getRigidBody()->getMaterial();
@ -165,8 +165,8 @@ HeightFieldScene::HeightFieldScene(const std::string& name, EngineSettings& sett
mPhysicsObjects.push_back(mHeightField);
// Set the color
mHeightField->setColor(mGreyColorDemo);
mHeightField->setSleepingColor(mGreyColorDemo);
mHeightField->setColor(mFloorColorDemo);
mHeightField->setSleepingColor(mFloorColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = mHeightField->getRigidBody()->getMaterial();

View File

@ -214,8 +214,8 @@ void JointsScene::createBallAndSocketJoints() {
mBallAndSocketJointChainBoxes[i]->setTransform(rp3d::Transform(positionBox, rp3d::Quaternion::identity()));
// Set the box color
mBallAndSocketJointChainBoxes[i]->setColor(mDemoColors[i % mNbDemoColors]);
mBallAndSocketJointChainBoxes[i]->setSleepingColor(mRedColorDemo);
mBallAndSocketJointChainBoxes[i]->setColor(mObjectColorDemo);
mBallAndSocketJointChainBoxes[i]->setSleepingColor(mSleepingColorDemo);
// The fist box cannot move (static body)
if (i == 0) {
@ -266,8 +266,8 @@ void JointsScene::createSliderJoint() {
mSliderJointBottomBox->setTransform(rp3d::Transform(positionBox1, rp3d::Quaternion::identity()));
// Set the box color
mSliderJointBottomBox->setColor(mBlueColorDemo);
mSliderJointBottomBox->setSleepingColor(mRedColorDemo);
mSliderJointBottomBox->setColor(mObjectColorDemo);
mSliderJointBottomBox->setSleepingColor(mSleepingColorDemo);
// The fist box cannot move
mSliderJointBottomBox->getRigidBody()->setType(rp3d::BodyType::STATIC);
@ -288,8 +288,8 @@ void JointsScene::createSliderJoint() {
mSliderJointTopBox->setTransform(rp3d::Transform(positionBox2, rp3d::Quaternion::identity()));
// Set the box color
mSliderJointTopBox->setColor(mOrangeColorDemo);
mSliderJointTopBox->setSleepingColor(mRedColorDemo);
mSliderJointTopBox->setColor(mObjectColorDemo);
mSliderJointTopBox->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material2 = mSliderJointTopBox->getRigidBody()->getMaterial();
@ -330,8 +330,8 @@ void JointsScene::createPropellerHingeJoint() {
mPropellerBox->setTransform(rp3d::Transform(positionBox1, rp3d::Quaternion::identity()));
// Set the box color
mPropellerBox->setColor(mYellowColorDemo);
mPropellerBox->setSleepingColor(mRedColorDemo);
mPropellerBox->setColor(mObjectColorDemo);
mPropellerBox->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material = mPropellerBox->getRigidBody()->getMaterial();
@ -371,8 +371,8 @@ void JointsScene::createFixedJoints() {
mFixedJointBox1->setTransform(rp3d::Transform(positionBox1, rp3d::Quaternion::identity()));
// Set the box color
mFixedJointBox1->setColor(mPinkColorDemo);
mFixedJointBox1->setSleepingColor(mRedColorDemo);
mFixedJointBox1->setColor(mObjectColorDemo);
mFixedJointBox1->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material1 = mFixedJointBox1->getRigidBody()->getMaterial();
@ -389,8 +389,8 @@ void JointsScene::createFixedJoints() {
mFixedJointBox2->setTransform(rp3d::Transform(positionBox2, rp3d::Quaternion::identity()));
// Set the box color
mFixedJointBox2->setColor(mBlueColorDemo);
mFixedJointBox2->setSleepingColor(mRedColorDemo);
mFixedJointBox2->setColor(mObjectColorDemo);
mFixedJointBox2->setSleepingColor(mSleepingColorDemo);
// Change the material properties of the rigid body
rp3d::Material& material2 = mFixedJointBox2->getRigidBody()->getMaterial();
@ -429,8 +429,8 @@ void JointsScene::createFloor() {
mFloor = new Box(FLOOR_SIZE, FLOOR_MASS, getDynamicsWorld(), mMeshFolderPath);
// Set the box color
mFloor->setColor(mGreyColorDemo);
mFloor->setSleepingColor(mGreyColorDemo);
mFloor->setColor(mFloorColorDemo);
mFloor->setSleepingColor(mFloorColorDemo);
// The floor must be a static rigid body
mFloor->getRigidBody()->setType(rp3d::BodyType::STATIC);

View File

@ -56,8 +56,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings)
mDumbbell = new Dumbbell(mPhysicsWorld, mMeshFolderPath);
// Set the box color
mDumbbell->setColor(mGreyColorDemo);
mDumbbell->setSleepingColor(mRedColorDemo);
mDumbbell->setColor(mObjectColorDemo);
mDumbbell->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mDumbbell);
// ---------- Box ---------- //
@ -67,8 +67,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings)
mBox->getCollisionBody()->setIsActive(false);
// Set the box color
mBox->setColor(mGreyColorDemo);
mBox->setSleepingColor(mRedColorDemo);
mBox->setColor(mObjectColorDemo);
mBox->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mBox);
// ---------- Sphere ---------- //
@ -77,8 +77,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings)
mSphere = new Sphere(SPHERE_RADIUS, mPhysicsWorld, mMeshFolderPath);
// Set the color
mSphere->setColor(mGreyColorDemo);
mSphere->setSleepingColor(mRedColorDemo);
mSphere->setColor(mObjectColorDemo);
mSphere->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mSphere);
// ---------- Capsule ---------- //
@ -88,8 +88,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings)
mCapsule = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, mPhysicsWorld, mMeshFolderPath);
// Set the color
mCapsule->setColor(mGreyColorDemo);
mCapsule->setSleepingColor(mRedColorDemo);
mCapsule->setColor(mObjectColorDemo);
mCapsule->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mCapsule);
// ---------- Convex Mesh ---------- //
@ -98,8 +98,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings)
mConvexMesh = new ConvexMesh(mPhysicsWorld, mMeshFolderPath + "convexmesh.obj");
// Set the color
mConvexMesh->setColor(mGreyColorDemo);
mConvexMesh->setSleepingColor(mRedColorDemo);
mConvexMesh->setColor(mObjectColorDemo);
mConvexMesh->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mConvexMesh);
// ---------- Concave Mesh ---------- //
@ -108,8 +108,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings)
mConcaveMesh = new ConcaveMesh(mPhysicsWorld, mMeshFolderPath + "city.obj");
// Set the color
mConcaveMesh->setColor(mGreyColorDemo);
mConcaveMesh->setSleepingColor(mRedColorDemo);
mConcaveMesh->setColor(mObjectColorDemo);
mConcaveMesh->setSleepingColor(mSleepingColorDemo);
mPhysicsObjects.push_back(mConcaveMesh);
// ---------- Heightfield ---------- //
@ -118,8 +118,8 @@ RaycastScene::RaycastScene(const std::string& name, EngineSettings& settings)
mHeightField = new HeightField(mPhysicsWorld);
// Set the color
mHeightField->setColor(mGreyColorDemo);
mHeightField->setSleepingColor(mRedColorDemo);
mHeightField->setColor(mObjectColorDemo);
mHeightField->setSleepingColor(mObjectColorDemo);
mPhysicsObjects.push_back(mHeightField);
// Create the lines that will be used for raycasting

View File

@ -1,103 +1,115 @@
#version 330
/********************************************************************************
* OpenGL-Framework *
* Copyright (c) 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. *
* *
********************************************************************************/
// Uniform variables
uniform vec3 lightAmbientColor; // Lights ambient color
uniform vec3 light0PosCameraSpace; // Camera-space position of the light
uniform vec3 light0DiffuseColor; // Light 0 diffuse color
uniform sampler2D textureSampler; // Texture
uniform sampler2D shadowMapSampler; // Shadow map texture sampler
uniform bool isTexture; // True if we need to use the texture
uniform vec4 vertexColor; // Vertex color
uniform bool isShadowEnabled; // True if shadow mapping is enabled
uniform vec2 shadowMapDimension; // Shadow map dimension
// In variables
in vec3 vertexPosCameraSpace; // Camera-space position of the vertex
in vec3 vertexNormalCameraSpace; // Vertex normal in camera-space
in vec2 texCoords; // Texture coordinates
in vec4 shadowMapCoords; // Shadow map texture coords
// Out variable
out vec4 color; // Output color
// Texture for PCF Shadow mapping
float textureLookupPCF(sampler2D map, vec2 texCoords, vec2 offset)
{
vec2 shadowMapScale = vec2(1.0, 1.0) / shadowMapDimension;
return texture(map, texCoords.xy + offset * shadowMapScale).r;
}
void main() {
// Compute the ambient term
vec3 ambient = lightAmbientColor;
// Get the texture color
vec3 textureColor = vertexColor.rgb;
if (isTexture) textureColor = texture(textureSampler, texCoords).rgb;
// Compute the surface normal vector
vec3 N = normalize(vertexNormalCameraSpace);
// Compute the diffuse term of light 0
vec3 L0 = normalize(light0PosCameraSpace - vertexPosCameraSpace);
float diffuseFactor = max(dot(N, L0), 0.0);
vec3 diffuse = light0DiffuseColor * diffuseFactor * textureColor;
// Compute shadow factor
float shadow = 1.0;
if (isShadowEnabled) {
shadow = 0.0;
float bias = 0.0003;
float shadowBias = -0.000;
vec4 shadowMapUV = shadowMapCoords;
shadowMapUV.z -= shadowBias;
vec4 shadowMapCoordsOverW = shadowMapUV / shadowMapUV.w;
// PCF Shadow Mapping
for (float i=-1; i<=1; i++) {
for (float j=-1; j<=1; j++) {
float distInShadowMap = textureLookupPCF(shadowMapSampler, shadowMapCoordsOverW.xy, vec2(i, j)) + bias;
if (shadowMapCoords.w > 0) {
shadow += distInShadowMap < shadowMapCoordsOverW.z ? 0.5 : 1.0;
}
}
}
shadow /= 9.0;
/*
float distanceInShadowMap = texture(shadowMapSampler, shadowMapCoordsOverW.xy).r + bias;
if (shadowMapCoords.w > 0) {
shadow = distanceInShadowMap < shadowMapCoordsOverW.z ? 0.5 : 1.0;
}
*/
}
// Compute the final color
color = vec4(ambient + shadow * diffuse, 1.0);
}
#version 330
/********************************************************************************
* OpenGL-Framework *
* Copyright (c) 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. *
* *
********************************************************************************/
// Uniform variables
uniform vec3 lightAmbientColor; // Lights ambient color
uniform vec3 light0PosCameraSpace; // Camera-space position of the light 0
uniform vec3 light1PosCameraSpace; // Camera-space position of the light 1
uniform vec3 light2PosCameraSpace; // Camera-space position of the light 2
uniform vec3 light0DiffuseColor; // Light 0 diffuse color
uniform vec3 light1DiffuseColor; // Light 1 diffuse color
uniform vec3 light2DiffuseColor; // Light 2 diffuse color
uniform sampler2D textureSampler; // Texture
uniform sampler2D shadowMapSampler[3]; // Shadow map texture sampler
uniform bool isTexture; // True if we need to use the texture
uniform vec4 vertexColor; // Vertex color
uniform bool isShadowEnabled; // True if shadow mapping is enabled
uniform vec2 shadowMapDimension; // Shadow map dimension
// In variables
in vec3 vertexPosCameraSpace; // Camera-space position of the vertex
in vec3 vertexNormalCameraSpace; // Vertex normal in camera-space
in vec2 texCoords; // Texture coordinates
in vec4 shadowMapCoords[3]; // Shadow map texture coords
// Out variable
out vec4 color; // Output color
// Texture for PCF Shadow mapping
float textureLookupPCF(sampler2D map, vec2 texCoords, vec2 offset)
{
vec2 shadowMapScale = vec2(1.0, 1.0) / shadowMapDimension;
return texture(map, texCoords.xy + offset * shadowMapScale).r;
}
void main() {
// Compute the ambient term
vec3 ambient = lightAmbientColor;
// Get the texture color
vec3 textureColor = vertexColor.rgb;
if (isTexture) textureColor = texture(textureSampler, texCoords).rgb;
// Compute the surface normal vector
vec3 N = normalize(vertexNormalCameraSpace);
color = vec4(ambient, 1);
vec3 lightPosCameraSpace[3];
lightPosCameraSpace[0] = light0PosCameraSpace;
lightPosCameraSpace[1] = light1PosCameraSpace;
lightPosCameraSpace[2] = light2PosCameraSpace;
vec3 lightDiffuseColor[3];
lightDiffuseColor[0] = light0DiffuseColor;
lightDiffuseColor[1] = light1DiffuseColor;
lightDiffuseColor[2] = light2DiffuseColor;
// For each light source
for (int l=0; l < 3; l++) {
// Compute the diffuse term of light 0
vec3 L0 = normalize(lightPosCameraSpace[l] - vertexPosCameraSpace);
float diffuseFactor = max(dot(N, L0), 0.0);
vec3 diffuse = lightDiffuseColor[l] * diffuseFactor * textureColor;
// Compute shadow factor
float shadow = 1.0;
if (isShadowEnabled) {
shadow = 0.0;
float bias = 0.0003;
float shadowBias = -0.000;
vec4 shadowMapUV = shadowMapCoords[l];
shadowMapUV.z -= shadowBias;
vec4 shadowMapCoordsOverW = shadowMapUV / shadowMapUV.w;
// PCF Shadow Mapping
for (float i=-1; i<=1; i++) {
for (float j=-1; j<=1; j++) {
float distInShadowMap = textureLookupPCF(shadowMapSampler[l], shadowMapCoordsOverW.xy, vec2(i, j)) + bias;
if (shadowMapCoords[l].w > 0) {
shadow += distInShadowMap < shadowMapCoordsOverW.z ? 0.5 : 1.0;
}
}
}
shadow /= 9.0;
}
// Compute the final color
color += vec4(shadow * diffuse, 0.0);
}
}

View File

@ -1,64 +1,78 @@
#version 330
/********************************************************************************
* OpenGL-Framework *
* Copyright (c) 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. *
* *
********************************************************************************/
// Uniform variables
uniform mat4 localToWorldMatrix; // Local-space to world-space matrix
uniform mat4 worldToCameraMatrix; // World-space to camera-space matrix
uniform mat4 worldToLight0CameraMatrix; // World-space to light0 camera-space matrix (for shadow mapping)
uniform mat4 projectionMatrix; // Projection matrix
uniform mat3 normalMatrix; // Normal matrix
uniform mat4 shadowMapProjectionMatrix; // Shadow map projection matrix
// In variables
in vec4 vertexPosition;
in vec3 vertexNormal;
in vec2 textureCoords;
// Out variables
out vec3 vertexPosCameraSpace; // Camera-space position of the vertex
out vec3 vertexNormalCameraSpace; // Vertex normal in camera-space
out vec2 texCoords; // Texture coordinates
out vec4 shadowMapCoords; // Shadow map texture coords
void main() {
// Compute the vertex position
vec4 positionCameraSpace = worldToCameraMatrix * localToWorldMatrix * vertexPosition;
vertexPosCameraSpace = positionCameraSpace.xyz;
// Compute the world surface normal
vertexNormalCameraSpace = normalMatrix * vertexNormal;
// Get the texture coordinates
texCoords = textureCoords;
// Compute the texture coords of the vertex in the shadow map
shadowMapCoords = shadowMapProjectionMatrix * worldToLight0CameraMatrix * localToWorldMatrix * vertexPosition;
// Compute the clip-space vertex coordinates
gl_Position = projectionMatrix * positionCameraSpace;
}
#version 330
/********************************************************************************
* OpenGL-Framework *
* Copyright (c) 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. *
* *
********************************************************************************/
// Uniform variables
uniform mat4 localToWorldMatrix; // Local-space to world-space matrix
uniform mat4 worldToCameraMatrix; // World-space to camera-space matrix
uniform mat4 worldToLight0CameraMatrix; // World-space to light0 camera-space matrix (for shadow mapping)
uniform mat4 worldToLight1CameraMatrix; // World-space to light1 camera-space matrix (for shadow mapping)
uniform mat4 worldToLight2CameraMatrix; // World-space to light2 camera-space matrix (for shadow mapping)
uniform mat4 projectionMatrix; // Projection matrix
uniform mat3 normalMatrix; // Normal matrix
uniform mat4 shadowMapLight0ProjectionMatrix; // Shadow map projection matrix for light 0
uniform mat4 shadowMapLight1ProjectionMatrix; // Shadow map projection matrix for light 1
uniform mat4 shadowMapLight2ProjectionMatrix; // Shadow map projection matrix for light 2
// In variables
in vec4 vertexPosition;
in vec3 vertexNormal;
in vec2 textureCoords;
// Out variables
out vec3 vertexPosCameraSpace; // Camera-space position of the vertex
out vec3 vertexNormalCameraSpace; // Vertex normal in camera-space
out vec2 texCoords; // Texture coordinates
out vec4 shadowMapCoords[3]; // Shadow map texture coords
void main() {
// Compute the vertex position
vec4 positionCameraSpace = worldToCameraMatrix * localToWorldMatrix * vertexPosition;
vertexPosCameraSpace = positionCameraSpace.xyz;
// Compute the world surface normal
vertexNormalCameraSpace = normalMatrix * vertexNormal;
// Get the texture coordinates
texCoords = textureCoords;
// Compute the texture coords of the vertex in the shadow map
mat4 worldToLightCameraMatrix[3];
worldToLightCameraMatrix[0] = worldToLight0CameraMatrix;
worldToLightCameraMatrix[1] = worldToLight1CameraMatrix;
worldToLightCameraMatrix[2] = worldToLight2CameraMatrix;
mat4 shadowMapProjectionMatrix[3];
shadowMapProjectionMatrix[0] = shadowMapLight0ProjectionMatrix;
shadowMapProjectionMatrix[1] = shadowMapLight1ProjectionMatrix;
shadowMapProjectionMatrix[2] = shadowMapLight2ProjectionMatrix;
for (int l=0; l < 3; l++) {
shadowMapCoords[l] = shadowMapProjectionMatrix[l] * worldToLightCameraMatrix[l] * localToWorldMatrix * vertexPosition;
}
// Compute the clip-space vertex coordinates
gl_Position = projectionMatrix * positionCameraSpace;
}

View File

@ -1,49 +1,64 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "TestbedApplication.h"
#include "nanogui/nanogui.h"
using namespace nanogui;
// Main function
int main(int argc, char** argv) {
nanogui::init();
{
// Create and start the testbed application
bool isFullscreen = false;
nanogui::ref<TestbedApplication> application = new TestbedApplication(isFullscreen);
application->setVisible(true);
nanogui::mainloop();
}
nanogui::shutdown();
return 0;
}
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "TestbedApplication.h"
#include "nanogui/nanogui.h"
using namespace nanogui;
// Main function
int main(int argc, char** argv) {
nanogui::init();
{
bool isFullscreen = false;
// Get the primary monitor
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
// Window size
int windowWidth = mode->width;
int windowHeight = mode->height;
if (!isFullscreen) {
windowWidth *= 0.9;
windowHeight *= 0.9;
}
// Create and start the testbed application
nanogui::ref<TestbedApplication> application = new TestbedApplication(isFullscreen, windowWidth, windowHeight);
application->setVisible(true);
nanogui::mainloop();
}
nanogui::shutdown();
return 0;
}

View File

@ -1,460 +1,522 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "SceneDemo.h"
#include <GLFW/glfw3.h>
#include "AABB.h"
#include "constraint/ContactPoint.h"
#include "collision/ContactManifold.h"
using namespace openglframework;
int SceneDemo::shadowMapTextureLevel = 0;
openglframework::Color SceneDemo::mGreyColorDemo = Color(0.70f, 0.70f, 0.7f, 1.0f);
openglframework::Color SceneDemo::mYellowColorDemo = Color(0.9f, 0.88f, 0.145f, 1.0f);
openglframework::Color SceneDemo::mBlueColorDemo = Color(0, 0.66f, 0.95f, 1.0f);
openglframework::Color SceneDemo::mOrangeColorDemo = Color(0.9f, 0.35f, 0, 1.0f);
openglframework::Color SceneDemo::mPinkColorDemo = Color(0.83f, 0.48f, 0.64f, 1.0f);
openglframework::Color SceneDemo::mRedColorDemo = Color(0.95f, 0, 0, 1.0f);
int SceneDemo::mNbDemoColors = 4;
openglframework::Color SceneDemo::mDemoColors[] = {SceneDemo::mYellowColorDemo, SceneDemo::mBlueColorDemo,
SceneDemo::mOrangeColorDemo, SceneDemo::mPinkColorDemo};
// Constructor
SceneDemo::SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled)
: Scene(name, settings, isShadowMappingEnabled), mIsShadowMappingInitialized(false),
mDepthShader("shaders/depth.vert", "shaders/depth.frag"),
mPhongShader("shaders/phong.vert", "shaders/phong.frag"),
mColorShader("shaders/color.vert", "shaders/color.frag"),
mQuadShader("shaders/quad.vert", "shaders/quad.frag"),
mVBOQuad(GL_ARRAY_BUFFER), mMeshFolderPath("meshes/"),
mPhysicsWorld(nullptr) {
shadowMapTextureLevel++;
// Move the light0
mLight0.translateWorld(Vector3(-2, 35, 40));
// Camera at light0 postion for the shadow map
mShadowMapLightCamera.translateWorld(mLight0.getOrigin());
mShadowMapLightCamera.rotateLocal(Vector3(1, 0, 0), -PI / 4.0f);
mShadowMapLightCamera.rotateWorld(Vector3(0, 1, 0), PI / 8.0f);
mShadowMapLightCamera.setDimensions(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT);
mShadowMapLightCamera.setFieldOfView(80.0f);
mShadowMapLightCamera.setSceneRadius(100);
mShadowMapBiasMatrix.setAllValues(0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0);
// Create the Shadow map FBO and texture
if (mIsShadowMappingEnabled) {
createShadowMapFBOAndTexture();
}
createQuadVBO();
// Init rendering for the AABBs
AABB::init();
VisualContactPoint::createStaticData(mMeshFolderPath);
}
// Destructor
SceneDemo::~SceneDemo() {
mShadowMapTexture.destroy();
mFBOShadowMap.destroy();
mVBOQuad.destroy();
mDepthShader.destroy();
mPhongShader.destroy();
mQuadShader.destroy();
mColorShader.destroy();
// Destroy the contact points
removeAllContactPoints();
// Destroy rendering data for the AABB
AABB::destroy();
VisualContactPoint::destroyStaticData();
}
// Update the scene
void SceneDemo::update() {
// Update the contact points
updateContactPoints();
// Update the position and orientation of the physics objects
for (std::vector<PhysicsObject*>::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) {
// Update the transform used for the rendering
(*it)->updateTransform(mInterpolationFactor);
}
}
// Update the physics world (take a simulation step)
// Can be called several times per frame
void SceneDemo::updatePhysics() {
if (getDynamicsWorld() != nullptr) {
// Take a simulation step
getDynamicsWorld()->update(mEngineSettings.timeStep);
}
}
// Render the scene (in multiple passes for shadow mapping)
void SceneDemo::render() {
const Color& diffCol = mLight0.getDiffuseColor();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
// ---------- Render the scene to generate the shadow map (first pass) ----------- //
const Matrix4 shadowMapProjMatrix = mShadowMapLightCamera.getProjectionMatrix();
const openglframework::Matrix4 worldToLightCameraMatrix = mShadowMapLightCamera.getTransformMatrix().getInverse();
// If Shadow Mapping is enabled
if (mIsShadowMappingEnabled) {
// Culling switching, rendering only backface, this is done to avoid self-shadowing
glCullFace(GL_BACK);
mFBOShadowMap.bind();
// Bind the shader
mDepthShader.bind();
// Set the variables of the shader
mDepthShader.setMatrix4x4Uniform("projectionMatrix", shadowMapProjMatrix);
// Set the viewport to render into the shadow map texture
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT);
// Clear previous frame values
glClear(GL_DEPTH_BUFFER_BIT);
// Disable color rendering, we only want to write to the Z-Buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// Render the objects of the scene
renderSinglePass(mDepthShader, worldToLightCameraMatrix);
// Unbind the shader
mDepthShader.unbind();
mFBOShadowMap.unbind();
glDisable(GL_POLYGON_OFFSET_FILL);
}
// ---------- Render the scene for final rendering (second pass) ----------- //
glCullFace(GL_BACK);
// Get the world-space to camera-space matrix
const openglframework::Matrix4 worldToCameraMatrix = mCamera.getTransformMatrix().getInverse();
mPhongShader.bind();
if (mIsShadowMappingEnabled) mShadowMapTexture.bind();
const GLuint textureUnit = 0;
// Set the variables of the phong shader
mPhongShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix());
mPhongShader.setMatrix4x4Uniform("shadowMapProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix);
mPhongShader.setMatrix4x4Uniform("worldToLight0CameraMatrix", worldToLightCameraMatrix);
mPhongShader.setVector3Uniform("light0PosCameraSpace", worldToCameraMatrix * mLight0.getOrigin());
mPhongShader.setVector3Uniform("lightAmbientColor", Vector3(0.4f, 0.4f, 0.4f));
mPhongShader.setVector3Uniform("light0DiffuseColor", Vector3(diffCol.r, diffCol.g, diffCol.b));
mPhongShader.setIntUniform("shadowMapSampler", textureUnit);
mPhongShader.setIntUniform("isShadowEnabled", mIsShadowMappingEnabled);
mPhongShader.setVector2Uniform("shadowMapDimension", Vector2(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT));
mPhongShader.unbind();
// Set the variables of the color shader
mColorShader.bind();
mColorShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix());
mColorShader.unbind();
// Set the viewport to render the scene
glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight);
//Enabling color write (previously disabled for light POV z-buffer rendering)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Clear previous frame values
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render the objects of the scene
renderSinglePass(mPhongShader, worldToCameraMatrix);
// Render the contact points
if (mIsContactPointsDisplayed) {
renderContactPoints(mPhongShader, worldToCameraMatrix);
}
// Render the AABBs
if (mIsAABBsDisplayed) {
renderAABBs(worldToCameraMatrix);
}
if (mIsShadowMappingEnabled) mShadowMapTexture.unbind();
mPhongShader.unbind();
//drawTextureQuad();
}
// Render the scene in a single pass
void SceneDemo::renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) {
if (mIsWireframeEnabled) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
// Bind the shader
shader.bind();
// Render all the physics objects of the scene
for (std::vector<PhysicsObject*>::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) {
(*it)->render(mIsWireframeEnabled ? mColorShader : shader, worldToCameraMatrix);
}
// Unbind the shader
shader.unbind();
if (mIsWireframeEnabled) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
// Create the Shadow map FBO and texture
void SceneDemo::createShadowMapFBOAndTexture() {
// Create the texture for the depth values
mShadowMapTexture.create(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
GL_UNSIGNED_BYTE, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, NULL);
// Create the FBO for the shadow map
mFBOShadowMap.create(0, 0, false);
mFBOShadowMap.bind();
// Tell OpenGL that we won't bind a color texture with the currently binded FBO
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
mFBOShadowMap.attachTexture(GL_DEPTH_ATTACHMENT, mShadowMapTexture.getID());
mFBOShadowMap.unbind();
mIsShadowMappingInitialized = true;
}
// Used for debugging shadow maps
void SceneDemo::createQuadVBO() {
mVAOQuad.create();
mVAOQuad.bind();
static const GLfloat quadVertexData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
mVBOQuad.create();
mVBOQuad.bind();
mVBOQuad.copyDataIntoVBO(sizeof(quadVertexData), quadVertexData, GL_STATIC_DRAW);
mVBOQuad.unbind();
mVAOQuad.unbind();
}
void SceneDemo::drawTextureQuad() {
glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Clear previous frame values
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const GLuint textureUnit = 0;
mVAOQuad.bind();
mQuadShader.bind();
mShadowMapTexture.bind();
mQuadShader.setIntUniform("textureSampler", textureUnit);
mVBOQuad.bind();
GLint vertexPositionLoc = mQuadShader.getAttribLocation("vertexPosition");
glEnableVertexAttribArray(vertexPositionLoc);
glVertexAttribPointer(
vertexPositionLoc, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
glDisableVertexAttribArray(vertexPositionLoc);
mVBOQuad.unbind();
mShadowMapTexture.unbind();
mQuadShader.unbind();
mVAOQuad.unbind();
}
// Gather and create contact points
void SceneDemo::updateContactPoints() {
// Remove the previous contact points
removeAllContactPoints();
if (mIsContactPointsDisplayed) {
// Get the current contact points of the scene
std::vector<ContactPoint> contactPoints = getContactPoints();
// For each contact point
std::vector<ContactPoint>::const_iterator it;
for (it = contactPoints.begin(); it != contactPoints.end(); ++it) {
// Create a visual contact point for rendering
VisualContactPoint* point = new VisualContactPoint(it->point, mMeshFolderPath, it->point + it->normal, it->color);
mContactPoints.push_back(point);
}
}
}
// Render the contact points
void SceneDemo::renderContactPoints(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) {
// Render all the contact points
for (std::vector<VisualContactPoint*>::iterator it = mContactPoints.begin();
it != mContactPoints.end(); ++it) {
(*it)->render(mColorShader, worldToCameraMatrix);
}
}
// Render the AABBs
void SceneDemo::renderAABBs(const openglframework::Matrix4& worldToCameraMatrix) {
// For each physics object of the scene
for (std::vector<PhysicsObject*>::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) {
// For each proxy shape of the object
rp3d::ProxyShape* proxyShape = (*it)->getCollisionBody()->getProxyShapesList();
while (proxyShape != nullptr) {
// Get the broad-phase AABB corresponding to the proxy shape
rp3d::AABB aabb = mPhysicsWorld->getWorldAABB(proxyShape);
openglframework::Vector3 aabbCenter(aabb.getCenter().x, aabb.getCenter().y, aabb.getCenter().z);
openglframework::Vector3 aabbMin(aabb.getMin().x, aabb.getMin().y, aabb.getMin().z);
openglframework::Vector3 aabbMax(aabb.getMax().x, aabb.getMax().y, aabb.getMax().z);
// Render the AABB
AABB::render(aabbCenter, aabbMax - aabbMin, Color::green(), mColorShader, worldToCameraMatrix);
proxyShape = proxyShape->getNext();
}
}
}
void SceneDemo::removeAllContactPoints() {
// Destroy all the visual contact points
for (std::vector<VisualContactPoint*>::iterator it = mContactPoints.begin();
it != mContactPoints.end(); ++it) {
delete (*it);
}
mContactPoints.clear();
}
// Return all the contact points of the scene
std::vector<ContactPoint> SceneDemo::computeContactPointsOfWorld(rp3d::DynamicsWorld* world) {
std::vector<ContactPoint> contactPoints;
// Get the list of contact manifolds from the world
rp3d::List<const rp3d::ContactManifold*> manifolds = world->getContactsList();
// For each contact manifold
rp3d::List<const rp3d::ContactManifold*>::Iterator it;
for (it = manifolds.begin(); it != manifolds.end(); ++it) {
const rp3d::ContactManifold* manifold = *it;
// For each contact point of the manifold
rp3d::ContactPoint* contactPoint = manifold->getContactPoints();
while (contactPoint != nullptr) {
rp3d::Vector3 point = manifold->getShape1()->getLocalToWorldTransform() * contactPoint->getLocalPointOnShape1();
rp3d::Vector3 normalWorld = contactPoint->getNormal();
openglframework::Vector3 normal = openglframework::Vector3(normalWorld.x, normalWorld.y, normalWorld.z);
ContactPoint contact(openglframework::Vector3(point.x, point.y, point.z), normal, openglframework::Color::red());
contactPoints.push_back(contact);
contactPoint = contactPoint->getNext();
}
}
return contactPoints;
}
// Update the engine settings
void SceneDemo::updateEngineSettings() {
if (getDynamicsWorld() != nullptr) {
// Update the physics engine parameters
getDynamicsWorld()->setIsGratityEnabled(mEngineSettings.isGravityEnabled);
rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y,
mEngineSettings.gravity.z);
getDynamicsWorld()->setGravity(gravity);
getDynamicsWorld()->enableSleeping(mEngineSettings.isSleepingEnabled);
getDynamicsWorld()->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity);
getDynamicsWorld()->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity);
getDynamicsWorld()->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations);
getDynamicsWorld()->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations);
getDynamicsWorld()->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep);
}
}
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "SceneDemo.h"
#include <GLFW/glfw3.h>
#include "AABB.h"
#include "constraint/ContactPoint.h"
#include "collision/ContactManifold.h"
using namespace openglframework;
int SceneDemo::shadowMapTextureLevel = 0;
openglframework::Color SceneDemo::mObjectColorDemo = Color(0.76f, 0.67f, 0.47f, 1.0f);
openglframework::Color SceneDemo::mFloorColorDemo = Color(0.47f, 0.48f, 0.49f, 1.0f);
openglframework::Color SceneDemo::mSleepingColorDemo = Color(1.0f, 0.25f, 0.25f, 1.0f);
openglframework::Color SceneDemo::mSelectedObjectColorDemo = Color(0.09f, 0.59f, 0.88f, 1.0f);
// Constructor
SceneDemo::SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled)
: Scene(name, settings, isShadowMappingEnabled), mIsShadowMappingInitialized(false),
mDepthShader("shaders/depth.vert", "shaders/depth.frag"),
mPhongShader("shaders/phong.vert", "shaders/phong.frag"),
mColorShader("shaders/color.vert", "shaders/color.frag"),
mQuadShader("shaders/quad.vert", "shaders/quad.frag"),
mVBOQuad(GL_ARRAY_BUFFER), mMeshFolderPath("meshes/"),
mPhysicsWorld(nullptr) {
shadowMapTextureLevel++;
// Move the lights
float lightsRadius = 30.0f;
float lightsHeight = 20.0f;
mLight0.translateWorld(Vector3(0 * lightsRadius, lightsHeight, 1 * lightsRadius));
mLight1.translateWorld(Vector3(0.95f * lightsRadius, lightsHeight, -0.3f * lightsRadius));
mLight2.translateWorld(Vector3(-0.58f * lightsRadius, lightsHeight, -0.81f * lightsRadius));
// Set the lights colors
mLight0.setDiffuseColor(Color(0.6f, 0.6f, 0.6f, 1.0f));
mLight1.setDiffuseColor(Color(0.6f, 0.6f, 0.6f, 1.0f));
mLight2.setDiffuseColor(Color(0.6f, 0.6f, 0.6f, 1.0f));
mShadowMapLightCameras[0].translateWorld(mLight0.getOrigin());
mShadowMapLightCameras[0].rotateLocal(Vector3(1, 0, 0), -PI / 4.0f);
mShadowMapLightCameras[1].translateWorld(mLight1.getOrigin());
mShadowMapLightCameras[1].rotateLocal(Vector3(0, 1, 0), -5.0f * PI/3.7f);
mShadowMapLightCameras[1].rotateLocal(Vector3(1, 0, 0), -PI/4.0f);
mShadowMapLightCameras[2].translateWorld(mLight2.getOrigin());
mShadowMapLightCameras[2].rotateLocal(Vector3(0, 1, 0), 5 * PI/4.0f);
mShadowMapLightCameras[2].rotateLocal(Vector3(1, 0 , 0), -PI/4.0f);
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
mShadowMapLightCameras[i].setDimensions(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT);
mShadowMapLightCameras[i].setFieldOfView(100.0f);
mShadowMapLightCameras[i].setSceneRadius(100);
}
mShadowMapBiasMatrix.setAllValues(0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0);
// Create the Shadow map FBO and texture
if (mIsShadowMappingEnabled) {
createShadowMapFBOAndTexture();
}
createQuadVBO();
// Init rendering for the AABBs
AABB::init();
VisualContactPoint::createStaticData(mMeshFolderPath);
}
// Destructor
SceneDemo::~SceneDemo() {
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
mShadowMapTexture[i].destroy();
mFBOShadowMap[i].destroy();
}
mVBOQuad.destroy();
mDepthShader.destroy();
mPhongShader.destroy();
mQuadShader.destroy();
mColorShader.destroy();
// Destroy the contact points
removeAllContactPoints();
// Destroy rendering data for the AABB
AABB::destroy();
VisualContactPoint::destroyStaticData();
}
// Update the scene
void SceneDemo::update() {
// Update the contact points
updateContactPoints();
// Update the position and orientation of the physics objects
for (std::vector<PhysicsObject*>::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) {
// Update the transform used for the rendering
(*it)->updateTransform(mInterpolationFactor);
}
}
// Update the physics world (take a simulation step)
// Can be called several times per frame
void SceneDemo::updatePhysics() {
if (getDynamicsWorld() != nullptr) {
// Take a simulation step
getDynamicsWorld()->update(mEngineSettings.timeStep);
}
}
// Render the scene (in multiple passes for shadow mapping)
void SceneDemo::render() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
Matrix4 shadowMapProjMatrix[NB_SHADOW_MAPS];
openglframework::Matrix4 worldToLightCameraMatrix[NB_SHADOW_MAPS];
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
shadowMapProjMatrix[i] = mShadowMapLightCameras[i].getProjectionMatrix();
worldToLightCameraMatrix[i] = mShadowMapLightCameras[i].getTransformMatrix().getInverse();
}
// ---------- Render the scene to generate the shadow map (first pass) ----------- //
// If Shadow Mapping is enabled
if (mIsShadowMappingEnabled) {
// Culling switching, rendering only backface, this is done to avoid self-shadowing
glCullFace(GL_BACK);
// For each shadow map
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
mFBOShadowMap[i].bind();
// Bind the shader
mDepthShader.bind();
// Set the variables of the shader
mDepthShader.setMatrix4x4Uniform("projectionMatrix", shadowMapProjMatrix[i]);
// Set the viewport to render into the shadow map texture
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT);
// Clear previous frame values
glClear(GL_DEPTH_BUFFER_BIT);
// Disable color rendering, we only want to write to the Z-Buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// Render the objects of the scene
renderSinglePass(mDepthShader, worldToLightCameraMatrix[i]);
// Unbind the shader
mDepthShader.unbind();
mFBOShadowMap[i].unbind();
}
glDisable(GL_POLYGON_OFFSET_FILL);
}
// ---------- Render the scene for final rendering (second pass) ----------- //
glCullFace(GL_BACK);
// Get the world-space to camera-space matrix
const openglframework::Matrix4 worldToCameraMatrix = mCamera.getTransformMatrix().getInverse();
mPhongShader.bind();
// Is shadow mapping is enabled
GLint textureUnits[NB_SHADOW_MAPS];
if (mIsShadowMappingEnabled) {
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
mShadowMapTexture[i].bind();
}
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
textureUnits[i] = mShadowMapTexture[i].getUnit();
}
}
// Set the variables of the phong shader
mPhongShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix());
mPhongShader.setMatrix4x4Uniform("shadowMapLight0ProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix[0]);
mPhongShader.setMatrix4x4Uniform("shadowMapLight1ProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix[1]);
mPhongShader.setMatrix4x4Uniform("shadowMapLight2ProjectionMatrix", mShadowMapBiasMatrix * shadowMapProjMatrix[2]);
mPhongShader.setMatrix4x4Uniform("worldToLight0CameraMatrix", worldToLightCameraMatrix[0]);
mPhongShader.setMatrix4x4Uniform("worldToLight1CameraMatrix", worldToLightCameraMatrix[1]);
mPhongShader.setMatrix4x4Uniform("worldToLight2CameraMatrix", worldToLightCameraMatrix[2]);
mPhongShader.setVector3Uniform("light0PosCameraSpace", worldToCameraMatrix * mLight0.getOrigin());
mPhongShader.setVector3Uniform("light1PosCameraSpace", worldToCameraMatrix * mLight1.getOrigin());
mPhongShader.setVector3Uniform("light2PosCameraSpace", worldToCameraMatrix * mLight2.getOrigin());
mPhongShader.setVector3Uniform("lightAmbientColor", Vector3(0.3f, 0.3f, 0.3f));
mPhongShader.setVector3Uniform("light0DiffuseColor", Vector3(mLight0.getDiffuseColor().r, mLight0.getDiffuseColor().g, mLight0.getDiffuseColor().b));
mPhongShader.setVector3Uniform("light1DiffuseColor", Vector3(mLight1.getDiffuseColor().r, mLight1.getDiffuseColor().g, mLight1.getDiffuseColor().b));
mPhongShader.setVector3Uniform("light2DiffuseColor", Vector3(mLight2.getDiffuseColor().r, mLight2.getDiffuseColor().g, mLight2.getDiffuseColor().b));
mPhongShader.setIntArrayUniform("shadowMapSampler", textureUnits, NB_SHADOW_MAPS);
mPhongShader.setIntUniform("isShadowEnabled", mIsShadowMappingEnabled);
mPhongShader.setVector2Uniform("shadowMapDimension", Vector2(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT));
mPhongShader.unbind();
// Set the variables of the color shader
mColorShader.bind();
mColorShader.setMatrix4x4Uniform("projectionMatrix", mCamera.getProjectionMatrix());
mColorShader.unbind();
// Set the viewport to render the scene
glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight);
//Enabling color write (previously disabled for light POV z-buffer rendering)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Clear previous frame values
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render the objects of the scene
renderSinglePass(mPhongShader, worldToCameraMatrix);
// Render the contact points
if (mIsContactPointsDisplayed) {
renderContactPoints(mPhongShader, worldToCameraMatrix);
}
// Render the AABBs
if (mIsAABBsDisplayed) {
renderAABBs(worldToCameraMatrix);
}
// Is shadow mapping is enabled
if (mIsShadowMappingEnabled) {
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
mShadowMapTexture[i].unbind();
}
}
mPhongShader.unbind();
//drawTextureQuad();
}
// Render the scene in a single pass
void SceneDemo::renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) {
if (mIsWireframeEnabled) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
// Bind the shader
shader.bind();
// Render all the physics objects of the scene
for (std::vector<PhysicsObject*>::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) {
(*it)->render(mIsWireframeEnabled ? mColorShader : shader, worldToCameraMatrix);
}
// Unbind the shader
shader.unbind();
if (mIsWireframeEnabled) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
// Create the Shadow map FBO and texture
void SceneDemo::createShadowMapFBOAndTexture() {
// For each shadow map
for (int i = 0; i < NB_SHADOW_MAPS; i++) {
// Create the texture for the depth values
mShadowMapTexture[i].create(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
GL_UNSIGNED_BYTE, GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER, NULL);
mShadowMapTexture[i].setUnit(i);
// Make sure that texture lookups outside the texture coords range will not
// treated as beeing in shadow
glBindTexture(GL_TEXTURE_2D, mShadowMapTexture[i].getID());
GLfloat border[] = { 1.0f, 0.0f, 0.0f, 0.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
glBindTexture(GL_TEXTURE_2D, 0);
// Create the FBO for the shadow map
mFBOShadowMap[i].create(0, 0, false);
mFBOShadowMap[i].bind();
// Tell OpenGL that we won't bind a color texture with the currently binded FBO
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
mFBOShadowMap[i].attachTexture(GL_DEPTH_ATTACHMENT, mShadowMapTexture[i].getID());
mFBOShadowMap[i].unbind();
}
mIsShadowMappingInitialized = true;
}
// Used for debugging shadow maps
void SceneDemo::createQuadVBO() {
mVAOQuad.create();
mVAOQuad.bind();
static const GLfloat quadVertexData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
mVBOQuad.create();
mVBOQuad.bind();
mVBOQuad.copyDataIntoVBO(sizeof(quadVertexData), quadVertexData, GL_STATIC_DRAW);
mVBOQuad.unbind();
mVAOQuad.unbind();
}
void SceneDemo::drawTextureQuad() {
glViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Clear previous frame values
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const int SHADOW_MAP_TEXTURE_TO_DRAW = 0;
const GLuint textureUnit = SHADOW_MAP_TEXTURE_TO_DRAW;
mVAOQuad.bind();
mQuadShader.bind();
mShadowMapTexture[SHADOW_MAP_TEXTURE_TO_DRAW].bind();
mQuadShader.setIntUniform("textureSampler", textureUnit);
mVBOQuad.bind();
GLint vertexPositionLoc = mQuadShader.getAttribLocation("vertexPosition");
glEnableVertexAttribArray(vertexPositionLoc);
glVertexAttribPointer(
vertexPositionLoc, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
glDisableVertexAttribArray(vertexPositionLoc);
mVBOQuad.unbind();
mShadowMapTexture[SHADOW_MAP_TEXTURE_TO_DRAW].unbind();
mQuadShader.unbind();
mVAOQuad.unbind();
}
// Gather and create contact points
void SceneDemo::updateContactPoints() {
// Remove the previous contact points
removeAllContactPoints();
if (mIsContactPointsDisplayed) {
// Get the current contact points of the scene
std::vector<ContactPoint> contactPoints = getContactPoints();
// For each contact point
std::vector<ContactPoint>::const_iterator it;
for (it = contactPoints.begin(); it != contactPoints.end(); ++it) {
// Create a visual contact point for rendering
VisualContactPoint* point = new VisualContactPoint(it->point, mMeshFolderPath, it->point + it->normal, it->color);
mContactPoints.push_back(point);
}
}
}
// Render the contact points
void SceneDemo::renderContactPoints(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix) {
// Render all the contact points
for (std::vector<VisualContactPoint*>::iterator it = mContactPoints.begin();
it != mContactPoints.end(); ++it) {
(*it)->render(mColorShader, worldToCameraMatrix);
}
}
// Render the AABBs
void SceneDemo::renderAABBs(const openglframework::Matrix4& worldToCameraMatrix) {
// For each physics object of the scene
for (std::vector<PhysicsObject*>::iterator it = mPhysicsObjects.begin(); it != mPhysicsObjects.end(); ++it) {
// For each proxy shape of the object
rp3d::ProxyShape* proxyShape = (*it)->getCollisionBody()->getProxyShapesList();
while (proxyShape != nullptr) {
// Get the broad-phase AABB corresponding to the proxy shape
rp3d::AABB aabb = mPhysicsWorld->getWorldAABB(proxyShape);
openglframework::Vector3 aabbCenter(aabb.getCenter().x, aabb.getCenter().y, aabb.getCenter().z);
openglframework::Vector3 aabbMin(aabb.getMin().x, aabb.getMin().y, aabb.getMin().z);
openglframework::Vector3 aabbMax(aabb.getMax().x, aabb.getMax().y, aabb.getMax().z);
// Render the AABB
AABB::render(aabbCenter, aabbMax - aabbMin, Color::green(), mColorShader, worldToCameraMatrix);
proxyShape = proxyShape->getNext();
}
}
}
void SceneDemo::removeAllContactPoints() {
// Destroy all the visual contact points
for (std::vector<VisualContactPoint*>::iterator it = mContactPoints.begin();
it != mContactPoints.end(); ++it) {
delete (*it);
}
mContactPoints.clear();
}
// Return all the contact points of the scene
std::vector<ContactPoint> SceneDemo::computeContactPointsOfWorld(rp3d::DynamicsWorld* world) {
std::vector<ContactPoint> contactPoints;
// Get the list of contact manifolds from the world
rp3d::List<const rp3d::ContactManifold*> manifolds = world->getContactsList();
// For each contact manifold
rp3d::List<const rp3d::ContactManifold*>::Iterator it;
for (it = manifolds.begin(); it != manifolds.end(); ++it) {
const rp3d::ContactManifold* manifold = *it;
// For each contact point of the manifold
rp3d::ContactPoint* contactPoint = manifold->getContactPoints();
while (contactPoint != nullptr) {
rp3d::Vector3 point = manifold->getShape1()->getLocalToWorldTransform() * contactPoint->getLocalPointOnShape1();
rp3d::Vector3 normalWorld = contactPoint->getNormal();
openglframework::Vector3 normal = openglframework::Vector3(normalWorld.x, normalWorld.y, normalWorld.z);
ContactPoint contact(openglframework::Vector3(point.x, point.y, point.z), normal, openglframework::Color::red());
contactPoints.push_back(contact);
contactPoint = contactPoint->getNext();
}
}
return contactPoints;
}
// Update the engine settings
void SceneDemo::updateEngineSettings() {
if (getDynamicsWorld() != nullptr) {
// Update the physics engine parameters
getDynamicsWorld()->setIsGratityEnabled(mEngineSettings.isGravityEnabled);
rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y,
mEngineSettings.gravity.z);
getDynamicsWorld()->setGravity(gravity);
getDynamicsWorld()->enableSleeping(mEngineSettings.isSleepingEnabled);
getDynamicsWorld()->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity);
getDynamicsWorld()->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity);
getDynamicsWorld()->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations);
getDynamicsWorld()->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations);
getDynamicsWorld()->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep);
}
}

View File

@ -1,189 +1,195 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 SCENEDEMO_H
#define SCENEDEMO_H
// Libraries
#include "Scene.h"
#include "VisualContactPoint.h"
#include "reactphysics3d.h"
#include "PhysicsObject.h"
// Constants
const int SHADOWMAP_WIDTH = 2048;
const int SHADOWMAP_HEIGHT = 2048;
// Class SceneDemo
// Abstract class that represents a 3D scene for the ReactPhysics3D examples.
// This scene has a single light source with shadow mapping.
class SceneDemo : public Scene {
protected:
// -------------------- Attributes -------------------- //
/// Light 0
openglframework::Light mLight0;
/// True if the shadows FBO, textures have been created
bool mIsShadowMappingInitialized;
/// FBO for the shadow map
openglframework::FrameBufferObject mFBOShadowMap;
/// Shadow map texture
openglframework::Texture2D mShadowMapTexture;
static int shadowMapTextureLevel;
/// All the visual contact points
std::vector<VisualContactPoint*> mContactPoints;
/// Shadow map bias matrix
openglframework::Matrix4 mShadowMapBiasMatrix;
/// Camera at light0 position for the shadow map
openglframework::Camera mShadowMapLightCamera;
/// Depth shader to render the shadow map
openglframework::Shader mDepthShader;
/// Phong shader
openglframework::Shader mPhongShader;
/// Constant color shader
openglframework::Shader mColorShader;
// TODO : Delete this
openglframework::Shader mQuadShader;
// TODO : Delete this
openglframework::VertexArrayObject mVAOQuad;
openglframework::VertexBufferObject mVBOQuad;
static openglframework::Color mGreyColorDemo;
static openglframework::Color mYellowColorDemo;
static openglframework::Color mBlueColorDemo;
static openglframework::Color mOrangeColorDemo;
static openglframework::Color mPinkColorDemo;
static openglframework::Color mRedColorDemo;
static openglframework::Color mDemoColors[];
static int mNbDemoColors;
std::string mMeshFolderPath;
std::vector<PhysicsObject*> mPhysicsObjects;
rp3d::CollisionWorld* mPhysicsWorld;
// -------------------- Methods -------------------- //
// Create the Shadow map FBO and texture
void createShadowMapFBOAndTexture();
// Used for debugging shadow maps
void createQuadVBO();
// TODO : Delete this
void drawTextureQuad();
// Update the contact points
void updateContactPoints();
// Render the contact points
void renderContactPoints(openglframework::Shader& shader,
const openglframework::Matrix4& worldToCameraMatrix);
/// Render the AABBs
void renderAABBs(const openglframework::Matrix4& worldToCameraMatrix);
/// Remove all contact points
void removeAllContactPoints();
/// Return a reference to the dynamics world
rp3d::DynamicsWorld* getDynamicsWorld();
/// Return a reference to the dynamics world
const rp3d::DynamicsWorld* getDynamicsWorld() const;
public:
// -------------------- Methods -------------------- //
/// Constructor
SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled = true);
/// Destructor
virtual ~SceneDemo() override;
/// Update the scene
virtual void update() override;
/// Update the physics world (take a simulation step)
/// Can be called several times per frame
virtual void updatePhysics() override;
/// Render the scene (possibly in multiple passes for shadow mapping)
virtual void render() override;
/// Update the engine settings
virtual void updateEngineSettings() override;
/// Render the scene in a single pass
virtual void renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix);
/// Enabled/Disable the shadow mapping
virtual void setIsShadowMappingEnabled(bool isShadowMappingEnabled) override;
/// Return all the contact points of the scene
std::vector<ContactPoint> computeContactPointsOfWorld(reactphysics3d::DynamicsWorld *world);
};
// Enabled/Disable the shadow mapping
inline void SceneDemo::setIsShadowMappingEnabled(bool isShadowMappingEnabled) {
Scene::setIsShadowMappingEnabled(isShadowMappingEnabled);
if (mIsShadowMappingEnabled && !mIsShadowMappingInitialized) {
createShadowMapFBOAndTexture();
}
}
// Return a reference to the dynamics world
inline rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() {
return dynamic_cast<rp3d::DynamicsWorld*>(mPhysicsWorld);
}
// Return a reference to the dynamics world
inline const rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() const {
return dynamic_cast<rp3d::DynamicsWorld*>(mPhysicsWorld);
}
#endif
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 SCENEDEMO_H
#define SCENEDEMO_H
// Libraries
#include "Scene.h"
#include "VisualContactPoint.h"
#include "reactphysics3d.h"
#include "PhysicsObject.h"
// Constants
const int SHADOWMAP_WIDTH = 2048;
const int SHADOWMAP_HEIGHT = 2048;
// Class SceneDemo
// Abstract class that represents a 3D scene for the ReactPhysics3D examples.
// This scene has a single light source with shadow mapping.
class SceneDemo : public Scene {
protected:
// -------------------- Constants -------------------- //
static constexpr int NB_SHADOW_MAPS = 3;
// -------------------- Attributes -------------------- //
/// Light 0
openglframework::Light mLight0;
/// Light 1
openglframework::Light mLight1;
/// Light 2
openglframework::Light mLight2;
/// True if the shadows FBO, textures have been created
bool mIsShadowMappingInitialized;
/// Array of FBO for the shadow maps
openglframework::FrameBufferObject mFBOShadowMap[NB_SHADOW_MAPS];
/// Shadow map texture
openglframework::Texture2D mShadowMapTexture[NB_SHADOW_MAPS];
static int shadowMapTextureLevel;
/// All the visual contact points
std::vector<VisualContactPoint*> mContactPoints;
/// Shadow map bias matrix
openglframework::Matrix4 mShadowMapBiasMatrix;
/// Cameras at lights position for the shadow maps
openglframework::Camera mShadowMapLightCameras[NB_SHADOW_MAPS];
/// Depth shader to render the shadow map
openglframework::Shader mDepthShader;
/// Phong shader
openglframework::Shader mPhongShader;
/// Constant color shader
openglframework::Shader mColorShader;
// TODO : Delete this
openglframework::Shader mQuadShader;
// TODO : Delete this
openglframework::VertexArrayObject mVAOQuad;
openglframework::VertexBufferObject mVBOQuad;
static openglframework::Color mObjectColorDemo;
static openglframework::Color mFloorColorDemo;
static openglframework::Color mSleepingColorDemo;
static openglframework::Color mSelectedObjectColorDemo;
std::string mMeshFolderPath;
std::vector<PhysicsObject*> mPhysicsObjects;
rp3d::CollisionWorld* mPhysicsWorld;
// -------------------- Methods -------------------- //
// Create the Shadow map FBO and texture
void createShadowMapFBOAndTexture();
// Used for debugging shadow maps
void createQuadVBO();
// TODO : Delete this
void drawTextureQuad();
// Update the contact points
void updateContactPoints();
// Render the contact points
void renderContactPoints(openglframework::Shader& shader,
const openglframework::Matrix4& worldToCameraMatrix);
/// Render the AABBs
void renderAABBs(const openglframework::Matrix4& worldToCameraMatrix);
/// Remove all contact points
void removeAllContactPoints();
/// Return a reference to the dynamics world
rp3d::DynamicsWorld* getDynamicsWorld();
/// Return a reference to the dynamics world
const rp3d::DynamicsWorld* getDynamicsWorld() const;
public:
// -------------------- Methods -------------------- //
/// Constructor
SceneDemo(const std::string& name, EngineSettings& settings, float sceneRadius, bool isShadowMappingEnabled = true);
/// Destructor
virtual ~SceneDemo() override;
/// Update the scene
virtual void update() override;
/// Update the physics world (take a simulation step)
/// Can be called several times per frame
virtual void updatePhysics() override;
/// Render the scene (possibly in multiple passes for shadow mapping)
virtual void render() override;
/// Update the engine settings
virtual void updateEngineSettings() override;
/// Render the scene in a single pass
virtual void renderSinglePass(openglframework::Shader& shader, const openglframework::Matrix4& worldToCameraMatrix);
/// Enabled/Disable the shadow mapping
virtual void setIsShadowMappingEnabled(bool isShadowMappingEnabled) override;
/// Return all the contact points of the scene
std::vector<ContactPoint> computeContactPointsOfWorld(reactphysics3d::DynamicsWorld *world);
};
// Enabled/Disable the shadow mapping
inline void SceneDemo::setIsShadowMappingEnabled(bool isShadowMappingEnabled) {
Scene::setIsShadowMappingEnabled(isShadowMappingEnabled);
if (mIsShadowMappingEnabled && !mIsShadowMappingInitialized) {
createShadowMapFBOAndTexture();
}
}
// Return a reference to the dynamics world
inline rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() {
return dynamic_cast<rp3d::DynamicsWorld*>(mPhysicsWorld);
}
// Return a reference to the dynamics world
inline const rp3d::DynamicsWorld* SceneDemo::getDynamicsWorld() const {
return dynamic_cast<rp3d::DynamicsWorld*>(mPhysicsWorld);
}
#endif

View File

@ -1,393 +1,393 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "TestbedApplication.h"
#include "openglframework.h"
#include <iostream>
#include <cstdlib>
#include <sstream>
#include "cubes/CubesScene.h"
#include "collisiondetection/CollisionDetectionScene.h"
#include "joints/JointsScene.h"
#include "collisionshapes/CollisionShapesScene.h"
#include "heightfield/HeightFieldScene.h"
#include "raycast/RaycastScene.h"
#include "concavemesh/ConcaveMeshScene.h"
#include "cubestack/CubeStackScene.h"
using namespace openglframework;
using namespace jointsscene;
using namespace cubesscene;
using namespace raycastscene;
using namespace collisionshapesscene;
using namespace trianglemeshscene;
using namespace heightfieldscene;
using namespace collisiondetectionscene;
using namespace cubestackscene;
// Initialization of static variables
const float TestbedApplication::SCROLL_SENSITIVITY = 0.08f;
// Constructor
TestbedApplication::TestbedApplication(bool isFullscreen)
: Screen(Vector2i(1280, 800), "Testbed ReactPhysics3D", true, isFullscreen, 8, 8, 24, 8, 8),
mIsInitialized(false), mGui(this), mCurrentScene(nullptr),
mEngineSettings(EngineSettings::defaultSettings()),
mFPS(0), mNbFrames(0), mPreviousTime(0),
mLastTimeComputedFPS(0), mFrameTime(0), mPhysicsTime(0),
mWidth(1280), mHeight(720),
mSinglePhysicsStepEnabled(false), mSinglePhysicsStepDone(false),
mWindowToFramebufferRatio(Vector2(1, 1)), mIsShadowMappingEnabled(true),
mIsContactPointsDisplayed(false), mIsAABBsDisplayed(false), mIsWireframeEnabled(false),
mIsVSyncEnabled(true) {
init();
resizeEvent(Vector2i(0, 0));
}
// Destructor
TestbedApplication::~TestbedApplication() {
// Destroy all the scenes
destroyScenes();
}
// Initialize the viewer
void TestbedApplication::init() {
// Create all the scenes
createScenes();
// Initialize the GUI
mGui.init();
mTimer.start();
mIsInitialized = true;
}
// Create all the scenes
void TestbedApplication::createScenes() {
// Cubes scene
CubesScene* cubeScene = new CubesScene("Cubes", mEngineSettings);
mScenes.push_back(cubeScene);
// Cube Stack scene
CubeStackScene* cubeStackScene = new CubeStackScene("Cube Stack", mEngineSettings);
mScenes.push_back(cubeStackScene);
// Joints scene
JointsScene* jointsScene = new JointsScene("Joints", mEngineSettings);
mScenes.push_back(jointsScene);
// Collision shapes scene
CollisionShapesScene* collisionShapesScene = new CollisionShapesScene("Collision Shapes", mEngineSettings);
mScenes.push_back(collisionShapesScene);
// Heightfield shape scene
HeightFieldScene* heightFieldScene = new HeightFieldScene("Heightfield", mEngineSettings);
mScenes.push_back(heightFieldScene);
// Raycast scene
RaycastScene* raycastScene = new RaycastScene("Raycast", mEngineSettings);
mScenes.push_back(raycastScene);
// Collision Detection scene
CollisionDetectionScene* collisionDetectionScene = new CollisionDetectionScene("Collision Detection", mEngineSettings);
mScenes.push_back(collisionDetectionScene);
// Concave Mesh scene
ConcaveMeshScene* concaveMeshScene = new ConcaveMeshScene("Concave Mesh", mEngineSettings);
mScenes.push_back(concaveMeshScene);
assert(mScenes.size() > 0);
const int firstSceneIndex = 0;
switchScene(mScenes[firstSceneIndex]);
}
// Remove all the scenes
void TestbedApplication::destroyScenes() {
for (uint i=0; i<mScenes.size(); i++) {
delete mScenes[i];
}
mCurrentScene = NULL;
}
void TestbedApplication::updateSinglePhysicsStep() {
assert(!mTimer.isRunning());
mCurrentScene->updatePhysics();
}
// Update the physics of the current scene
void TestbedApplication::updatePhysics() {
// Update the elapsed time
mEngineSettings.elapsedTime = mTimer.getPhysicsTime();
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(mEngineSettings.timeStep)) {
// Take a physics simulation step
mCurrentScene->updatePhysics();
// Update the timer
mTimer.nextStep(mEngineSettings.timeStep);
}
}
}
void TestbedApplication::update() {
double currentTime = glfwGetTime();
// Update the physics
if (mSinglePhysicsStepEnabled && !mSinglePhysicsStepDone) {
updateSinglePhysicsStep();
mSinglePhysicsStepDone = true;
}
else {
updatePhysics();
}
// Compute the physics update time
mPhysicsTime = glfwGetTime() - currentTime;
// 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);
// Enable/Disable shadow mapping
mCurrentScene->setIsShadowMappingEnabled(mIsShadowMappingEnabled);
// Display/Hide contact points
mCurrentScene->setIsContactPointsDisplayed(mIsContactPointsDisplayed);
// Display/Hide the AABBs
mCurrentScene->setIsAABBsDisplayed(mIsAABBsDisplayed);
// Enable/Disable wireframe mode
mCurrentScene->setIsWireframeEnabled(mIsWireframeEnabled);
// Update the scene
mCurrentScene->update();
}
void TestbedApplication::drawContents() {
update();
int bufferWidth, bufferHeight;
glfwMakeContextCurrent(mGLFWWindow);
glfwGetFramebufferSize(mGLFWWindow, &bufferWidth, &bufferHeight);
// Set the viewport of the scene
mCurrentScene->setViewport(0, 0, bufferWidth, bufferHeight);
// Render the scene
mCurrentScene->render();
// Check the OpenGL errors
checkOpenGLErrors();
mGui.update();
// Compute the current framerate
computeFPS();
}
/// Window resize event handler
bool TestbedApplication::resizeEvent(const Vector2i& size) {
if (!mIsInitialized) return false;
// Get the framebuffer dimension
int width, height;
glfwGetFramebufferSize(mGLFWWindow, &width, &height);
// Resize the camera viewport
mCurrentScene->reshape(width, height);
// Update the window size of the scene
int windowWidth, windowHeight;
glfwGetWindowSize(mGLFWWindow, &windowWidth, &windowHeight);
mCurrentScene->setWindowDimension(windowWidth, windowHeight);
return true;
}
// Change the current scene
void TestbedApplication::switchScene(Scene* newScene) {
if (newScene == mCurrentScene) return;
mCurrentScene = newScene;
// Reset the scene
mCurrentScene->reset();
mCurrentScene->updateEngineSettings();
resizeEvent(Vector2i(0, 0));
}
// Notify that the engine settings have changed
void TestbedApplication::notifyEngineSetttingsChanged() {
mCurrentScene->updateEngineSettings();
}
// Check the OpenGL errors
void TestbedApplication::checkOpenGLErrorsInternal(const char* file, int line) {
GLenum glError;
// Get the OpenGL errors
glError = glGetError();
// While there are errors
while (glError != GL_NO_ERROR) {
std::string error;
switch(glError) {
case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break;
case GL_INVALID_ENUM: error="INVALID_ENUM"; break;
case GL_INVALID_VALUE: error="INVALID_VALUE"; break;
case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break;
}
std::cerr << "OpenGL Error #" << error.c_str() << " - " << file << ": " << line << std::endl;
// Get the next error
glError = glGetError();
}
}
// Compute the FPS
void TestbedApplication::computeFPS() {
// Note : By default the nanogui library is using glfwWaitEvents() to process
// events and sleep to target a framerate of 50 ms (using a thread
// sleeping). However, for games we prefer to use glfwPollEvents()
// instead and remove the update. Therefore the file common.cpp of the
// nanogui library has been modified to have a faster framerate
mNbFrames++;
// Get the number of seconds since start
mCurrentTime = glfwGetTime();
// Calculate time passed
mFrameTime = mCurrentTime - mPreviousTime;
double timeInterval = (mCurrentTime - mLastTimeComputedFPS) * 1000.0;
// Update the FPS counter each second
if(timeInterval > 1000) {
// calculate the number of frames per second
mFPS = static_cast<double>(mNbFrames) / timeInterval;
mFPS *= 1000.0;
// Reset frame count
mNbFrames = 0;
mLastTimeComputedFPS = mCurrentTime;
}
// Set time
mPreviousTime = mCurrentTime;
}
bool TestbedApplication::keyboardEvent(int key, int scancode, int action, int modifiers) {
if (Screen::keyboardEvent(key, scancode, action, modifiers)) {
return true;
}
// Close application on escape key
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(mGLFWWindow, GL_TRUE);
return true;
}
return mCurrentScene->keyboardEvent(key, scancode, action, modifiers);
}
// Handle a mouse button event (default implementation: propagate to children)
bool TestbedApplication::mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) {
if (Screen::mouseButtonEvent(p, button, down, modifiers)) {
return true;
}
// Get the mouse cursor position
double x, y;
glfwGetCursorPos(mGLFWWindow, &x, &y);
return mCurrentScene->mouseButtonEvent(button, down, modifiers, x, y);
}
// Handle a mouse motion event (default implementation: propagate to children)
bool TestbedApplication::mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) {
if (Screen::mouseMotionEvent(p, rel, button, modifiers)) {
return true;
}
int leftButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_LEFT);
int rightButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_RIGHT);
int middleButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_MIDDLE);
int altKeyState = glfwGetKey(mGLFWWindow, GLFW_KEY_LEFT_ALT);
return mCurrentScene->mouseMotionEvent(p[0], p[1], leftButtonState, rightButtonState,
middleButtonState, altKeyState);
}
// Handle a mouse scroll event (default implementation: propagate to children)
bool TestbedApplication::scrollEvent(const Vector2i &p, const Vector2f &rel) {
if (Screen::scrollEvent(p, rel)) {
return true;
}
return mCurrentScene->scrollingEvent(rel[0], rel[1], SCROLL_SENSITIVITY);
}
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 "TestbedApplication.h"
#include "openglframework.h"
#include <iostream>
#include <cstdlib>
#include <sstream>
#include "cubes/CubesScene.h"
#include "collisiondetection/CollisionDetectionScene.h"
#include "joints/JointsScene.h"
#include "collisionshapes/CollisionShapesScene.h"
#include "heightfield/HeightFieldScene.h"
#include "raycast/RaycastScene.h"
#include "concavemesh/ConcaveMeshScene.h"
#include "cubestack/CubeStackScene.h"
using namespace openglframework;
using namespace jointsscene;
using namespace cubesscene;
using namespace raycastscene;
using namespace collisionshapesscene;
using namespace trianglemeshscene;
using namespace heightfieldscene;
using namespace collisiondetectionscene;
using namespace cubestackscene;
// Initialization of static variables
const float TestbedApplication::SCROLL_SENSITIVITY = 0.08f;
// Constructor
TestbedApplication::TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight)
: Screen(Vector2i(windowWidth, windowHeight), "Testbed ReactPhysics3D", true, isFullscreen, 8, 8, 24, 8, 8),
mIsInitialized(false), mGui(this), mCurrentScene(nullptr),
mEngineSettings(EngineSettings::defaultSettings()),
mFPS(0), mNbFrames(0), mPreviousTime(0),
mLastTimeComputedFPS(0), mFrameTime(0), mPhysicsTime(0),
mWidth(windowWidth), mHeight(windowHeight),
mSinglePhysicsStepEnabled(false), mSinglePhysicsStepDone(false),
mWindowToFramebufferRatio(Vector2(1, 1)), mIsShadowMappingEnabled(true),
mIsContactPointsDisplayed(false), mIsAABBsDisplayed(false), mIsWireframeEnabled(false),
mIsVSyncEnabled(true) {
init();
resizeEvent(Vector2i(0, 0));
}
// Destructor
TestbedApplication::~TestbedApplication() {
// Destroy all the scenes
destroyScenes();
}
// Initialize the viewer
void TestbedApplication::init() {
// Create all the scenes
createScenes();
// Initialize the GUI
mGui.init();
mTimer.start();
mIsInitialized = true;
}
// Create all the scenes
void TestbedApplication::createScenes() {
// Cubes scene
CubesScene* cubeScene = new CubesScene("Cubes", mEngineSettings);
mScenes.push_back(cubeScene);
// Cube Stack scene
CubeStackScene* cubeStackScene = new CubeStackScene("Cube Stack", mEngineSettings);
mScenes.push_back(cubeStackScene);
// Joints scene
JointsScene* jointsScene = new JointsScene("Joints", mEngineSettings);
mScenes.push_back(jointsScene);
// Collision shapes scene
CollisionShapesScene* collisionShapesScene = new CollisionShapesScene("Collision Shapes", mEngineSettings);
mScenes.push_back(collisionShapesScene);
// Heightfield shape scene
HeightFieldScene* heightFieldScene = new HeightFieldScene("Heightfield", mEngineSettings);
mScenes.push_back(heightFieldScene);
// Raycast scene
RaycastScene* raycastScene = new RaycastScene("Raycast", mEngineSettings);
mScenes.push_back(raycastScene);
// Collision Detection scene
CollisionDetectionScene* collisionDetectionScene = new CollisionDetectionScene("Collision Detection", mEngineSettings);
mScenes.push_back(collisionDetectionScene);
// Concave Mesh scene
ConcaveMeshScene* concaveMeshScene = new ConcaveMeshScene("Concave Mesh", mEngineSettings);
mScenes.push_back(concaveMeshScene);
assert(mScenes.size() > 0);
const int firstSceneIndex = 0;
switchScene(mScenes[firstSceneIndex]);
}
// Remove all the scenes
void TestbedApplication::destroyScenes() {
for (uint i=0; i<mScenes.size(); i++) {
delete mScenes[i];
}
mCurrentScene = NULL;
}
void TestbedApplication::updateSinglePhysicsStep() {
assert(!mTimer.isRunning());
mCurrentScene->updatePhysics();
}
// Update the physics of the current scene
void TestbedApplication::updatePhysics() {
// Update the elapsed time
mEngineSettings.elapsedTime = mTimer.getPhysicsTime();
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(mEngineSettings.timeStep)) {
// Take a physics simulation step
mCurrentScene->updatePhysics();
// Update the timer
mTimer.nextStep(mEngineSettings.timeStep);
}
}
}
void TestbedApplication::update() {
double currentTime = glfwGetTime();
// Update the physics
if (mSinglePhysicsStepEnabled && !mSinglePhysicsStepDone) {
updateSinglePhysicsStep();
mSinglePhysicsStepDone = true;
}
else {
updatePhysics();
}
// Compute the physics update time
mPhysicsTime = glfwGetTime() - currentTime;
// 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);
// Enable/Disable shadow mapping
mCurrentScene->setIsShadowMappingEnabled(mIsShadowMappingEnabled);
// Display/Hide contact points
mCurrentScene->setIsContactPointsDisplayed(mIsContactPointsDisplayed);
// Display/Hide the AABBs
mCurrentScene->setIsAABBsDisplayed(mIsAABBsDisplayed);
// Enable/Disable wireframe mode
mCurrentScene->setIsWireframeEnabled(mIsWireframeEnabled);
// Update the scene
mCurrentScene->update();
}
void TestbedApplication::drawContents() {
update();
int bufferWidth, bufferHeight;
glfwMakeContextCurrent(mGLFWWindow);
glfwGetFramebufferSize(mGLFWWindow, &bufferWidth, &bufferHeight);
// Set the viewport of the scene
mCurrentScene->setViewport(0, 0, bufferWidth, bufferHeight);
// Render the scene
mCurrentScene->render();
// Check the OpenGL errors
checkOpenGLErrors();
mGui.update();
// Compute the current framerate
computeFPS();
}
/// Window resize event handler
bool TestbedApplication::resizeEvent(const Vector2i& size) {
if (!mIsInitialized) return false;
// Get the framebuffer dimension
int width, height;
glfwGetFramebufferSize(mGLFWWindow, &width, &height);
// Resize the camera viewport
mCurrentScene->reshape(width, height);
// Update the window size of the scene
int windowWidth, windowHeight;
glfwGetWindowSize(mGLFWWindow, &windowWidth, &windowHeight);
mCurrentScene->setWindowDimension(windowWidth, windowHeight);
return true;
}
// Change the current scene
void TestbedApplication::switchScene(Scene* newScene) {
if (newScene == mCurrentScene) return;
mCurrentScene = newScene;
// Reset the scene
mCurrentScene->reset();
mCurrentScene->updateEngineSettings();
resizeEvent(Vector2i(0, 0));
}
// Notify that the engine settings have changed
void TestbedApplication::notifyEngineSetttingsChanged() {
mCurrentScene->updateEngineSettings();
}
// Check the OpenGL errors
void TestbedApplication::checkOpenGLErrorsInternal(const char* file, int line) {
GLenum glError;
// Get the OpenGL errors
glError = glGetError();
// While there are errors
while (glError != GL_NO_ERROR) {
std::string error;
switch(glError) {
case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break;
case GL_INVALID_ENUM: error="INVALID_ENUM"; break;
case GL_INVALID_VALUE: error="INVALID_VALUE"; break;
case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break;
}
std::cerr << "OpenGL Error #" << error.c_str() << " - " << file << ": " << line << std::endl;
// Get the next error
glError = glGetError();
}
}
// Compute the FPS
void TestbedApplication::computeFPS() {
// Note : By default the nanogui library is using glfwWaitEvents() to process
// events and sleep to target a framerate of 50 ms (using a thread
// sleeping). However, for games we prefer to use glfwPollEvents()
// instead and remove the update. Therefore the file common.cpp of the
// nanogui library has been modified to have a faster framerate
mNbFrames++;
// Get the number of seconds since start
mCurrentTime = glfwGetTime();
// Calculate time passed
mFrameTime = mCurrentTime - mPreviousTime;
double timeInterval = (mCurrentTime - mLastTimeComputedFPS) * 1000.0;
// Update the FPS counter each second
if(timeInterval > 1000) {
// calculate the number of frames per second
mFPS = static_cast<double>(mNbFrames) / timeInterval;
mFPS *= 1000.0;
// Reset frame count
mNbFrames = 0;
mLastTimeComputedFPS = mCurrentTime;
}
// Set time
mPreviousTime = mCurrentTime;
}
bool TestbedApplication::keyboardEvent(int key, int scancode, int action, int modifiers) {
if (Screen::keyboardEvent(key, scancode, action, modifiers)) {
return true;
}
// Close application on escape key
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(mGLFWWindow, GL_TRUE);
return true;
}
return mCurrentScene->keyboardEvent(key, scancode, action, modifiers);
}
// Handle a mouse button event (default implementation: propagate to children)
bool TestbedApplication::mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) {
if (Screen::mouseButtonEvent(p, button, down, modifiers)) {
return true;
}
// Get the mouse cursor position
double x, y;
glfwGetCursorPos(mGLFWWindow, &x, &y);
return mCurrentScene->mouseButtonEvent(button, down, modifiers, x, y);
}
// Handle a mouse motion event (default implementation: propagate to children)
bool TestbedApplication::mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) {
if (Screen::mouseMotionEvent(p, rel, button, modifiers)) {
return true;
}
int leftButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_LEFT);
int rightButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_RIGHT);
int middleButtonState = glfwGetMouseButton(mGLFWWindow, GLFW_MOUSE_BUTTON_MIDDLE);
int altKeyState = glfwGetKey(mGLFWWindow, GLFW_KEY_LEFT_ALT);
return mCurrentScene->mouseMotionEvent(p[0], p[1], leftButtonState, rightButtonState,
middleButtonState, altKeyState);
}
// Handle a mouse scroll event (default implementation: propagate to children)
bool TestbedApplication::scrollEvent(const Vector2i &p, const Vector2f &rel) {
if (Screen::scrollEvent(p, rel)) {
return true;
}
return mCurrentScene->scrollingEvent(rel[0], rel[1], SCROLL_SENSITIVITY);
}

View File

@ -1,260 +1,260 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 TESTBED_APPLICATION_H
#define TESTBED_APPLICATION_H
// Libraries
#include "openglframework.h"
#include "Gui.h"
#include "Scene.h"
#include "Timer.h"
#include <GLFW/glfw3.h>
using namespace nanogui;
// Macro for OpenGL errors
#define checkOpenGLErrors() checkOpenGLErrorsInternal(__FILE__,__LINE__)
/// Class TestbedApplication
class TestbedApplication : public Screen {
private :
// -------------------- Constants -------------------- //
static const float SCROLL_SENSITIVITY;
// -------------------- Attributes -------------------- //
bool mIsInitialized;
Gui mGui;
/// Timer
Timer mTimer;
/// List of 3D scenes
std::vector<Scene*> mScenes;
/// Current 3D scene
Scene* mCurrentScene;
/// Physics engine settings
EngineSettings mEngineSettings;
/// Current number of frames per seconds
double mFPS;
/// Number of frames during the last second
int mNbFrames;
/// Current time for fps computation (in seconds)
double mCurrentTime;
/// Previous time for fps computation (in seconds)
double mPreviousTime;
/// Last time the FPS have been computed
double mLastTimeComputedFPS;
/// Update time (in seconds)
double mFrameTime;
/// Physics update time (in seconds)
double mPhysicsTime;
/// Width and height of the window
int mWidth, mHeight;
/// True if the next simulation update is a single physics step
bool mSinglePhysicsStepEnabled;
/// True if the single physics step has been taken already
bool mSinglePhysicsStepDone;
openglframework::Vector2 mWindowToFramebufferRatio;
/// True if shadow mapping is enabled
bool mIsShadowMappingEnabled;
/// True if contact points are displayed
bool mIsContactPointsDisplayed;
/// True if the AABBs of physics objects are displayed
bool mIsAABBsDisplayed;
/// True if the wireframe rendering is enabled
bool mIsWireframeEnabled;
/// True if vsync is enabled
bool mIsVSyncEnabled;
// -------------------- Methods -------------------- //
/// Private copy-constructor (for the singleton class)
TestbedApplication(TestbedApplication const&);
/// Private assignment operator (for the singleton class)
void operator=(TestbedApplication const&);
/// Update the physics of the current scene
void updatePhysics();
/// Update
void update();
/// Update the simulation by taking a single physics step
void updateSinglePhysicsStep();
/// Check the OpenGL errors
static void checkOpenGLErrorsInternal(const char* file, int line);
/// Compute the FPS
void computeFPS();
/// Initialize all the scenes
void createScenes();
/// Remove all the scenes
void destroyScenes();
/// Return the list of the scenes
std::vector<Scene*> getScenes();
/// Start/stop the simulation
void togglePlayPauseSimulation();
/// Play the simulation
void playSimulation();
/// Pause the simulation
void pauseSimulation();
/// Restart the simulation
void restartSimulation();
/// Set the variable to know if we need to take a single physics step
void toggleTakeSinglePhysicsStep();
public :
// -------------------- Methods -------------------- //
/// Private constructor (for the singleton class)
TestbedApplication(bool isFullscreen);
/// Destructor
virtual ~TestbedApplication() override;
/// Render the content of the application
virtual void drawContents() override;
/// Window resize event handler
virtual bool resizeEvent(const Vector2i& size) override;
/// Default keyboard event handler
virtual bool keyboardEvent(int key, int scancode, int action, int modifiers) override;
/// Handle a mouse button event (default implementation: propagate to children)
virtual bool mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) override;
/// Handle a mouse motion event (default implementation: propagate to children)
virtual bool mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override;
/// Handle a mouse scroll event (default implementation: propagate to children)
virtual bool scrollEvent(const Vector2i &p, const Vector2f &rel) override;
/// Initialize the application
void init();
/// Change the current scene
void switchScene(Scene* newScene);
/// Enable/Disable Vertical synchronization
void enableVSync(bool enable);
/// Notify that the engine settings have changed
void notifyEngineSetttingsChanged();
// -------------------- Friendship -------------------- //
friend class Gui;
};
// Return the list of the scenes
inline std::vector<Scene*> TestbedApplication::getScenes() {
return mScenes;
}
// Toggle play/pause for the simulation
inline void TestbedApplication::togglePlayPauseSimulation() {
if (mTimer.isRunning()) {
mTimer.stop();
}
else {
mTimer.start();
}
}
// Play the simulation
inline void TestbedApplication::playSimulation() {
if (!mTimer.isRunning()) mTimer.start();
}
// Pause the simulation
inline void TestbedApplication::pauseSimulation() {
if (mTimer.isRunning()) mTimer.stop();
}
// Restart the simulation
inline void TestbedApplication::restartSimulation() {
mCurrentScene->reset();
mTimer.start();
}
// Take a single step of simulation
inline void TestbedApplication::toggleTakeSinglePhysicsStep() {
mSinglePhysicsStepEnabled = true;
mSinglePhysicsStepDone = false;
if (mTimer.isRunning()) {
mSinglePhysicsStepEnabled = false;
}
}
// Enable/Disable Vertical synchronization
inline void TestbedApplication::enableVSync(bool enable) {
mIsVSyncEnabled = enable;
if (mIsVSyncEnabled) {
glfwSwapInterval(1);
}
else {
glfwSwapInterval(0);
}
}
#endif
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2016 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 TESTBED_APPLICATION_H
#define TESTBED_APPLICATION_H
// Libraries
#include "openglframework.h"
#include "Gui.h"
#include "Scene.h"
#include "Timer.h"
#include <GLFW/glfw3.h>
using namespace nanogui;
// Macro for OpenGL errors
#define checkOpenGLErrors() checkOpenGLErrorsInternal(__FILE__,__LINE__)
/// Class TestbedApplication
class TestbedApplication : public Screen {
private :
// -------------------- Constants -------------------- //
static const float SCROLL_SENSITIVITY;
// -------------------- Attributes -------------------- //
bool mIsInitialized;
Gui mGui;
/// Timer
Timer mTimer;
/// List of 3D scenes
std::vector<Scene*> mScenes;
/// Current 3D scene
Scene* mCurrentScene;
/// Physics engine settings
EngineSettings mEngineSettings;
/// Current number of frames per seconds
double mFPS;
/// Number of frames during the last second
int mNbFrames;
/// Current time for fps computation (in seconds)
double mCurrentTime;
/// Previous time for fps computation (in seconds)
double mPreviousTime;
/// Last time the FPS have been computed
double mLastTimeComputedFPS;
/// Update time (in seconds)
double mFrameTime;
/// Physics update time (in seconds)
double mPhysicsTime;
/// Width and height of the window
int mWidth, mHeight;
/// True if the next simulation update is a single physics step
bool mSinglePhysicsStepEnabled;
/// True if the single physics step has been taken already
bool mSinglePhysicsStepDone;
openglframework::Vector2 mWindowToFramebufferRatio;
/// True if shadow mapping is enabled
bool mIsShadowMappingEnabled;
/// True if contact points are displayed
bool mIsContactPointsDisplayed;
/// True if the AABBs of physics objects are displayed
bool mIsAABBsDisplayed;
/// True if the wireframe rendering is enabled
bool mIsWireframeEnabled;
/// True if vsync is enabled
bool mIsVSyncEnabled;
// -------------------- Methods -------------------- //
/// Private copy-constructor (for the singleton class)
TestbedApplication(TestbedApplication const&);
/// Private assignment operator (for the singleton class)
void operator=(TestbedApplication const&);
/// Update the physics of the current scene
void updatePhysics();
/// Update
void update();
/// Update the simulation by taking a single physics step
void updateSinglePhysicsStep();
/// Check the OpenGL errors
static void checkOpenGLErrorsInternal(const char* file, int line);
/// Compute the FPS
void computeFPS();
/// Initialize all the scenes
void createScenes();
/// Remove all the scenes
void destroyScenes();
/// Return the list of the scenes
std::vector<Scene*> getScenes();
/// Start/stop the simulation
void togglePlayPauseSimulation();
/// Play the simulation
void playSimulation();
/// Pause the simulation
void pauseSimulation();
/// Restart the simulation
void restartSimulation();
/// Set the variable to know if we need to take a single physics step
void toggleTakeSinglePhysicsStep();
public :
// -------------------- Methods -------------------- //
/// Private constructor (for the singleton class)
TestbedApplication(bool isFullscreen, int windowWidth, int windowHeight);
/// Destructor
virtual ~TestbedApplication() override;
/// Render the content of the application
virtual void drawContents() override;
/// Window resize event handler
virtual bool resizeEvent(const Vector2i& size) override;
/// Default keyboard event handler
virtual bool keyboardEvent(int key, int scancode, int action, int modifiers) override;
/// Handle a mouse button event (default implementation: propagate to children)
virtual bool mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) override;
/// Handle a mouse motion event (default implementation: propagate to children)
virtual bool mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) override;
/// Handle a mouse scroll event (default implementation: propagate to children)
virtual bool scrollEvent(const Vector2i &p, const Vector2f &rel) override;
/// Initialize the application
void init();
/// Change the current scene
void switchScene(Scene* newScene);
/// Enable/Disable Vertical synchronization
void enableVSync(bool enable);
/// Notify that the engine settings have changed
void notifyEngineSetttingsChanged();
// -------------------- Friendship -------------------- //
friend class Gui;
};
// Return the list of the scenes
inline std::vector<Scene*> TestbedApplication::getScenes() {
return mScenes;
}
// Toggle play/pause for the simulation
inline void TestbedApplication::togglePlayPauseSimulation() {
if (mTimer.isRunning()) {
mTimer.stop();
}
else {
mTimer.start();
}
}
// Play the simulation
inline void TestbedApplication::playSimulation() {
if (!mTimer.isRunning()) mTimer.start();
}
// Pause the simulation
inline void TestbedApplication::pauseSimulation() {
if (mTimer.isRunning()) mTimer.stop();
}
// Restart the simulation
inline void TestbedApplication::restartSimulation() {
mCurrentScene->reset();
mTimer.start();
}
// Take a single step of simulation
inline void TestbedApplication::toggleTakeSinglePhysicsStep() {
mSinglePhysicsStepEnabled = true;
mSinglePhysicsStepDone = false;
if (mTimer.isRunning()) {
mSinglePhysicsStepEnabled = false;
}
}
// Enable/Disable Vertical synchronization
inline void TestbedApplication::enableVSync(bool enable) {
mIsVSyncEnabled = enable;
if (mIsVSyncEnabled) {
glfwSwapInterval(1);
}
else {
glfwSwapInterval(0);
}
}
#endif