Vec3 TriMesh::computeFaceNormal(unsigned face) const
{
    std::vector<unsigned> fVert;
    getFaceVerts(face, fVert);
    assert(fVert.size() == 3);

    Vec3 p0 = getVertPos(fVert[0]);
    Vec3 p1 = getVertPos(fVert[1]);
    Vec3 p2 = getVertPos(fVert[2]);
    return (p1-p0).cross(p2-p1).normalized();
}
double TriMesh::computeFaceArea(unsigned face) const
{
    std::vector<unsigned> fVert;
    getFaceVerts(face, fVert);
    assert(fVert.size() == 3);

    Vec3 p0 = getVertPos(fVert[0]);
    Vec3 p1 = getVertPos(fVert[1]);
    Vec3 p2 = getVertPos(fVert[2]);
    return Triangle::area(p0, p1, p2);
}
void TriMesh::computeFaceGrad(const VectorXd& vertForm, std::vector<Vec3>& faceVector) const
{
    faceVector.resize(numFaces());
    for (unsigned face = 0; face < numFaces(); ++face) 
    {
        std::vector<unsigned> fVert;
        getFaceVerts(face, fVert);
        assert(fVert.size() == 3);

        Vec3 pos[3];
        double val[3];
        for (unsigned i = 0; i < 3; ++i) 
        {
            val[i] = vertForm(fVert[i]);
            pos[i] = getVertPos(fVert[i]);
        }

        Vec3 X = Vec3::Zero();
        for (unsigned i = 0; i < 3; ++i) 
        {
            unsigned j = (i + 1) % 3;
            unsigned k = (i + 2) % 3;
            X += val[i] * (pos[k] - pos[j]);
        }

        Vec3 n = (pos[1]-pos[0]).cross(pos[2]-pos[1]);
        double twice_area = n.norm();
        n /= twice_area;

        faceVector[face] = n.cross(X) / twice_area;
    }
}
void VboCircleRenderer::noFillCircle(float x, float y, float size) {
    int res = getResolution(size);
    
    float oneStep = M_2XPI / res;
    int baseIndex = noFillCounter.vertex;
    
    float rad = 0;
    ofVec2f pos;
    for(int i = 0; i < res; i++) {
        rad = oneStep * i;
        pos = getVertPos(x, y, rad, size);
        addVertex(noFill, pos); //put into base index
        
        //This Vertex
        addIndex(noFill, baseIndex + i);
        addColor(noFill, color);
        
        //Second
        if(i == (res - 1)) {
            addIndex(noFill, baseIndex);
            addColor(noFill, color);
        } else {
            addIndex(noFill, baseIndex + i + 1);
            addColor(noFill, color);
        }
    }
}
void TriMesh::computeDivergence(const std::vector<Vec3>& faceVector, VectorXd& vertForm) const
{
    vertForm = VectorXd::Zero(numVerts());
    for (unsigned face = 0; face < numFaces(); ++face) 
    {
        std::vector<unsigned> fVert;
        getFaceVerts(face, fVert);
        assert(fVert.size() == 3);
        
        Vec3 n = computeFaceNormal(face);
        for (unsigned i = 0; i < 3; ++i) 
        {
            Vec3 p1 = getVertPos(fVert[(i+1)%3]);
            Vec3 p2 = getVertPos(fVert[(i+2)%3]);
            vertForm[fVert[i]] += 0.5*faceVector[face].dot(n.cross(p2-p1));
        }
    }
}
double TriMesh::computeFaceCotan(unsigned face, unsigned vertInFace) const
{
    std::vector<unsigned> fVert;
    getFaceVerts(face, fVert);
    assert(fVert.size() == 3);

    Vec3 p[3];
    for (unsigned i = 0; i < 3; ++i)
        p[i] = getVertPos(fVert[(vertInFace+i)%3]);
    return Triangle::cotan(p[0], p[1], p[2]);
}
void VboCircleRenderer::filledCircle(float x, float y, float size) {
    
    int res = getResolution(size);
    float oneStep = M_2XPI / res;
    int baseIndex = filledCounter.vertex;
    
    //Set Center vertex
    ofVec2f center = ofVec2f(x * width, y * height);
    addVertex(filled, center);  //Add Center first
    addColor(filled, color);
    
    float rad = 0;
    ofVec2f pos;
    for(int i = 0; i < res; i++) {
        rad = oneStep * i;
        pos = getVertPos(x, y, rad, size);
        addVertex(filled, pos);
        //cout << "Vertex :" << pos << endl;
        
        //Center Vertex
        addIndex(filled, baseIndex);
        addColor(filled, color);
        
        //First
        addIndex(filled, baseIndex + i + 1);
        addColor(filled, color);
        
        //Second
        if(i == (res - 1)) {
            addIndex(filled, baseIndex + 1);
            addColor(filled, color);
        } else {
            addIndex(filled, baseIndex + i + 2);
            addColor(filled, color);
        }
    }
}
Beispiel #8
0
void AtlasOldMesher::writeCollision(Stream *s)
{
   // First, do the binning. This is a bit gross but, hey, what can you do...
   const U32 gridSize = BIT(gAtlasColTreeDepth-1);
   const U32 gridCount = gridSize * gridSize;

   Vector<U16> bins[gridCount];

   // Track the min/max for the bins.
   S16 binsMax[gridCount];
   S16 binsMin[gridCount];

   // Clear bins.
   for(S32 i=0; i<gridCount; i++)
   {
      binsMax[i] = S16_MIN;
      binsMin[i] = S16_MAX;
   }

   // Get the size of bins (we step in x/y, not in Z).
   Point3F binSize( mBounds.len_x() / F32(gridSize), mBounds.len_y() / F32(gridSize), mBounds.len_z());

   for(S32 i=0; i<gridSize; i++)
   {
      for(S32 j=0; j<gridSize; j++)
      {
         // Figure the bounds for this bin...
         Box3F binBox;

         binBox.minExtents.x = binSize.x * i;
         binBox.minExtents.y = binSize.y * j;
         binBox.minExtents.z = mBounds.minExtents.z - 1.f;

         binBox.maxExtents.x = binSize.x * (i+1);
         binBox.maxExtents.y = binSize.y * (j+1);
         binBox.maxExtents.z = mBounds.maxExtents.z + 1.f;

         Vector<U16> &binList = bins[i * gridSize + j];

         S16 &binMin = binsMin[i * gridSize + j];
         S16 &binMax = binsMax[i * gridSize + j];

         // Now, consider all the triangles in the mesh. Note: we assume a trilist.
         for(S32 v=0; v<mIndices.size(); v+=3)
         {
            // Get the verts.
            const Vert &a = mVerts[mIndices[v+0]];
            const Vert &b = mVerts[mIndices[v+1]];
            const Vert &c = mVerts[mIndices[v+2]];

            // If it's a special, skip it, we don't want to collide with skirts.
            if(a.special ||
               b.special ||
               c.special)
               continue; // I can't stand skirts!

            // Reject anything degenerate...
            if(mIndices[v+0] == mIndices[v+1])
               continue;
            if(mIndices[v+1] == mIndices[v+2])
               continue;
            if(mIndices[v+2] == mIndices[v+0])
               continue;

            // Otherwise, we're good, so consider it for the current bin.
            const Point3F aPos = getVertPos(a);
            const Point3F bPos = getVertPos(b);
            const Point3F cPos = getVertPos(c);

            if(triBoxOverlap(binBox, aPos, bPos, cPos))
            {
               // Got a hit, add it to the list!
               binList.push_back(v);

               // Update the min/max info. This will be TOO BIG if we have a
               // very large triangle! An optimal implementation will do a clip,
               // then update the bin. This is probably ok for the moment.
               S16 hA = mHeight->sample(a.pos);
               S16 hB = mHeight->sample(b.pos);
               S16 hC = mHeight->sample(c.pos);

               if(hA > binMax) binMax = hA;
               if(hB > binMax) binMax = hB;
               if(hC > binMax) binMax = hC;

               if(hA < binMin) binMin = hA;
               if(hB < binMin) binMin = hB;
               if(hC < binMin) binMin = hC;
            }
         }

		 // Limit the triangle count to 16bits.  While primary meshes support more
		 // than that, collision meshes don't.  If we don't catch that here, we'll
		 // see raycasting issues later in Atlas.
		 AssertISV( binList.size() <= 65536,
			 "AtlasOldMesher::writeCollision - too many triangles! (>65536)  Try again with a deeper tree" );

         // Ok, we're all set for this bin...
         AssertFatal(binMin <= binMax,
            "AtlasOldMesher::writeCollision - empty bin, crap!");
      }
   }

   // Next, generate the quadtree.
   FrameAllocatorMarker qtPool;
   const U32 nodeCount = QuadTreeTracer::getNodeCount(gAtlasColTreeDepth);
   S16 *qtMin = (S16*)qtPool.alloc(sizeof(S16) * nodeCount);
   S16 *qtMax = (S16*)qtPool.alloc(sizeof(S16) * nodeCount);

   // We have to recursively generate this from the bins on up. First we copy
   // the bins from earlier, then we do our recursomatic thingummy. (It's
   // actually not recursive.)
   for(S32 i=0; i<gridSize; i++)
   {
      for(S32 j=0; j<gridSize; j++)
      {
         const U32 qtIdx = QuadTreeTracer::getNodeIndex(gAtlasColTreeDepth-1, Point2I(i,j));

         qtMin[qtIdx] = binsMin[i * gridSize + j];
         qtMax[qtIdx] = binsMax[i * gridSize + j];

         AssertFatal(qtMin[qtIdx] <= qtMax[qtIdx],
            "AtlasOldMesher::writeCollision - bad child quadtree node min/max! (negative a)");

      }
   }

   // Alright, now we go up the bins, generating from the four children of each,
   // till we hit the root.

   // For each empty level from bottom to top...
   for(S32 depth = gAtlasColTreeDepth - 2; depth >= 0; depth--)
   {
      // For each square...
      for(S32 i=0; i<BIT(depth); i++)
      for(S32 j=0; j<BIT(depth); j++)
      {
         const U32 curIdx = QuadTreeTracer::getNodeIndex(depth, Point2I(i,j));

         // For each of this square's 4 children...
         for(S32 subI=0; subI<2; subI++)
         for(S32 subJ=0; subJ<2; subJ++)
         {
            const U32 subIdx =
               QuadTreeTracer::getNodeIndex(depth+1, Point2I(i*2+subI,j*2+subJ));

            // As is the child.
            AssertFatal(qtMin[subIdx] <= qtMax[subIdx],
               "AtlasOldMesher::writeCollision - bad child quadtree node min/max! (a)");

            // Update the min and max of the parent.
            if(qtMin[subIdx] < qtMin[curIdx]) qtMin[curIdx] = qtMin[subIdx];
            if(qtMax[subIdx] > qtMax[curIdx]) qtMax[curIdx] = qtMax[subIdx];

            // Make sure we actually contain the child.
            AssertFatal(qtMin[subIdx] >= qtMin[curIdx],
               "AtlasOldMesher::writeCollision - bad quadtree child min during coltree generation!");
            AssertFatal(qtMax[subIdx] <= qtMax[curIdx],
               "AtlasOldMesher::writeCollision - bad quadtree child max during coltree generation!");

            // And that the parent is still valid.
            AssertFatal(qtMin[curIdx] <= qtMax[curIdx],
               "AtlasOldMesher::writeCollision - bad parent quadtree node min/max!");

            // As is the child.
            AssertFatal(qtMin[subIdx] <= qtMax[subIdx],
               "AtlasOldMesher::writeCollision - bad child quadtree node min/max! (b)");

         }
      }
   }

   // Wasn't that fun? Now we have a ready-to-go quadtree.

   // Now write the quadtree, in proper order
   for(S32 i=0; i<nodeCount; i++)
   {
      AssertFatal(qtMin[i] <= qtMax[i], "AtlasOldMesher::writeCollision - invalid quadtree min/max.");
      s->write(qtMin[i]);
      s->write(qtMax[i]);
   }

   s->write(U32(0xb33fd34d));

   // We have to generate...
   // ... the list of triangle offsets for each bin. (Done above!)
   // ... the triangle buffer which stores the offsets for each bin.
   ChunkTriangleBufferGenerator ctbg(gridSize);

   for(S32 i=0; i<gridSize; i++)
      for(S32 j=0; j<gridSize; j++)
         ctbg.insertBinList(Point2I(i,j), bins[i * gridSize + j]);

   // Finally, write the data out.
   ctbg.write(s);
}
double TriMesh::computeEdgeLength(unsigned vert0, unsigned vert1) const
{
    Vec3 p0 = getVertPos(vert0);
    Vec3 p1 = getVertPos(vert1);
    return (p1-p0).norm();
}