void Geometry::ShowInformation() const { Debug::Log(QString("Information of the mesh %1:").arg(mName)); Debug::Log(QString(" Number of faces: %1").arg(GetNumFaces())); Debug::Log(QString(" Number of vertices: %1").arg(GetNumVertices())); Debug::Log(QString(" Diameter: %1").arg(mBoundingSphere->GetRadius()*2)); }
HRESULT Mesh::CreateTopologyFromMesh() { HRESULT hr; mVertices = new Vertex[GetNumVertices()]; mFaces = new DWORD[3*GetNumFaces()]; mVertexFaceAdjazency = new std::vector<DWORD>[GetNumVertices()]; FULL_VERTEX *pVertices = NULL; hr = mMesh->LockVertexBuffer(0, (void**)&pVertices); PD(hr, L"lock vertex buffer"); if(FAILED(hr)) return hr; for ( DWORD i = 0; i < mMesh->GetNumVertices(); ++i ) { Vertex vertex; vertex.pos.x = pVertices[i].position.x; vertex.pos.y = pVertices[i].position.y; vertex.pos.z = pVertices[i].position.z; vertex.normal.x = pVertices[i].normal.x; vertex.normal.y = pVertices[i].normal.y; vertex.normal.z = pVertices[i].normal.z; mVertices[i] = vertex; } hr = mMesh->UnlockVertexBuffer(); PD(hr, L"unlock vertex buffer"); if(FAILED(hr)) return hr; DWORD* pIndexBuffer = NULL; hr = mMesh->LockIndexBuffer( 0, ( void** )&pIndexBuffer ); PD(hr, L"lock index buffer"); if(FAILED(hr)) return hr; for( DWORD j = 0; j < GetNumFaces(); j++ ) { mFaces[j*3+0] = pIndexBuffer[j*3+0]; mFaces[j*3+1] = pIndexBuffer[j*3+1]; mFaces[j*3+2] = pIndexBuffer[j*3+2]; mVertexFaceAdjazency[pIndexBuffer[j*3+0]].push_back(j); mVertexFaceAdjazency[pIndexBuffer[j*3+1]].push_back(j); mVertexFaceAdjazency[pIndexBuffer[j*3+2]].push_back(j); } hr = mMesh->UnlockIndexBuffer(); PD(hr, L"unlock index buffer"); if(FAILED(hr)) return hr; }
void SkpModel::print_all_counts(){ std::cout << "Definitions: " << GetNumDefinitions() << "\n"; std::cout << "Instances: " << GetNumInstances() << "\n"; std::cout << "Groups: " << GetNumGroups() << "\n"; std::cout << "Faces: " << GetNumFaces() << "\n"; std::cout << "Images: " << GetNumImages() << "\n"; std::cout << "Edges: " << GetNumEdges() << "\n"; std::cout << "Guides: " << GetNumGuides() << "\n"; std::cout << "Curves: " << GetNumCurves() << "\n"; }
void Geometry::ComputeAreasOfPolygons() { mAreasOfPolygons.fill( 0.0f, GetNumFaces() ); if( mTopology == Triangles ) { for( int i = 0; i < mIndexData.size(); i+=3 ) { mAreasOfPolygons[ i / 3 ] = 0.5f * glm::length( glm::cross( GetVertexByIndexPosition( i + 1 ) - GetVertexByIndexPosition( i ), GetVertexByIndexPosition( i + 2 ) - GetVertexByIndexPosition( i ) ) ); } } }
void RenderWindowControl::updateInfo() { auto model = HonViewerApp::GetViewerApp()->GetModelViewer(); if (!model) return; int numVerts = model->GetNumVertices(); int numFaces = model->GetNumFaces(); int numSubMods = model->GetNumSubModels(); int numBones = model->GetNumBones(); DiString info; info.Format("%d\n%d\n%d\n%d", numVerts, numFaces, numSubMods, numBones); mInfo->setCaption(info.c_str()); }
ParametricSurface::ParametricSurface(int dSampleU, int dSampleV) : iVertexVBO(0), iUvVBO(0), iNormalVBO(0), pVertex(0), pUV(0),pNormal(0), pIndex(0), fMinU(0), fMaxU(0), fMinV(0), fMaxV(0), nSampleU(dSampleU), nSampleV(dSampleV) { pIndex = new unsigned short[GetNumFaces()*3]; // Generate three vertex buffer objects. glGenBuffers(1, &iVertexVBO); glGenBuffers(1, &iUvVBO); glGenBuffers(1, &iNormalVBO); for (int i=0; i<nSampleU-1; i++) { for (int j=0; j<nSampleV-1; j++) { pIndex[ (j*(nSampleU-1)+i)*6 + 0 ] = (unsigned short) (j * nSampleU + i); pIndex[ (j*(nSampleU-1)+i)*6 + 1 ] = (unsigned short) (j * nSampleU + (i+1)); pIndex[ (j*(nSampleU-1)+i)*6 + 2 ] = (unsigned short) ((j+1) * nSampleU + (i+1)); pIndex[ (j*(nSampleU-1)+i)*6 + 3 ] = (unsigned short) (j * nSampleU + i); pIndex[ (j*(nSampleU-1)+i)*6 + 4 ] = (unsigned short) ((j+1) * nSampleU + (i+1)); pIndex[ (j*(nSampleU-1)+i)*6 + 5 ] = (unsigned short) ((j+1) * nSampleU + i); } } }
// Draw shape using OpenGL. void STShape::Draw() { glBegin(GL_TRIANGLES); size_t numFaces = GetNumFaces(); for (size_t ii = 0; ii < numFaces; ++ii) { const Face& face = GetFace(ii); for (size_t jj = 0; jj < 3; ++jj) { Index index = face.GetIndex(jj); const Vertex& vertex = mVertices[index]; glTexCoord2f(vertex.texCoord.x, vertex.texCoord.y); glNormal3f(vertex.normal.x, vertex.normal.y, vertex.normal.z); glVertex3f(vertex.position.x, vertex.position.y, vertex.position.z); } } glEnd(); }
/*! Subdivides the mesh one step, depending on subdividability */ void AdaptiveLoopSubdivisionMesh::Subdivide() { // Create new mesh and copy all the attributes HalfEdgeMesh subDivMesh; subDivMesh.SetTransform(GetTransform()); subDivMesh.SetName(GetName()); subDivMesh.SetColorMap(GetColorMap()); subDivMesh.SetWireframe(GetWireframe()); subDivMesh.SetShowNormals(GetShowNormals()); subDivMesh.SetOpacity(GetOpacity()); if (IsHovering()) subDivMesh.Hover(); if (IsSelected()) subDivMesh.Select(); subDivMesh.mMinCMap = mMinCMap; subDivMesh.mMaxCMap = mMaxCMap; subDivMesh.mAutoMinMax = mAutoMinMax; // loop over each face and create new ones for(unsigned int i=0; i<GetNumFaces(); i++){ // find neighbor faces unsigned int f1, f2, f3; EdgeIterator eit = GetEdgeIterator( f(i).edge ); f1 = eit.Pair().GetEdgeFaceIndex(); eit.Pair(); f2 = eit.Next().Pair().GetEdgeFaceIndex(); eit.Pair(); f3 = eit.Next().Pair().GetEdgeFaceIndex(); unsigned int numNotSubdividable = !Subdividable(f1) + !Subdividable(f2) + !Subdividable(f3); // Do not subdivide if "self" is not subdividable if(!Subdividable(i)){ numNotSubdividable = 3; } std::vector< std::vector <Vector3<float> > > faces; switch(numNotSubdividable){ case 0: // normal subdivision (from LoopSubdivisionMesh) faces = LoopSubdivisionMesh::Subdivide(i); break; case 1: // special case 1 faces = Subdivide1(i); break; case 2: // special case 2 faces = Subdivide2(i); break; case 3: // trivial case, no subdivision, same as if subdividable(fi) == false faces = Subdivide3(i); break; } // add the faces (if any) to subDivMesh for(unsigned int j=0; j<faces.size(); j++){ subDivMesh.AddFace(faces.at(j)); } } // Assign the new mesh *this = AdaptiveLoopSubdivisionMesh(subDivMesh, ++mNumSubDivs); Update(); }
void HalfEdgeMesh::Render() { glEnable(GL_LIGHTING); glMatrixMode(GL_MODELVIEW); // Apply transform glPushMatrix(); // Push modelview matrix onto stack // Convert transform-matrix to format matching GL matrix format // Load transform into modelview matrix glMultMatrixf( mTransform.ToGLMatrix().GetArrayPtr() ); if (mWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Draw geometry glBegin(GL_TRIANGLES); const int numTriangles = GetNumFaces(); for (int i = 0; i < numTriangles; i++){ Face & face = f(i); HalfEdge* edge = &e(face.edge); Vertex & v1 = v(edge->vert); edge = &e(edge->next); Vertex & v2 = v(edge->vert); edge = &e(edge->next); Vertex & v3 = v(edge->vert); if (mVisualizationMode == CurvatureVertex) { glColor3fv(v1.color.GetArrayPtr()); glNormal3fv(v1.normal.GetArrayPtr()); glVertex3fv(v1.pos.GetArrayPtr()); glColor3fv(v2.color.GetArrayPtr()); glNormal3fv(v2.normal.GetArrayPtr()); glVertex3fv(v2.pos.GetArrayPtr()); glColor3fv(v3.color.GetArrayPtr()); glNormal3fv(v3.normal.GetArrayPtr()); glVertex3fv(v3.pos.GetArrayPtr()); } else { glColor3fv(face.color.GetArrayPtr()); glNormal3fv(face.normal.GetArrayPtr()); glVertex3fv(v1.pos.GetArrayPtr()); glVertex3fv(v2.pos.GetArrayPtr()); glVertex3fv(v3.pos.GetArrayPtr()); } } glEnd(); // Mesh normals by courtesy of Richard Khoury if (mShowNormals) { glDisable(GL_LIGHTING); glBegin(GL_LINES); const int numTriangles = GetNumFaces(); for (int i = 0; i < numTriangles; i++){ Face & face = f(i); HalfEdge* edge = &e(face.edge); Vertex & v1 = v(edge->vert); edge = &e(edge->next); Vertex & v2 = v(edge->vert); edge = &e(edge->next); Vertex & v3 = v(edge->vert); Vector3<float> faceStart = (v1.pos + v2.pos + v3.pos) / 3.0f; Vector3<float> faceEnd = faceStart + face.normal*0.1; glColor3f(1,0,0); // Red for face normal glVertex3fv(faceStart.GetArrayPtr()); glVertex3fv(faceEnd.GetArrayPtr()); glColor3f(0,1,0); // Vertex normals in Green glVertex3fv(v1.pos.GetArrayPtr()); glVertex3fv((v1.pos + v1.normal*0.1).GetArrayPtr()); glVertex3fv(v2.pos.GetArrayPtr()); glVertex3fv((v2.pos + v2.normal*0.1).GetArrayPtr()); glVertex3fv(v3.pos.GetArrayPtr()); glVertex3fv((v3.pos + v3.normal*0.1).GetArrayPtr()); } glEnd(); glEnable(GL_LIGHTING); } if (mWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Restore modelview matrix glPopMatrix(); GLObject::Render(); }
void HalfEdgeMesh::Update() { // Calculate and store all differentials and area // First update all face normals and triangle areas for(unsigned int i = 0; i < GetNumFaces(); i++){ f(i).normal = FaceNormal(i); } // Then update all vertex normals and curvature for(unsigned int i = 0; i < GetNumVerts(); i++){ // Vertex normals are just weighted averages mVerts.at(i).normal = VertexNormal(i); } // Then update vertex curvature for(unsigned int i = 0; i < GetNumVerts(); i++){ mVerts.at(i).curvature = VertexCurvature(i); // std::cerr << mVerts.at(i).curvature << "\n"; } // Finally update face curvature for(unsigned int i = 0; i < GetNumFaces(); i++){ f(i).curvature = FaceCurvature(i); } std::cerr << "Area: " << Area() << ".\n"; std::cerr << "Volume: " << Volume() << ".\n"; // Update vertex and face colors if (mVisualizationMode == CurvatureVertex) { std::vector<Vertex>::iterator iter = mVerts.begin(); std::vector<Vertex>::iterator iend = mVerts.end(); float minCurvature = (std::numeric_limits<float>::max)(); float maxCurvature = -(std::numeric_limits<float>::max)(); while (iter != iend) { if (minCurvature > (*iter).curvature) minCurvature = (*iter).curvature; if (maxCurvature < (*iter).curvature) maxCurvature = (*iter).curvature; iter++; } std::cerr << "Mapping color based on vertex curvature with range [" << minCurvature << "," << maxCurvature << "]" << std::endl; iter = mVerts.begin(); while (iter != iend) { (*iter).color = mColorMap->Map((*iter).curvature, minCurvature, maxCurvature); iter++; } } else if (mVisualizationMode == CurvatureFace) { std::vector<Face>::iterator iter = mFaces.begin(); std::vector<Face>::iterator iend = mFaces.end(); float minCurvature = (std::numeric_limits<float>::max)(); float maxCurvature = -(std::numeric_limits<float>::max)(); while (iter != iend) { if (minCurvature > (*iter).curvature) minCurvature = (*iter).curvature; if (maxCurvature < (*iter).curvature) maxCurvature = (*iter).curvature; iter++; } std::cerr << "Mapping color based on face curvature with range [" << minCurvature << "," << maxCurvature << "]" << std::endl; iter = mFaces.begin(); while (iter != iend) { (*iter).color = mColorMap->Map((*iter).curvature, minCurvature, maxCurvature); iter++; } } }
/*! Proceeds to check if the mesh is valid. All indices are inspected and * checked to see that they are initialized. The method checks: mEdges, mFaces and mVerts. * Also checks to see if all verts have a neighborhood using the findNeighbourFaces method. */ void HalfEdgeMesh::Validate() { std::vector<HalfEdge>::iterator iterEdge = mEdges.begin(); std::vector<HalfEdge>::iterator iterEdgeEnd = mEdges.end(); while (iterEdge != iterEdgeEnd) { if ((*iterEdge).face == UNINITIALIZED || (*iterEdge).next == UNINITIALIZED || (*iterEdge).pair == UNINITIALIZED || (*iterEdge).prev == UNINITIALIZED || (*iterEdge).vert == UNINITIALIZED) std::cerr << "HalfEdge " << iterEdge - mEdges.begin() << " not properly initialized" << std::endl; iterEdge++; } std::cerr << "Done with edge check (checked " << GetNumEdges() << " edges)" << std::endl; std::vector<Face>::iterator iterTri = mFaces.begin(); std::vector<Face>::iterator iterTriEnd = mFaces.end(); while (iterTri != iterTriEnd) { if ((*iterTri).edge == UNINITIALIZED) std::cerr << "Tri " << iterTri - mFaces.begin() << " not properly initialized" << std::endl; iterTri++; } std::cerr << "Done with face check (checked " << GetNumFaces() << " faces)" << std::endl; std::vector<Vertex>::iterator iterVertex = mVerts.begin(); std::vector<Vertex>::iterator iterVertexEnd = mVerts.end(); while (iterVertex != iterVertexEnd) { if ((*iterVertex).edge == UNINITIALIZED) std::cerr << "Vertex " << iterVertex - mVerts.begin() << " not properly initialized" << std::endl; iterVertex++; } std::cerr << "Done with vertex check (checked " << GetNumVerts() << " vertices)" << std::endl; std::cerr << "Looping through triangle neighborhood of each vertex... "; iterVertex = mVerts.begin(); iterVertexEnd = mVerts.end(); int emptyCount = 0; std::vector<unsigned int> problemVerts; while (iterVertex != iterVertexEnd) { std::vector<unsigned int> foundFaces = FindNeighborFaces(iterVertex - mVerts.begin()); std::vector<unsigned int> foundVerts = FindNeighborVertices(iterVertex - mVerts.begin()); if (foundFaces.empty() || foundVerts.empty()) emptyCount++; std::set<unsigned int> uniqueFaces(foundFaces.begin(), foundFaces.end()); std::set<unsigned int> uniqueVerts(foundVerts.begin(), foundVerts.end()); if ( foundFaces.size() != uniqueFaces.size() || foundVerts.size() != uniqueVerts.size() ) problemVerts.push_back(iterVertex - mVerts.begin()); iterVertex++; } std::cerr << std::endl << "Done: " << emptyCount << " isolated vertices found" << std::endl; if(problemVerts.size()){ std::cerr << std::endl << "Found " << problemVerts.size() << " duplicate faces in vertices: "; std::copy(problemVerts.begin(), problemVerts.end(), std::ostream_iterator<unsigned int>(std::cerr, ", ")); std::cerr << "\n"; } std::cerr << std::endl << "The mesh has genus " << Genus() << ", and consists of " << Shells() << " shells.\n"; }
void DoPhysicsAlignObject (tObject * objP) { vmsVector desired_upvec; fixang delta_ang, roll_ang; //vmsVector forvec = {0, 0, f1_0}; vmsMatrix temp_matrix; fix d, largest_d=-f1_0; int i, best_side; best_side=0; // bank player according to tSegment orientation //find tSide of tSegment that player is most alligned with for (i=0;i<6;i++) { #ifdef COMPACT_SEGS vmsVector _tv1; GetSideNormal (gameData.segs.segments + objP->nSegment, i, 0, &_tv1); d = VmVecDot (&_tv1, &objP->orient.uVec); #else d = VmVecDot (gameData.segs.segments [objP->nSegment].sides [i].normals, &objP->orient.uVec); #endif if (d > largest_d) {largest_d = d; best_side=i;} } if (floorLevelling) { // old way: used floor's normal as upvec #ifdef COMPACT_SEGS GetSideNormal (gameData.segs.segments + objP->nSegment, 3, 0, &desired_upvec); #else desired_upvec = gameData.segs.segments [objP->nSegment].sides [3].normals [0]; #endif } else // new player leveling code: use normal of tSide closest to our up vec if (GetNumFaces (&gameData.segs.segments [objP->nSegment].sides [best_side])==2) { #ifdef COMPACT_SEGS vmsVector normals [2]; GetSideNormals (&gameData.segs.segments [objP->nSegment], best_side, &normals [0], &normals [1]); desired_upvec.x = (normals [0].x + normals [1].x) / 2; desired_upvec.y = (normals [0].y + normals [1].y) / 2; desired_upvec.z = (normals [0].z + normals [1].z) / 2; VmVecNormalize (&desired_upvec); #else tSide *s = &gameData.segs.segments [objP->nSegment].sides [best_side]; desired_upvec.x = (s->normals [0].x + s->normals [1].x) / 2; desired_upvec.y = (s->normals [0].y + s->normals [1].y) / 2; desired_upvec.z = (s->normals [0].z + s->normals [1].z) / 2; VmVecNormalize (&desired_upvec); #endif } else #ifdef COMPACT_SEGS GetSideNormal (&gameData.segs.segments [objP->nSegment], best_side, 0, &desired_upvec); #else desired_upvec = gameData.segs.segments [objP->nSegment].sides [best_side].normals [0]; #endif if (labs (VmVecDot (&desired_upvec, &objP->orient.fVec)) < f1_0/2) { fixang save_delta_ang; vmsAngVec tangles; VmVector2Matrix (&temp_matrix, &objP->orient.fVec, &desired_upvec, NULL); save_delta_ang = delta_ang = VmVecDeltaAng (&objP->orient.uVec, &temp_matrix.uVec, &objP->orient.fVec); delta_ang += objP->mType.physInfo.turnRoll; if (abs (delta_ang) > DAMP_ANG) { vmsMatrix rotmat, new_pm; roll_ang = FixMul (gameData.time.xFrame, ROLL_RATE); if (abs (delta_ang) < roll_ang) roll_ang = delta_ang; else if (delta_ang<0) roll_ang = -roll_ang; tangles.p = tangles.h = 0; tangles.b = roll_ang; VmAngles2Matrix (&rotmat, &tangles); VmMatMul (&new_pm, &objP->orient, &rotmat); objP->orient = new_pm; } else floorLevelling=0; } }
// Compute or re-compute the per-vertex normals for this shape // using the normals of adjoining faces. void STShape::GenerateNormals() { // // We compute the normals for hte mesh as the area-weighted average of // the normals of incident faces. This is a simple technique to implement, // but other techniques are possible. // // // Initialize all the normals to zero. // size_t numVertices = GetNumVertices(); for (size_t ii = 0; ii < numVertices; ++ii) { mVertices[ii].normal = STVector3::Zero; } // // Loop over faces, adding the normal of each face // to the vertices that use it. // size_t numFaces = GetNumFaces(); for (size_t ii = 0; ii < numFaces; ++ii) { const Face& face = mFaces[ii]; Vertex& v0 = mVertices[face.GetIndex(0)]; Vertex& v1 = mVertices[face.GetIndex(1)]; Vertex& v2 = mVertices[face.GetIndex(2)]; // // We compute a cross-product of two triangle edges. // This direction of this vector will be the normal // direction, while the magnitude will be twice // the triangle area. We can thus use this directly // as a weighted normal. // STVector3 edge1 = v1.position - v0.position; STVector3 edge2 = v2.position - v0.position; STVector3 weightedNormal = STVector3::Cross(edge1, edge2); // // We now add the face normal to the normal stored // in each of the vertices using the face. // v0.normal += weightedNormal; v1.normal += weightedNormal; v2.normal += weightedNormal; } // // Each vertex now has an area-weighted normal. We need to // normalize them to turn them into correct unit-lenght // normal vectors for rendering. // for (size_t ii = 0; ii < numVertices; ++ii) { // // Check that the weighted normal is non-zero so that // we don't divide by zero when normalizing. // Vertex& vertex = mVertices[ii]; if (vertex.normal.LengthSq() > 0.0f) { vertex.normal.Normalize(); } } }