void terrain::setTerrainSize(btVector3 size) { if(size == m_terrainSize) return; btVector3 modscale = (size - m_terrainSize) / m_terrainSize; // the difference between the new and old size divided by the old size if(m_terrainSize.z() == 0) modscale.setZ(size.z()); // incase of NAN m_terrainMinHeight = m_terrainMaxHeight = 0; for(int i=0; i<m_terrainVertexCount; i++){ m_terrainVerts[i].x += modscale.x() * m_terrainVerts[i].x; m_terrainVerts[i].y += modscale.y() * m_terrainVerts[i].y; if(m_terrainSize.z() == 0) m_terrainVerts[i].z = size.z(); else m_terrainVerts[i].z += modscale.z() * m_terrainVerts[i].z; if(m_terrainVerts[i].z > m_terrainMaxHeight) m_terrainMaxHeight = m_terrainVerts[i].z; else if(m_terrainVerts[i].z < m_terrainMinHeight) m_terrainMinHeight = m_terrainVerts[i].z; } buildNormals(); m_terrainSize = size; tTool->setSize(m_terrainSize); m_parent->printText(QString("Terrain Resized %1,%2,%3").arg(m_terrainSize.x()).arg(m_terrainSize.y()).arg(m_terrainSize.z())); this->terrainRefresh(); emit newTerrain(); }
void MD5Model::animate(float dt) { // sanity check #1 if (currAnim < 0 || currAnim >= int(anims.size()) || !anims[currAnim]) throw Exception("MD5Model::animate(): currAnim is invalid"); Anim *anim = anims[currAnim]; // sanity check #2 if (currFrame < 0 || currFrame >= int(anim->numFrames)) throw Exception("MD5Model::animate(): currFrame is invalid"); // compute index of next frame int nextFrameIndex = currFrame >= anim->numFrames - 1 ? 0 : currFrame + 1; // update animation time animTime += dt*float(anim->frameRate); if (animTime > 1.0f) { while (animTime > 1.0f) animTime -= 1.0f; //setFrame(nextFrameIndex); currFrame = nextFrameIndex; nextFrameIndex = currFrame >= anim->numFrames - 1 ? 0 : currFrame + 1; } // make sure size of storage for interpolated frame is correct if (int(interpFrame.joints.size()) != numJoints) interpFrame.joints.resize(numJoints); ///// now interpolate between the two frames ///// Frame &frame = anim->frames[currFrame], &nextFrame = anim->frames[nextFrameIndex]; // interpolate between the joints of the current frame and those of the next // frame and store them in interpFrame for (int i = 0; i < numJoints; i++) { Joint &interpJoint = interpFrame.joints[i]; // linearly interpolate between joint positions float *pos1 = frame.joints[i].pos, *pos2 = nextFrame.joints[i].pos; interpJoint.pos[0] = pos1[0] + animTime*(pos2[0] - pos1[0]); interpJoint.pos[1] = pos1[1] + animTime*(pos2[1] - pos1[1]); interpJoint.pos[2] = pos1[2] + animTime*(pos2[2] - pos1[2]); interpJoint.quat = slerp(frame.joints[i].quat, nextFrame.joints[i].quat, animTime); } buildVerts(interpFrame); buildNormals(); calculateRenderData(); }
// the center of editing takes place at HERE // raise terrain DIR = 1, lower terrain DIR = -1 void terrain::terrainEdit(btVector3 here, int dir) { float area = tTool->diameter(); float amount = tTool->increment(); if(area <= 0 || amount <= 0) return; amount *= dir; // determine the direction of editing, up or down float xp = here.x(); // make sure the X location of the edit is over the terrain if(xp < 0) xp = 0; else if(xp > m_terrainSize.x()) xp = m_terrainSize.x(); float yp = here.y(); // make sure the Y location of the edit is over the terrain if(yp < 0) yp = 0; else if(yp > m_terrainSize.y()) yp = m_terrainSize.y(); for(int i=0; i<m_terrainVertexCount; i++) // loop through the terrain vertex array { float x = (i % m_pixelSize.width()) * m_terrainSize.x()/m_pixelSize.width();// get the X and Y incides of the terrain vertices float y = (i / m_pixelSize.width()) * m_terrainSize.y()/m_pixelSize.height(); float xd = xp - x; float yd = yp - y; float d = (float)sqrt((xd*xd) + (yd*yd)); // calculate the diameter of the area float a = (m_terrainVerts[i].z + amount) - (amount*(d / area)); // calculate the new height of the vertex if((dir == 1 && a > m_terrainVerts[i].z) || (dir == -1 && a < m_terrainVerts[i].z)) { m_terrainVerts[i].z = a; if(a > m_terrainMaxHeight) m_terrainMaxHeight = a; else if(a < m_terrainMinHeight) m_terrainMinHeight = a; float avgheight = (m_terrainMaxHeight + m_terrainMinHeight)/2.0; if(a > avgheight) m_terrainColors[i].x = 0.8; // set red color else m_terrainColors[i].x = 0.; m_terrainColors[i].y = 0.; // set green color if(a < avgheight) m_terrainColors[i].z = 0.8; // set blue color else m_terrainColors[i].z = 0.; } } buildNormals(); this->terrainRefresh(); m_terrainModified = true; }
void RMesh::mesh::cube(QString filename, mesh &m) { assert( &m != NULL ); // float plus = 0.5; // float minus = -plus; float plus = 2.5; float minus = 1.0; m.vertices.reserve(8); m.polygons.reserve(12); // initialize points m.vertices.push_back( Primitives::Point3d( minus, plus, plus )); m.vertices.push_back( Primitives::Point3d( minus, plus, minus )); m.vertices.push_back( Primitives::Point3d( plus, plus, minus )); m.vertices.push_back( Primitives::Point3d( plus, plus, plus )); m.vertices.push_back( Primitives::Point3d( minus, minus, plus )); m.vertices.push_back( Primitives::Point3d( minus, minus, minus )); m.vertices.push_back( Primitives::Point3d( plus, minus, minus )); m.vertices.push_back( Primitives::Point3d( plus, minus, plus )); m.polygons.push_back( MeshPolygon( 2, 1, 3 )); m.polygons.push_back( MeshPolygon( 3, 1, 0 )); m.polygons.push_back( MeshPolygon( 1, 5, 0 )); m.polygons.push_back( MeshPolygon( 0, 5, 4 )); m.polygons.push_back( MeshPolygon( 1, 2, 5 )); m.polygons.push_back( MeshPolygon( 5, 2, 6 )); m.polygons.push_back( MeshPolygon( 3, 0, 7 )); m.polygons.push_back( MeshPolygon( 7, 0, 4 )); m.polygons.push_back( MeshPolygon( 7, 2, 3 )); m.polygons.push_back( MeshPolygon( 2, 7, 6 )); m.polygons.push_back( MeshPolygon( 7, 5, 6 )); m.polygons.push_back( MeshPolygon( 5, 7, 4 )); buildNormals(m); vector < Primitives::Point3d > points_for_bbox; for (int i = 0; i < m.vertices.size(); ++i) { points_for_bbox.push_back( Primitives::Point3d( m.vertices[i][0], m.vertices[i][1], m.vertices[i][2] )); } m.bbox = Primitives::BBoxD(); m.bbox.Set(points_for_bbox); std::cout << "bbox center : " << m.bbox.Center()[0] << ", " << m.bbox.Center()[1] << ", " << m.bbox.Center()[1] << endl; }
void MD5Model::loadMesh(const char *filename) { // sanity check if (!filename) throw Exception("MD5Model::loadMesh(): filename is NULL"); // attempt to open file for reading std::ifstream fin(filename, std::ifstream::in); // was open successful? if (!fin.is_open()) { std::string msg = std::string("MD5Model::loadMesh(): unable to open ") + std::string(filename) + std::string(" for reading"); throw Exception(msg); } // read in file version std::string str; getNextToken(fin, &str); // token must read "MD5Version" if (str != "MD5Version") throw Exception("MD5Model::loadMesh(): expected 'MD5Version'"); // get version # int ver = readInt(fin); // must be version 10 if (ver != 10) throw Exception("MD5Model::loadMesh(): MD5Version must be 10"); // clear any data before reading file clear(); // read in all of the MD5Model elements readElements(fin); // close input file (should be done destructor anyway...) fin.close(); // calculate vertex positions and normals from information in joints // 模型pose姿势中,多个骨骼节点初始位置+连续weight位置变换(骨骼节点开始的位置 + weightPos经过joint四元数旋转的位置)* 权重 的结果作为顶点的位置。 buildVerts(); // 直接叉乘,规范化,将单位面法向量作为每个顶点的法向量 buildNormals(); createRenderData(); }
void MD5Model::setFrame(int frameIndex) { // sanity check #1 if (anims.size() == 0 || currAnim < 0) throw Exception("MD5Model::setFrame(): no animation has beens set"); // sanity check #2 if (frameIndex < 0 || !anims[currAnim] || anims[currAnim]->numFrames <= 0 || anims[currAnim]->numFrames <= frameIndex) throw Exception("MD5Model::setFrame(): frame index is invalid"); buildVerts(anims[currAnim]->frames[frameIndex]); buildNormals(); calculateRenderData(); currFrame = frameIndex; animTime = 0.0f; }
// creates a new triangle based terrain mesh, be sure heightData is large enough // to fit the world which must be set prior. This function fills the proper arrays // for both OpenGL and Bullet. void terrain::terrainCreateMesh(unsigned int *heightData) { int i,j,k; btVector3 scale; int xWorld = m_pixelSize.width(); int yWorld = m_pixelSize.height(); scale.setX(m_terrainSize.x() / m_pixelSize.width()); scale.setY(m_terrainSize.y() / m_pixelSize.height()); if(heightData != NULL) scale.setZ(m_terrainSize.z() / (float)heightData[m_terrainVertexCount]); else scale.setZ(1); m_terrainVertexCount = xWorld * yWorld; // calculate the number of verticies m_terrainTriangleCount = (xWorld-1) * (yWorld-1)*2; // calculate the number of triangles // allocate new data arrays m_terrainVerts = new Vertex[m_terrainVertexCount]; m_terrainColors = new Vertex[m_terrainVertexCount]; m_terrainNormals = new Vertex[m_terrainVertexCount]; m_terrainTriangles = new Triangle[m_terrainTriangleCount]; m_terrainMaxHeight = m_terrainSize.z(); m_terrainMinHeight = 0; // generate the vertices for the triangle mesh // This sets the proper coordinates for the vertices that // will make up the terrain triangle mesh. The color of // each vertex is based on the height of from the BMP for(i=0; i<m_terrainVertexCount; i++) { m_terrainVerts[i].x = (i % xWorld) * scale.x(); m_terrainVerts[i].y = (i / xWorld) * scale.y(); if(heightData != NULL) m_terrainVerts[i].z = heightData[i] * scale.z(); // get the height from the image data and scale it else m_terrainVerts[i].z = m_terrainSize.z(); m_terrainColors[i].x = 0.7 * m_terrainVerts[i].z / m_terrainMaxHeight; // set the color based on the terrain height m_terrainColors[i].y = 0.7 * m_terrainVerts[i].z / m_terrainMaxHeight; m_terrainColors[i].z = 0.7 * m_terrainVerts[i].z / m_terrainMaxHeight; } // generate the indices which point to the vertices of the triangle mesh // the m_terrainTriangle array is used to tell OpenGL and Bullet // what vertices make up each triangle. This is done so the same vertices // can be re-used for different triangles k=0; for(j=1;j<yWorld;j++) { for(i=1;i<xWorld;i++) { int ind1 = ((j-1) * xWorld) + (i-1); int ind2 = (j * xWorld) + (i-1); int ind3 = ((j-1) * xWorld) + i; int ind4 = (j * xWorld) + i; // low triangle m_terrainTriangles[k].v1 = ind1; m_terrainTriangles[k].v2 = ind3; m_terrainTriangles[k].v3 = ind2; // high triangle m_terrainTriangles[k+1].v1 = ind2; m_terrainTriangles[k+1].v2 = ind3; m_terrainTriangles[k+1].v3 = ind4; k += 2; } } buildNormals(); }
// Main function for fast curving void HighOrderMeshFastCurving(GModel *gm, FastCurvingParameters &p) { double t1 = Cpu(); Msg::StatusBar(true, "Optimizing high order mesh..."); std::vector<GEntity*> allEntities; gm->getEntities(allEntities); // Compute vert. -> elt. connectivity Msg::Info("Computing connectivity..."); std::map<MVertex*, std::vector<MElement *> > vertex2elements; for (int iEnt = 0; iEnt < allEntities.size(); ++iEnt) calcVertex2Elements(p.dim, allEntities[iEnt], vertex2elements); // Get BL field (if any) BoundaryLayerField *blf = getBLField(gm); // Build multimap of each geometric entity to its boundaries std::multimap<GEntity*,GEntity*> entities; if (blf) { // BF field? for (int iEnt = 0; iEnt < allEntities.size(); ++iEnt) { GEntity* &entity = allEntities[iEnt]; if (entity->dim() == p.dim && (!p.onlyVisible || entity->getVisibility())) // Consider only "domain" entities if (p.dim == 2) { // "Domain" face? std::list<GEdge*> edges = entity->edges(); for (std::list<GEdge*>::iterator itEd = edges.begin(); itEd != edges.end(); itEd++) // Loop over model boundary edges if (blf->isEdgeBL((*itEd)->tag())) // Already skip model edge if no BL there entities.insert(std::pair<GEntity*,GEntity*>(entity, *itEd)); } else if (p.dim == 3) { // "Domain" region? std::list<GFace*> faces = entity->faces(); for (std::list<GFace*>::iterator itF = faces.begin(); itF != faces.end(); itF++) // Loop over model boundary faces if (blf->isFaceBL((*itF)->tag())) // Already skip model face if no BL there entities.insert(std::pair<GEntity*,GEntity*>(entity, *itF)); } } } else { // No BL field for (int iEnt = 0; iEnt < allEntities.size(); ++iEnt) { GEntity* &entity = allEntities[iEnt]; if (entity->dim() == p.dim-1 && (!p.onlyVisible || entity->getVisibility())) // Consider boundary entities entities.insert(std::pair<GEntity*,GEntity*>(0, entity)); } } // Build normals if necessary std::map<GEntity*, std::map<MVertex*, SVector3> > normVertEnt; // Normal to each vertex for each geom. entity if (!blf) { Msg::Warning("Boundary layer data not found, trying to detect columns"); buildNormals(vertex2elements, entities, p, normVertEnt); } // Loop over geometric entities for (std::multimap<GEntity*,GEntity*>::iterator itBE = entities.begin(); itBE != entities.end(); itBE++) { GEntity *domEnt = itBE->first, *bndEnt = itBE->second; BoundaryLayerColumns *blc = 0; if (blf) { Msg::Info("Curving elements for entity %d bounding entity %d...", bndEnt->tag(), domEnt->tag()); if (p.dim == 2) blc = domEnt->cast2Face()->getColumns(); else if (p.dim == 3) blc = domEnt->cast2Region()->getColumns(); else Msg::Error("Fast curving implemented only in dim. 2 and 3"); } else Msg::Info("Curving elements for boundary entity %d...", bndEnt->tag()); std::map<MVertex*, SVector3> &normVert = normVertEnt[bndEnt]; curveMeshFromBnd(vertex2elements, normVert, blc, bndEnt, p); } double t2 = Cpu(); Msg::StatusBar(true, "Done curving high order mesh (%g s)", t2-t1); }