void ConvexPolyhedron3<Real>::Create (const V3Array& rakPoint, const IArray& raiConnect) { assert( rakPoint.size() >= 4 && raiConnect.size() >= 4 ); int iVQuantity = (int)rakPoint.size(); int iTQuantity = (int)raiConnect.size()/3; int iEQuantity = iVQuantity + iTQuantity - 2; Reset(iVQuantity,iEQuantity,iTQuantity); m_akPoint = rakPoint; // Copy polyhedron points into vertex array. Compute centroid for use in // making sure the triangles are counterclockwise oriented when viewed // from the outside. ComputeCentroid(); // get polyhedron edge and triangle information for (int iT = 0, iIndex = 0; iT < iTQuantity; iT++) { // get vertex indices for triangle int iV0 = raiConnect[iIndex++]; int iV1 = raiConnect[iIndex++]; int iV2 = raiConnect[iIndex++]; // make sure triangle is counterclockwise Vector3<Real>& rkV0 = m_akPoint[iV0]; Vector3<Real>& rkV1 = m_akPoint[iV1]; Vector3<Real>& rkV2 = m_akPoint[iV2]; Vector3<Real> kDiff = m_kCentroid - rkV0; Vector3<Real> kE1 = rkV1 - rkV0; Vector3<Real> kE2 = rkV2 - rkV0; Vector3<Real> kNormal = kE1.Cross(kE2); Real fLength = kNormal.Length(); if ( fLength > Math<Real>::EPSILON ) { kNormal /= fLength; } else { kNormal = kDiff; kNormal.Normalize(); } Real fDistance = kNormal.Dot(kDiff); if ( fDistance < (Real)0.0 ) { // triangle is counterclockwise Insert(iV0,iV1,iV2); } else { // triangle is clockwise Insert(iV0,iV2,iV1); } } UpdatePlanes(); }
//---------------------------------------------------------------------------- void ExtractTrilinear::MakeUnique (V3Array& rkVA, T3Array& rkTA) { int iVQuantity = (int)rkVA.size(), iTQuantity = (int)rkTA.size(); if ( iVQuantity == 0 || iTQuantity == 0 ) return; // use a hash table to generate unique storage V3Map kVMap; V3MapIterator pkVIter; for (int iV = 0, iNextVertex = 0; iV < iVQuantity; iV++) { // keep only unique vertices pair<V3MapIterator,bool> kResult = kVMap.insert( make_pair(rkVA[iV],iNextVertex)); if ( kResult.second == true ) iNextVertex++; } // use a hash table to generate unique storage T3Map kTMap; T3MapIterator pkTIter; for (int iT = 0, iNextTriangle = 0; iT < iTQuantity; iT++) { // replace old vertex indices by new ones Triangle3& rkTri = rkTA[iT]; pkVIter = kVMap.find(rkVA[rkTri.i0]); assert( pkVIter != kVMap.end() ); rkTri.i0 = pkVIter->second; pkVIter = kVMap.find(rkVA[rkTri.i1]); assert( pkVIter != kVMap.end() ); rkTri.i1 = pkVIter->second; pkVIter = kVMap.find(rkVA[rkTri.i2]); assert( pkVIter != kVMap.end() ); rkTri.i2 = pkVIter->second; // keep only unique triangles pair<T3MapIterator,bool> kResult = kTMap.insert( make_pair(rkTri,iNextTriangle)); if ( kResult.second == true ) iNextTriangle++; } // pack the vertices rkVA.resize(kVMap.size()); for (pkVIter = kVMap.begin(); pkVIter != kVMap.end(); pkVIter++) rkVA[pkVIter->second] = pkVIter->first; // pack the triangles rkTA.resize(kTMap.size()); for (pkTIter = kTMap.begin(); pkTIter != kTMap.end(); pkTIter++) rkTA[pkTIter->second] = pkTIter->first; }
bool ConvexPolyhedron3<Real>::ComputeSilhouette (V3Array& rkTerminator, const Vector3<Real>& rkEye, const Plane3<Real>& rkPlane, const Vector3<Real>& rkU, const Vector3<Real>& rkV, V2Array& rkSilhouette) { Real fEDist = rkPlane.DistanceTo(rkEye); // assert: fEDist > 0 // closest planar point to E is K = E-dist*N Vector3<Real> kClosest = rkEye - fEDist*rkPlane.GetNormal(); // project polyhedron points onto plane for (int i = 0; i < (int)rkTerminator.size(); i++) { Vector3<Real>& rkPoint = rkTerminator[i]; Real fVDist = rkPlane.DistanceTo(rkPoint); if ( fVDist >= fEDist ) { // cannot project vertex onto plane return false; } // compute projected point Q Real fRatio = fEDist/(fEDist-fVDist); Vector3<Real> kProjected = rkEye + fRatio*(rkPoint - rkEye); // compute (x,y) so that Q = K+x*U+y*V+z*N Vector3<Real> kDiff = kProjected - kClosest; rkSilhouette.push_back(Vector2<Real>(rkU.Dot(kDiff),rkV.Dot(kDiff))); } return true; }
//---------------------------------------------------------------------------- void ExtractTrilinear::ExtractContour (float fLevel, V3Array& rkVA, T3Array& rkTA) { rkVA.clear(); rkTA.clear(); for (int iZ = 0; iZ < m_iZBound-1; iZ++) { for (int iY = 0; iY < m_iYBound-1; iY++) { for (int iX = 0; iX < m_iXBound-1; iX++) { // get vertices on edges of box (if any) VETable kTable; int iType = GetVertices(fLevel,iX,iY,iZ,kTable); if ( iType != 0 ) { // get edges on faces of box GetXMinEdges(iX,iY,iZ,iType,kTable); GetXMaxEdges(iX,iY,iZ,iType,kTable); GetYMinEdges(iX,iY,iZ,iType,kTable); GetYMaxEdges(iX,iY,iZ,iType,kTable); GetZMinEdges(iX,iY,iZ,iType,kTable); GetZMaxEdges(iX,iY,iZ,iType,kTable); // ear-clip the wireframe mesh kTable.RemoveTriangles(rkVA,rkTA); } } } } }
//---------------------------------------------------------------------------- void VETable::RemoveTriangles (V3Array& rkVA, T3Array& rkTA) { // ear-clip the wireframe to get the triangles Triangle3 kTri; while ( Remove(kTri) ) { int iV0 = (int)rkVA.size(), iV1 = iV0+1, iV2 = iV1+1; rkTA.push_back(Triangle3(iV0,iV1,iV2)); const Vertex& rkV0 = m_akVertex[kTri.i0]; const Vertex& rkV1 = m_akVertex[kTri.i1]; const Vertex& rkV2 = m_akVertex[kTri.i2]; rkVA.push_back(Vertex3(rkV0.m_fX,rkV0.m_fY,rkV0.m_fZ)); rkVA.push_back(Vertex3(rkV1.m_fX,rkV1.m_fY,rkV1.m_fZ)); rkVA.push_back(Vertex3(rkV2.m_fX,rkV2.m_fY,rkV2.m_fZ)); } }
void ConvexPolyhedron3<Real>::Create (const V3Array& rakPoint, const IArray& raiConnect, const PArray& rakPlane) { assert( rakPoint.size() >= 4 && raiConnect.size() >= 4 ); int iVQuantity = (int)rakPoint.size(); int iTQuantity = (int)raiConnect.size()/3; int iEQuantity = iVQuantity + iTQuantity - 2; Reset(iVQuantity,iEQuantity,iTQuantity); m_akPoint = rakPoint; m_akPlane = rakPlane; // Copy polyhedron points into vertex array. Compute centroid for use in // making sure the triangles are counterclockwise oriented when viewed // from the outside. ComputeCentroid(); // get polyhedron edge and triangle information for (int iT = 0, iIndex = 0; iT < iTQuantity; iT++) { // get vertex indices for triangle int iV0 = raiConnect[iIndex++]; int iV1 = raiConnect[iIndex++]; int iV2 = raiConnect[iIndex++]; Real fDistance = m_akPlane[iT].DistanceTo(m_kCentroid); if ( fDistance > (Real)0.0 ) { // triangle is counterclockwise Insert(iV0,iV1,iV2); } else { // triangle is clockwise Insert(iV0,iV2,iV1); } } }
void ConvexPolyhedron3<Real>::ComputeTerminator (const Vector3<Real>& rkEye, V3Array& rkTerminator) { // temporary storage for signed distances from eye to triangles int iTQuantity = m_akTriangle.GetQuantity(); vector<Real> afDistance(iTQuantity); int i, j; for (i = 0; i < iTQuantity; i++) afDistance[i] = Math<Real>::MAX_REAL; // Start a search for a front-facing triangle that has an adjacent // back-facing triangle or for a back-facing triangle that has an // adjacent front-facing triangle. int iTCurrent = 0; MTTriangle* pkTCurrent = &m_akTriangle[iTCurrent]; Real fTriDist = GetDistance(rkEye,iTCurrent,afDistance); int iEFirst = -1; for (i = 0; i < iTQuantity; i++) { // Check adjacent neighbors for edge of terminator. Such an // edge occurs if the signed distance changes sign. int iMinIndex = -1; Real fMinAbsDist = Math<Real>::MAX_REAL; Real afAdjDist[3]; for (j = 0; j < 3; j++) { afAdjDist[j] = GetDistance(rkEye,pkTCurrent->Adjacent(j), afDistance); if ( IsNegativeProduct(fTriDist,afAdjDist[j]) ) { iEFirst = pkTCurrent->Edge(j); break; } Real fAbsDist = Math<Real>::FAbs(afAdjDist[j]); if ( fAbsDist < fMinAbsDist ) { fMinAbsDist = fAbsDist; iMinIndex = j; } } if ( j < 3 ) break; // First edge not found during this iteration. Move to adjacent // triangle whose distance is smallest of all adjacent triangles. iTCurrent = pkTCurrent->Adjacent(iMinIndex); pkTCurrent = &m_akTriangle[iTCurrent]; fTriDist = afAdjDist[iMinIndex]; } assert( i < iTQuantity ); MTEdge& rkEFirst = m_akEdge[iEFirst]; rkTerminator.push_back(m_akPoint[GetVLabel(rkEFirst.Vertex(0))]); rkTerminator.push_back(m_akPoint[GetVLabel(rkEFirst.Vertex(1))]); // walk along the terminator int iVFirst = rkEFirst.Vertex(0); int iV = rkEFirst.Vertex(1); int iE = iEFirst; int iEQuantity = m_akEdge.GetQuantity(); for (i = 0; i < iEQuantity; i++) { // search all edges sharing the vertex for another terminator edge int j, jMax = m_akVertex[iV].GetEdgeQuantity(); for (j = 0; j < m_akVertex[iV].GetEdgeQuantity(); j++) { int iENext = m_akVertex[iV].GetEdge(j); if ( iENext == iE ) continue; Real fDist0 = GetDistance(rkEye,m_akEdge[iENext].GetTriangle(0), afDistance); Real fDist1 = GetDistance(rkEye,m_akEdge[iENext].GetTriangle(1), afDistance); if ( IsNegativeProduct(fDist0,fDist1) ) { if ( m_akEdge[iENext].GetVertex(0) == iV ) { iV = m_akEdge[iENext].GetVertex(1); rkTerminator.push_back(m_akPoint[GetVLabel(iV)]); if ( iV == iVFirst ) return; } else { iV = m_akEdge[iENext].GetVertex(0); rkTerminator.push_back(m_akPoint[GetVLabel(iV)]); if ( iV == iVFirst ) return; } iE = iENext; break; } } assert( j < jMax ); } assert( i < iEQuantity ); }
//---------------------------------------------------------------------------- void ExtractTrilinear::ComputeNormals (const V3Array& rkVA, const T3Array& rkTA, V3Array& rkNA) { // maintain a running sum of triangle normals at each vertex int iVQuantity = (int)rkVA.size(), iTQuantity = (int)rkTA.size(); rkNA.resize(iVQuantity); int i, j; for (i = 0; i < iVQuantity; i++) { rkNA[i].x = 0.0f; rkNA[i].y = 0.0f; rkNA[i].z = 0.0f; } for (i = 0, j = 0; i < iTQuantity; i++) { const Triangle3& rkT = rkTA[i]; Vertex3 kV0 = rkVA[rkT.i0]; Vertex3 kV1 = rkVA[rkT.i1]; Vertex3 kV2 = rkVA[rkT.i2]; // construct triangle normal float fEX1 = kV1.x - kV0.x; float fEY1 = kV1.y - kV0.y; float fEZ1 = kV1.z - kV0.z; float fEX2 = kV2.x - kV0.x; float fEY2 = kV2.y - kV0.y; float fEZ2 = kV2.z - kV0.z; float fNX = fEY1*fEZ2 - fEY2*fEZ1; float fNY = fEZ1*fEX2 - fEZ2*fEX1; float fNZ = fEX1*fEY2 - fEX2*fEY1; // maintain the sum of normals at each vertex rkNA[rkT.i0].x += fNX; rkNA[rkT.i0].y += fNY; rkNA[rkT.i0].z += fNZ; rkNA[rkT.i1].x += fNX; rkNA[rkT.i1].y += fNY; rkNA[rkT.i1].z += fNZ; rkNA[rkT.i2].x += fNX; rkNA[rkT.i2].y += fNY; rkNA[rkT.i2].z += fNZ; } // The normal vector storage was used to accumulate the sum of // triangle normals. Now these vectors must be rescaled to be // unit length. for (i = 0; i < iVQuantity; i++) { Vertex3& rkV = rkNA[i]; float fLength = sqrtf(rkV.x*rkV.x + rkV.y*rkV.y + rkV.z*rkV.z); if ( fLength > 1e-08f ) { float fInvLength = 1.0f/fLength; rkV.x *= fInvLength; rkV.y *= fInvLength; rkV.z *= fInvLength; } else { rkV.x = 0.0f; rkV.y = 0.0f; rkV.z = 0.0f; } } }