1 /********************************************************************************
2 * ReactPhysics3D physics library, http://www.reactphysics3d.com *
3 * Copyright (c) 2010-2016 Daniel Chappuis *
4 *********************************************************************************
5 * *
6 * This software is provided 'as-is', without any express or implied warranty. *
7 * In no event will the authors be held liable for any damages arising from the *
8 * use of this software. *
9 * *
10 * Permission is granted to anyone to use this software for any purpose, *
11 * including commercial applications, and to alter it and redistribute it *
12 * freely, subject to the following restrictions: *
13 * *
14 * 1. The origin of this software must not be misrepresented; you must not claim *
15 * that you wrote the original software. If you use this software in a *
16 * product, an acknowledgment in the product documentation would be *
17 * appreciated but is not required. *
18 * *
19 * 2. Altered source versions must be plainly marked as such, and must not be *
20 * misrepresented as being the original software. *
21 * *
22 * 3. This notice may not be removed or altered from any source distribution. *
23 * *
24 ********************************************************************************/
25
26 // Libraries
27 #include "HeightField.h"
28 #include "PerlinNoise.h"
29
30 // Constructor
HeightField(bool createRigidBody,reactphysics3d::PhysicsCommon & physicsCommon,rp3d::PhysicsWorld * physicsWorld)31 HeightField::HeightField(bool createRigidBody, reactphysics3d::PhysicsCommon& physicsCommon, rp3d::PhysicsWorld* physicsWorld)
32 : PhysicsObject(physicsCommon), mVBOVertices(GL_ARRAY_BUFFER),
33 mVBONormals(GL_ARRAY_BUFFER), mVBOTextureCoords(GL_ARRAY_BUFFER),
34 mVBOIndices(GL_ELEMENT_ARRAY_BUFFER) {
35
36 // Compute the scaling matrix
37 //mScalingMatrix = openglframework::Matrix4::identity();
38 mScalingMatrix = openglframework::Matrix4(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1);
39
40 // Generate the height field
41 generateHeightField();
42
43 // Generate the graphics mesh
44 generateGraphicsMesh();
45
46 // Create the collision shape for the rigid body (convex mesh shape) and
47 // do not forget to delete it at the end
48 mHeightFieldShape = mPhysicsCommon.createHeightFieldShape(NB_POINTS_WIDTH, NB_POINTS_LENGTH, mMinHeight, mMaxHeight,
49 mHeightData, rp3d::HeightFieldShape::HeightDataType::HEIGHT_FLOAT_TYPE);
50 mHeightFieldShape->setScale(rp3d::Vector3(2, 2, 2));
51
52 mPreviousTransform = rp3d::Transform::identity();
53
54 // Create a body
55 if (createRigidBody) {
56 rp3d::RigidBody* body = physicsWorld->createRigidBody(mPreviousTransform);
57 mCollider = body->addCollider(mHeightFieldShape, rp3d::Transform::identity());
58 body->updateMassPropertiesFromColliders();
59 mBody = body;
60 }
61 else {
62 mBody = physicsWorld->createCollisionBody(mPreviousTransform);
63 mCollider = mBody->addCollider(mHeightFieldShape, rp3d::Transform::identity());
64 }
65
66
67 // Create the VBOs and VAO
68 createVBOAndVAO();
69
70 mTransformMatrix = mTransformMatrix * mScalingMatrix;
71 }
72
73 // Destructor
~HeightField()74 HeightField::~HeightField() {
75
76 // Destroy the mesh
77 destroy();
78
79 // Destroy the VBOs and VAO
80 mVBOIndices.destroy();
81 mVBOVertices.destroy();
82 mVBONormals.destroy();
83 mVBOTextureCoords.destroy();
84 mVAO.destroy();
85
86 mPhysicsCommon.destroyHeightFieldShape(mHeightFieldShape);
87 }
88
89 // Render the sphere at the correct position and with the correct orientation
render(openglframework::Shader & shader,const openglframework::Matrix4 & worldToCameraMatrix)90 void HeightField::render(openglframework::Shader& shader,
91 const openglframework::Matrix4& worldToCameraMatrix) {
92
93 // Bind the shader
94 shader.bind();
95
96 // Set the model to camera matrix
97 shader.setMatrix4x4Uniform("localToWorldMatrix", mTransformMatrix);
98 shader.setMatrix4x4Uniform("worldToCameraMatrix", worldToCameraMatrix);
99
100 // Set the normal matrix (inverse transpose of the 3x3 upper-left sub matrix of the
101 // model-view matrix)
102 const openglframework::Matrix4 localToCameraMatrix = worldToCameraMatrix * mTransformMatrix;
103 const openglframework::Matrix3 normalMatrix =
104 localToCameraMatrix.getUpperLeft3x3Matrix().getInverse().getTranspose();
105 shader.setMatrix3x3Uniform("normalMatrix", normalMatrix, false);
106
107 // Set the vertex color
108 rp3d::RigidBody* rigidBody = dynamic_cast<rp3d::RigidBody*>(mBody);
109 openglframework::Color currentColor = rigidBody != nullptr && rigidBody->isSleeping() ? mSleepingColor : mColor;
110 openglframework::Vector4 color(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
111 shader.setVector4Uniform("globalVertexColor", color, false);
112
113 // Bind the VAO
114 mVAO.bind();
115
116 mVBOVertices.bind();
117
118 // Get the location of shader attribute variables
119 GLint vertexPositionLoc = shader.getAttribLocation("vertexPosition");
120 GLint vertexNormalLoc = shader.getAttribLocation("vertexNormal", false);
121
122 glEnableVertexAttribArray(vertexPositionLoc);
123 glVertexAttribPointer(vertexPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL);
124
125 mVBONormals.bind();
126
127 if (vertexNormalLoc != -1) glVertexAttribPointer(vertexNormalLoc, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL);
128 if (vertexNormalLoc != -1) glEnableVertexAttribArray(vertexNormalLoc);
129
130 // For each part of the mesh
131 for (unsigned int i=0; i<getNbParts(); i++) {
132 glDrawElements(GL_TRIANGLES, getNbFaces(i) * 3, GL_UNSIGNED_INT, (char*)NULL);
133 }
134
135 glDisableVertexAttribArray(vertexPositionLoc);
136 if (vertexNormalLoc != -1) glDisableVertexAttribArray(vertexNormalLoc);
137
138 mVBONormals.unbind();
139 mVBOVertices.unbind();
140
141 // Unbind the VAO
142 mVAO.unbind();
143
144 // Unbind the shader
145 shader.unbind();
146 }
147
148 // Compute the heights of the height field
generateHeightField()149 void HeightField::generateHeightField() {
150
151 double persistence = 9;
152 double frequency = 0.28;
153 double amplitude = 12;
154 int octaves = 1;
155 int randomseed = 23;
156 PerlinNoise perlinNoise(persistence, frequency, amplitude, octaves, randomseed);
157
158 mMinHeight = 0;
159 mMaxHeight = 0;
160
161 float width = (NB_POINTS_WIDTH - 1);
162 float length = (NB_POINTS_LENGTH - 1);
163
164 for (int i=0; i<NB_POINTS_WIDTH; i++) {
165 for (int j=0; j<NB_POINTS_LENGTH; j++) {
166
167 int arrayIndex = j * NB_POINTS_WIDTH + i;
168
169 mHeightData[arrayIndex] = (float)(perlinNoise.GetHeight(-width * 0.5 + i, -length * 0.5 + j));
170
171 if (i==0 && j==0) {
172 mMinHeight = mHeightData[arrayIndex] ;
173 mMaxHeight = mHeightData[arrayIndex] ;
174 }
175
176 if (mHeightData[arrayIndex] > mMaxHeight) mMaxHeight = mHeightData[arrayIndex] ;
177 if (mHeightData[arrayIndex] < mMinHeight) mMinHeight = mHeightData[arrayIndex] ;
178 }
179 }
180 }
181
182 // Generate the graphics mesh to render the height field
generateGraphicsMesh()183 void HeightField::generateGraphicsMesh() {
184
185 std::vector<unsigned int> indices;
186 int vertexId = 0;
187
188 for (int i=0; i<NB_POINTS_WIDTH; i++) {
189 for (int j=0; j<NB_POINTS_LENGTH; j++) {
190
191 float originHeight = -(mMaxHeight - mMinHeight) * 0.5f - mMinHeight;
192 float height = originHeight + mHeightData[j * NB_POINTS_WIDTH + i];
193 openglframework::Vector3 vertex(-(NB_POINTS_WIDTH - 1) * 0.5f + i, height, -(NB_POINTS_LENGTH - 1) * 0.5f + j);
194
195 mVertices.push_back(vertex);
196
197 // Triangle indices
198 if ((i < NB_POINTS_WIDTH - 1) && (j < NB_POINTS_LENGTH - 1)) {
199
200 unsigned int v1 = vertexId;
201 unsigned int v2 = vertexId + 1;
202 unsigned int v3 = vertexId + NB_POINTS_LENGTH;
203 unsigned int v4 = vertexId + NB_POINTS_LENGTH + 1;
204
205 // First triangle
206 indices.push_back(v1);
207 indices.push_back(v2);
208 indices.push_back(v3);
209
210 // Second triangle
211 indices.push_back(v2);
212 indices.push_back(v4);
213 indices.push_back(v3);
214 }
215
216 vertexId++;
217 }
218 }
219
220 mIndices.push_back(indices);
221
222 calculateNormals();
223 }
224
225 // Create the Vertex Buffer Objects used to render with OpenGL.
226 /// We create two VBOs (one for vertices and one for indices)
createVBOAndVAO()227 void HeightField::createVBOAndVAO() {
228
229 // Create the VBO for the vertices data
230 mVBOVertices.create();
231 mVBOVertices.bind();
232 size_t sizeVertices = mVertices.size() * sizeof(openglframework::Vector3);
233 mVBOVertices.copyDataIntoVBO(sizeVertices, getVerticesPointer(), GL_STATIC_DRAW);
234 mVBOVertices.unbind();
235
236 // Create the VBO for the normals data
237 mVBONormals.create();
238 mVBONormals.bind();
239 size_t sizeNormals = mNormals.size() * sizeof(openglframework::Vector3);
240 mVBONormals.copyDataIntoVBO(sizeNormals, getNormalsPointer(), GL_STATIC_DRAW);
241 mVBONormals.unbind();
242
243 if (hasTexture()) {
244 // Create the VBO for the texture co data
245 mVBOTextureCoords.create();
246 mVBOTextureCoords.bind();
247 size_t sizeTextureCoords = mUVs.size() * sizeof(openglframework::Vector2);
248 mVBOTextureCoords.copyDataIntoVBO(sizeTextureCoords, getUVTextureCoordinatesPointer(), GL_STATIC_DRAW);
249 mVBOTextureCoords.unbind();
250 }
251
252 // Create th VBO for the indices data
253 mVBOIndices.create();
254 mVBOIndices.bind();
255 size_t sizeIndices = mIndices[0].size() * sizeof(unsigned int);
256 mVBOIndices.copyDataIntoVBO(sizeIndices, getIndicesPointer(), GL_STATIC_DRAW);
257 mVBOIndices.unbind();
258
259 // Create the VAO for both VBOs
260 mVAO.create();
261 mVAO.bind();
262
263 // Bind the VBO of vertices
264 mVBOVertices.bind();
265
266 // Bind the VBO of normals
267 mVBONormals.bind();
268
269 if (hasTexture()) {
270 // Bind the VBO of texture coords
271 mVBOTextureCoords.bind();
272 }
273
274 // Bind the VBO of indices
275 mVBOIndices.bind();
276
277 // Unbind the VAO
278 mVAO.unbind();
279 }
280