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);
}
Beispiel #2
0
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);
        
        
        
    }
}
Beispiel #3
0
  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();
  }
Beispiel #4
0
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;
}
Beispiel #7
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;
//                }
//            }
//        }
//    }
}