void MeshMassPropertiesTests::testClosedTetrahedronMesh() { // given a tetrahedron as a closed mesh of four tiangles // verify MeshMassProperties computes the right nubers // these numbers from the Tonon paper: VectorOfPoints points; points.push_back(btVector3(8.33220f, -11.86875f, 0.93355f)); points.push_back(btVector3(0.75523f, 5.00000f, 16.37072f)); points.push_back(btVector3(52.61236f, 5.00000f, -5.38580f)); points.push_back(btVector3(2.00000f, 5.00000f, 3.00000f)); btScalar expectedVolume = 1873.233236f; btMatrix3x3 expectedInertia; expectedInertia[0][0] = 43520.33257f; expectedInertia[1][1] = 194711.28938f; expectedInertia[2][2] = 191168.76173f; expectedInertia[1][2] = -4417.66150f; expectedInertia[2][1] = -4417.66150f; expectedInertia[0][2] = 46343.16662f; expectedInertia[2][0] = 46343.16662f; expectedInertia[0][1] = -11996.20119f; expectedInertia[1][0] = -11996.20119f; btVector3 expectedCenterOfMass = 0.25f * (points[0] + points[1] + points[2] + points[3]); VectorOfIndices triangles; pushTriangle(triangles, 0, 2, 1); pushTriangle(triangles, 0, 3, 2); pushTriangle(triangles, 0, 1, 3); pushTriangle(triangles, 1, 2, 3); // compute mass properties MeshMassProperties mesh(points, triangles); // verify QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); // test again, but this time shift the points so that the origin is definitely OUTSIDE the mesh btVector3 shift = points[0] + expectedCenterOfMass; for (int i = 0; i < (int)points.size(); ++i) { points[i] += shift; } expectedCenterOfMass = 0.25f * (points[0] + points[1] + points[2] + points[3]); // compute mass properties mesh.computeMassProperties(points, triangles); // verify // QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); // QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); // QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); }
void sierpinskiGasket(unsigned int a, unsigned int b, unsigned int c, unsigned int level) { if(level == 0) { // Generate new vertices and call this function recursively // ... insert your code here ... pushTriangle(a, b, c); // ... end of your code ... } else{ Vertex newTrianglePointA = Vertex((vertices[a].position.x+vertices[b].position.x)/2, (vertices[a].position.y+vertices[b].position.y)/2); Vertex newTrianglePointB = Vertex((vertices[b].position.x+vertices[c].position.x)/2, (vertices[b].position.y+vertices[c].position.y)/2); Vertex newTrianglePointC = Vertex((vertices[c].position.x+vertices[a].position.x)/2, (vertices[c].position.y+vertices[a].position.y)/2); int indexA = vertices.size(); int indexB = indexA+1; int indexC = indexB+1; vertices.push_back(newTrianglePointA); vertices.push_back(newTrianglePointB); vertices.push_back(newTrianglePointC); level = level-1; sierpinskiGasket(a, indexA, indexC, level); sierpinskiGasket(indexA, b, indexB, level); sierpinskiGasket(indexC, indexB, c, level); } }
Terrain::Terrain(int width, int height, int patchSize) : m_width(width), m_height(height), m_patchSize(patchSize), m_patchCount(width / patchSize, height / patchSize), m_patchMesh(), m_currentHeightMap(0), m_shader() { for (int i = 0; i < 2; ++i) { m_heightMaps[i] = new FrameBuffer(width, height); m_heightMaps[i]->edit(); m_heightMaps[i]->addColorTexture(GL_R32F); m_heightMaps[i]->done(); } std::vector<glm::vec3> vertices; std::vector<unsigned short> indicies; #define INDEX(x, z) ((z) * patchSize) + (x) for (int z = 0; z < patchSize; ++z) for (int x = 0; x < patchSize; ++x) { float ux = x / (patchSize - 1.0); float uz = z / (patchSize - 1.0); vertices.push_back(glm::vec3(ux, 0.0, uz)); if (z < (patchSize - 1) && x < (patchSize - 1)) { pushTriangle(indicies, INDEX(x, z), INDEX(x, z + 1), INDEX(x + 1, z)); pushTriangle(indicies, INDEX(x, z + 1), INDEX(x + 1, z + 1), INDEX(x + 1, z)); } } m_patchMesh.addBuffer(Mesh::VERTEX, vertices); m_patchMesh.addBuffer(Mesh::INDICIES, indicies); m_patchMesh.setIndexCount(indicies.size()); m_shader.load("../../example/data/Terrain.vert", GL_VERTEX_SHADER); m_shader.load("../../example/data/Terrain.frag", GL_FRAGMENT_SHADER); m_shader.setupMeshAttributes(); m_shader.link(); }
void Rasterizer::pushTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) { Vector3 p1, p2, p3; p1 = getRenderer()->projectPoint(v1); p2 = getRenderer()->projectPoint(v2); p3 = getRenderer()->projectPoint(v3); if (pushProjectedTriangle(canvas, p1, p2, p3, v1, v2, v3)) { // Cutting needed Vector3 vm1 = v1.midPointTo(v2); Vector3 vm2 = v2.midPointTo(v3); Vector3 vm3 = v3.midPointTo(v1); pushTriangle(canvas, v1, vm1, vm3); pushTriangle(canvas, v2, vm1, vm2); pushTriangle(canvas, v3, vm3, vm2); pushTriangle(canvas, vm1, vm2, vm3); } }
void MeshMassPropertiesTests::testOpenTetrahedonMesh() { // given the simplest possible mesh (open, with one triangle) // verify MeshMassProperties computes the right nubers // these numbers from the Tonon paper: VectorOfPoints points; points.push_back(btVector3(8.33220f, -11.86875f, 0.93355f)); points.push_back(btVector3(0.75523f, 5.00000f, 16.37072f)); points.push_back(btVector3(52.61236f, 5.00000f, -5.38580f)); points.push_back(btVector3(2.00000f, 5.00000f, 3.00000f)); btScalar expectedVolume = 1873.233236f; btMatrix3x3 expectedInertia; expectedInertia[0][0] = 43520.33257f; expectedInertia[1][1] = 194711.28938f; expectedInertia[2][2] = 191168.76173f; expectedInertia[1][2] = -4417.66150f; expectedInertia[2][1] = -4417.66150f; expectedInertia[0][2] = 46343.16662f; expectedInertia[2][0] = 46343.16662f; expectedInertia[0][1] = -11996.20119f; expectedInertia[1][0] = -11996.20119f; // test as an open mesh with one triangle VectorOfPoints shiftedPoints; shiftedPoints.push_back(points[0] - points[0]); shiftedPoints.push_back(points[1] - points[0]); shiftedPoints.push_back(points[2] - points[0]); shiftedPoints.push_back(points[3] - points[0]); VectorOfIndices triangles; pushTriangle(triangles, 1, 2, 3); btVector3 expectedCenterOfMass = 0.25f * (shiftedPoints[0] + shiftedPoints[1] + shiftedPoints[2] + shiftedPoints[3]); // compute mass properties MeshMassProperties mesh(shiftedPoints, triangles); // verify // (expected - actual) / expected > e ==> expected - actual > e * expected QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); }
void SoCapsule::build ( float len, float rt, float rb, int nfaces ) { P.clear(); C.clear(); // set size to zero, just in case float hlen = len/2.0f; int levels = std::ceil(static_cast<float>(nfaces) / 2.0f); float faceAngularHeight = (static_cast<float>(M_PI) / 2.0) / static_cast<float>(levels); float faceAngularLength = (2.0 * static_cast<float>(M_PI)) / static_cast<float>(nfaces); int vertices = 2 + (2*levels + 1)*(nfaces * 6); // Reserve space for the capsule vertices P.reserve(vertices); C.reserve(vertices); // Generate the coordinates for the capsule body std::vector<GsVec> bodyTopCoordinates; std::vector<GsVec> bodyBottomCoordinates; bodyTopCoordinates.reserve(nfaces); bodyBottomCoordinates.reserve(nfaces); // Compute the tube section of the capsule for(int i = 0; i < nfaces; i++) { float p = static_cast<float>(i) * faceAngularLength; bodyTopCoordinates.push_back(GsVec(rt * std::cos(p), hlen, rt * std::sin(p))); bodyBottomCoordinates.push_back(GsVec(rb * std::cos(p), -hlen, rb * std::sin(p))); } pushLevel(P, C, bodyTopCoordinates, bodyBottomCoordinates, nfaces); // Compute the top of the capsule std::vector<GsVec>& previousTopVector = bodyTopCoordinates; std::vector<GsVec> currentTopVector; currentTopVector.reserve(nfaces); for(int j = 1; j < levels; j++) { // theta coordinate float t = static_cast<float>(j) * faceAngularHeight; for(int i = 0; i < nfaces; i++) { // phi coordinate float p = static_cast<float>(i) * faceAngularLength; currentTopVector.push_back(GsVec((rt * std::cos(p)) * std::cos(t), hlen + (rt * std::sin(t)), (rt * std::sin(p)) * std::cos(t))); } pushLevel(P, C, currentTopVector, previousTopVector, nfaces); std::swap(currentTopVector, previousTopVector); currentTopVector.clear(); } // Compute the cap of the capsule GsVec tv(0.0f, hlen + rt, 0.0f); for(int i = 0; i < nfaces; i++) { GsVec a = previousTopVector[i]; GsVec b = (i+1 == nfaces) ? previousTopVector[0] : previousTopVector[i+1]; pushTriangle(P, C, {a, b, tv}); } // Compute the bottom of the capsule std::vector<GsVec>& previousBottomVector = bodyBottomCoordinates; std::vector<GsVec> currentBottomVector; currentBottomVector.reserve(nfaces); for(int j = 1; j < levels; j++) { // theta coordinate float t = static_cast<float>(j) * faceAngularHeight; for(int i = 0; i < nfaces; i++) { // phi coordinate float p = static_cast<float>(i) * faceAngularLength; currentBottomVector.push_back(GsVec((rb * std::cos(p)) * std::cos(t), -hlen - (rb * std::sin(t)), (rb * std::sin(p)) * std::cos(t))); } pushLevel(P, C, currentBottomVector, previousBottomVector, nfaces); std::swap(currentBottomVector, previousBottomVector); currentBottomVector.clear(); } // Compute the cap of the capsule GsVec bv(0.0f, -hlen - rb, 0.0f); for(int i = 0; i < nfaces; i++) { GsVec a = previousBottomVector[i]; GsVec b = (i+1 == nfaces) ? previousBottomVector[0] : previousBottomVector[i+1]; pushTriangle(P, C, {a, bv, b}); } //pushCap(P, C, previousBottomVector, bv, nfaces); // send data to OpenGL buffers: glBindBuffer ( GL_ARRAY_BUFFER, buf[0] ); glBufferData ( GL_ARRAY_BUFFER, P.size()*3*sizeof(float), &P[0], GL_STATIC_DRAW ); glBindBuffer ( GL_ARRAY_BUFFER, buf[1] ); glBufferData ( GL_ARRAY_BUFFER, C.size()*4*sizeof(gsbyte), &C[0], GL_STATIC_DRAW ); // save size so that we can free our buffers and later just draw the OpenGL arrays: _numpoints = P.size(); // free non-needed memory: P.resize(0); C.resize(0); changed = 0; }
void Rasterizer::pushQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4) { pushTriangle(canvas, v2, v3, v1); pushTriangle(canvas, v4, v1, v3); }
void MeshMassPropertiesTests::testBoxAsMesh() { // verify that a mesh box produces the same mass properties as the analytic box. // build a box: // / // y // / // 6-------------------------7 // /| /| // / | / | // / 2----------------------/--3 // / / / / // | 4-------------------------5 / --x-- // z | / | / // | |/ |/ // 0 ------------------------1 btScalar x(5.0f); btScalar y(3.0f); btScalar z(2.0f); VectorOfPoints points; points.reserve(8); points.push_back(btVector3(0.0f, 0.0f, 0.0f)); points.push_back(btVector3(x, 0.0f, 0.0f)); points.push_back(btVector3(0.0f, y, 0.0f)); points.push_back(btVector3(x, y, 0.0f)); points.push_back(btVector3(0.0f, 0.0f, z)); points.push_back(btVector3(x, 0.0f, z)); points.push_back(btVector3(0.0f, y, z)); points.push_back(btVector3(x, y, z)); VectorOfIndices triangles; pushTriangle(triangles, 0, 1, 4); pushTriangle(triangles, 1, 5, 4); pushTriangle(triangles, 1, 3, 5); pushTriangle(triangles, 3, 7, 5); pushTriangle(triangles, 2, 0, 6); pushTriangle(triangles, 0, 4, 6); pushTriangle(triangles, 3, 2, 7); pushTriangle(triangles, 2, 6, 7); pushTriangle(triangles, 4, 5, 6); pushTriangle(triangles, 5, 7, 6); pushTriangle(triangles, 0, 2, 1); pushTriangle(triangles, 2, 3, 1); // compute expected mass properties analytically btVector3 expectedCenterOfMass = 0.5f * btVector3(x, y, z); btScalar expectedVolume = x * y * z; btMatrix3x3 expectedInertia; computeBoxInertia(expectedVolume, btVector3(x, y, z), expectedInertia); // compute the mass properties using the mesh MeshMassProperties mesh(points, triangles); // verify QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); // test this twice: _RELATIVE_ERROR doesn't test zero cases (to avoid divide-by-zero); _ABS_ERROR does. QCOMPARE_WITH_ABS_ERROR(mesh._inertia, expectedInertia, acceptableAbsoluteError); QCOMPARE_WITH_RELATIVE_ERROR(mesh._inertia, expectedInertia, acceptableRelativeError); // These two macros impl this: // for (int i = 0; i < 3; ++i) { // for (int j = 0; j < 3; ++j) { // if (expectedInertia [i][j] == btScalar(0.0f)) { // error = mesh._inertia[i][j] - expectedInertia[i][j]; // COMPARE_WITH_ABS_ERROR // if (fabsf(error) > acceptableAbsoluteError) { // std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " // << error << " absolute"<< std::endl; // } // } else { // error = (mesh._inertia[i][j] - expectedInertia[i][j]) / expectedInertia[i][j]; // COMPARE_WITH_RELATIVE_ERROR // if (fabsf(error) > acceptableRelativeError) { // std::cout << __FILE__ << ":" << __LINE__ << " ERROR : inertia[" << i << "][" << j << "] off by " // << error << std::endl; // } // } // } // } }