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(); }
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::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; }
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 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 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; } } }