void MeshObject::getNextElement(const char* buffer) { switch(buffer[0]) { case PARSED_ELEMENT_VERTEX: switch(buffer[1]) { case PARSED_ELEMENT_TEXTURE: readTexCoord(buffer); break; case PARSED_ELEMENT_NORMAL: readNormal(buffer); break; default: readVertex(buffer); } break; case PARSED_ELEMENT_FACE: readFace(buffer); break; //ignore case PARSED_ELEMENT_SMOOTH: case PARSED_ELEMENT_COMMENT: case PARSED_ELEMENT_MATERIAL: default: //printf("%s",buffer); break; } }
MeshData* LoadObj::readObjFile(std::string pObj) { bool first = true; fstream f(pObj.c_str()); string tmp; if(f) { while(f.eof() != true) { f >> tmp; if(tmp == "v") readVertices(f); if(tmp == "vt") readTexC(f); if(tmp == "vn") readNormal(f); if(tmp == "f") readFaces(f); if(tmp == "mtllib") readMtl(f); if(tmp == "g") readGroup(f); if(f.eof()) break; } } MeshData* data = new MeshData(); data->position = position; data->textureCoordinate = textureCoordinate; data->normal = normal; data->vertices = vertices; data->indices = indices; reset(); return data; }
int Model::readObj(string filename) { ifstream stream(filename); if (stream.is_open()) { string line, chunk; while (stream >> chunk) { getline(stream, line); if (chunk == "v") readVertex(line); else if (chunk == "vn") readNormal(line); else if (chunk == "vt") readTexture(line); else if (chunk == "f") readFace(line); } // If we have normals or texture coordinates, we need to rearrange everything to avoid multiple indices. // TODO: Do this without blowing up the size of the v/n/t buffers. if (nBuffer.size() > 0 || tBuffer.size() > 0) { vector<glm::vec4> vBuffer2; vector<glm::vec3> nBuffer2; vector<glm::vec2> tBuffer2; for (unsigned int i = 0; i < viBuffer.size(); i++) { vBuffer2.push_back(vBuffer[viBuffer[i]]); if (niBuffer.size() > 0) nBuffer2.push_back(nBuffer[niBuffer[i]]); if (tiBuffer.size() > 0) tBuffer2.push_back(tBuffer[tiBuffer[i]]); } vBuffer = vBuffer2; nBuffer = nBuffer2; tBuffer = tBuffer2; } stream.close(); return 0; }
Mesh loadMeshFromObj(const char *filename, float scale) { printf("Attempting to load mesh->from %s\n", filename); std::ifstream filehandle; filehandle.open(filename, std::ios::in); if(filehandle.fail()) { printf("Could not open file.\n"); return Mesh(); } std::vector<std::list<sVertexIndex> > existingVertexTable; std::vector<sVertexIndex> vertexTable; std::vector<Mesh::sFace> faceTable; std::vector<sVec3> positionTable; std::vector<sVec3> normalTable; std::vector<sVec2> texcoordTable; std::string line; std::string name(filename); int sg = 0; clock_t start, end; start = clock(); printf("Reading data... "); while( filehandle.good() && !filehandle.eof() ) { std::getline(filehandle, line); if(line[0] == 'v') { if(line[1] == 't') readTexcoord(line, texcoordTable); else if(line[1] == 'n') readNormal(line, normalTable); else readPosition(line, positionTable, scale); } else if(line[0] == 'f') readFace(line, vertexTable, existingVertexTable, faceTable, sg); else if(line[0] == 's') readSG(line, sg); } Mesh m; fillMesh( m, name, vertexTable, faceTable, positionTable, normalTable, texcoordTable); printf("done!\n"); printf("total vertex count %i\n", vertexTable.size()); printf("total face count %i\n", faceTable.size()); end = clock(); double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; printf("Time taken %3.3fs \n", cpu_time_used); return m; }
std::vector<Mesh> loadMeshesFromObj(const char *filename, float scale) { printf("Attempting to load mesh->from %s\n", filename); std::ifstream filehandle; filehandle.open(filename, std::ios::in); std::vector<Mesh> meshes; if(filehandle.fail()) { printf("Could not open file.\n"); return meshes; } std::vector<std::list<sVertexIndex> > existingVertexTable; std::vector<sVertexIndex> vertexTable; std::vector<Mesh::sFace> faceTable; std::vector<sVec3> positionTable; std::vector<sVec3> normalTable; std::vector<sVec2> texcoordTable; std::string line; std::string name; std::string material; int sg = 0; int count = 0; clock_t start, end; start = clock(); printf("Reading data... "); while( filehandle.good() && !filehandle.eof() ) { std::getline(filehandle, line); if(line[0] == 'v') { if(line[1] == 't') readTexcoord(line, texcoordTable); else if(line[1] == 'n') readNormal(line, normalTable); else readPosition(line, positionTable, scale); } else if(line[0] == 'f') readFace(line, vertexTable, existingVertexTable, faceTable, sg); else if(line[0] == 's') readSG(line, sg); else if(line[0] == 'g') { readG(line, name); } else if(line[0] == 'u') { char str[32]; char mtl[128]; int success = sscanf(line.c_str(), "%s %s", str, mtl); if(success && strcmp(str, "usemtl") == 0) { if(count > 0) { meshes.push_back(Mesh()); fillMesh( meshes[count-1], name, vertexTable, faceTable, positionTable, normalTable, texcoordTable); meshes[count-1].material = material; vertexTable.clear(); faceTable.clear(); existingVertexTable.clear(); } ++count; if(success > 1) material = std::string(mtl); } } } if(count > 0) { meshes.push_back(Mesh()); fillMesh( meshes[count-1], name, vertexTable, faceTable, positionTable, normalTable, texcoordTable); meshes[count-1].material = material; } printf("done!\n"); //printf("total vertex count %i\n", vertexTable.size()); //printf("total face count %i\n", faceTable.size()); end = clock(); double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; printf("Time taken %3.3fs \n", cpu_time_used); //printf("meshes.size() = %i\n", meshes.size()); return meshes; }
void fbxLoader2::processMesh(FbxNode* node) { FbxMesh* mesh = node->GetMesh(); this->readAnimationWeigths(mesh); if(mesh!=NULL && mesh->IsTriangleMesh()) { for (int i = 0; i<mesh->GetControlPointsCount(); i++) { readVertex(mesh, i, &vertex[i]); vertexArray[i].position = D3DXVECTOR3(vertex[i]); } int a = mesh->GetPolygonVertexCount(); for (int i = 0; i<mesh->GetPolygonVertexCount(); i++) { readUV(mesh, i, 0, &uv[i]); readNormal(mesh, i, &normal[i]); indices[i].indice = mesh->GetPolygonVertices()[i]; indices[i].normal1 = normal[i]; indices[i].uv1 = uv[i]; indicesMeshCount++; } } //vertexLists.push_back(vertexArray); indiceLists.push_back(indices); FbxAnimStack* pAnimStack = FbxCast<FbxAnimStack>(scene->GetSrcObject(FBX_TYPE(FbxAnimStack))); int numAnimLayers = pAnimStack->GetMemberCount(FBX_TYPE(FbxAnimLayer)); this->setBindPoseCluster(node); for (int i = 0; i < numAnimLayers; i++) { FbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(FbxAnimLayer), i); FbxAnimCurve* animCv = this->findSkeletonRootBone(scene->GetRootNode())->GetChild(0)->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X); if (animCv) { FbxTimeSpan animationLength; int p = animCv->KeyGetCount(); animCv->GetTimeInterval(animationLength); for(int j = 0; j<animationStructure->GetFramesNumber();j++) { FbxTime timeKey = animCv->KeyGet(j).mTime; //FbxTime interval = (duration/p)*j + animationLength.GetStart(); //int intervalVal = (duration.GetSecondCount()/p)*j + animationLength.GetStart().GetSecondCount(); const FbxTime pTime = animCv->KeyGet(j).mTime; FbxAMatrix pGlobalPos = GetGlobalPosition(node, pTime, scene->GetPose(j)); ComputeSkinDeformation(pGlobalPos, mesh, timeKey, scene->GetPose(j), j); } } } for(int i = 0; i<node->GetChildCount(); i++) { processMesh(node->GetChild(i)); } }
void ArticulatedModel::initOBJ(const std::string& filename, const Preprocess& preprocess) { Stopwatch loadTimer; TextInput::Settings set; set.cppBlockComments = false; set.cppLineComments = false; set.otherCommentCharacter = '#'; set.generateNewlineTokens = true; // Notes on OBJ file format. See also: // // - http://www.martinreddy.net/gfx/3d/OBJ.spec // - http://en.wikipedia.org/wiki/Obj // - http://www.royriggs.com/obj.html // // OBJ indexing is 1-based. // Line breaks are significant. // The first token on a line indicates the contents of the line. // // Faces contain separate indices for normals and texcoords. // We load the raw vertices and then form our own optimized // gl indices from them. // // Negative indices are relative to the last coordinate seen. // Raw arrays with independent indexing, as imported from the file Array<Vector3> rawVertex; Array<Vector3> rawNormal; Array<Vector2> rawTexCoord; // part.geometry.vertexArray[i] = rawVertex[cookVertex[i]]; Array<int> cookVertex; Array<int> cookNormal; Array<int> cookTexCoord; // Put everything into a single part // Convert to a Part Part& part = partArray.next(); part.cframe = CoordinateFrame(); part.name = "root"; part.parent = -1; // v,t,n repeated for each vertex Array<int> faceTempIndex; // Count of errors from mismatched texcoord and vertex int texCoordChanged = 0; int normalChanged = 0; Table<std::string, Material::Ref> materialLibrary; Table<std::string, TriListSpec*> groupTable; TriListSpec* currentTriList = NULL; int numTris = 0; const Matrix3 normalXform = preprocess.xform.upper3x3().transpose().inverse(); const std::string& basePath = FilePath::parent(FileSystem::resolve(filename)); { TextInput ti(filename, set); while (ti.hasMore()) { // Consume comments/newlines while (ti.hasMore() && (ti.peek().type() == Token::NEWLINE)) { // Consume the newline ti.read(); } if (! ti.hasMore()) { break; } // Process one line const std::string& cmd = ti.readSymbol(); if (cmd == "mtllib") { // Specify material library const std::string& mtlFilename = ti.readUntilNewlineAsString(); loadMTL(FilePath::concat(basePath, mtlFilename), materialLibrary, preprocess); } else if (cmd == "g") { // New trilist const std::string& name = ti.readUntilNewlineAsString(); if (! groupTable.containsKey(name)) { currentTriList = new TriListSpec(); currentTriList->name = name; groupTable.set(name, currentTriList); } else { currentTriList = groupTable[name]; } } else if (cmd == "usemtl") { if (currentTriList) { currentTriList->materialName = ti.readUntilNewlineAsString(); } } else if (cmd == "v") { rawVertex.append(readVertex(ti, preprocess.xform)); } else if (cmd == "vt") { // Texcoord Vector2& t = rawTexCoord.next(); t.x = ti.readNumber(); t.y = 1.0f - ti.readNumber(); } else if (cmd == "vn") { // Normal rawNormal.append(readNormal(ti, normalXform)); } else if ((cmd == "f") && currentTriList) { // Face // Read each vertex while (ti.hasMore() && (ti.peek().type() != Token::NEWLINE)) { // Read one 3-part index int v = ti.readNumber(); if (v < 0) { v = rawVertex.size() + 1 + v; } int n = 0; int t = 0; if (ti.peek().type() == Token::SYMBOL) { ti.readSymbol("/"); if (ti.peek().type() == Token::NUMBER) { t = ti.readNumber(); if (t < 0) { t = rawTexCoord.size() + 1 + t; } } if (ti.peek().type() == Token::SYMBOL) { ti.readSymbol("/"); if (ti.peek().type() == Token::NUMBER) { n = ti.readNumber(); if (n < 0) { n = rawNormal.size() + 1 + n; } } } } // Switch to zero-based indexing --v; --n; --t; faceTempIndex.append(v, t, n); } alwaysAssertM(faceTempIndex.size() >= 3*3, "Face with fewer than three vertices in model."); numTris += (faceTempIndex.size()/3) - 2; // The faceTempIndex is now a triangle fan. Convert it to a triangle list and use unique vertices for (int i = 2; i < faceTempIndex.size()/3; ++i) { // Always start with vertex 0 cookVertex.append(faceTempIndex[0]); cookTexCoord.append(faceTempIndex[1]); cookNormal.append(faceTempIndex[2]); // The vertex just before the one we're adding int j = (i - 1) * 3; cookVertex.append(faceTempIndex[j]); cookTexCoord.append(faceTempIndex[j+1]); cookNormal.append(faceTempIndex[j+2]); // The vertex we're adding j = i * 3; cookVertex.append(faceTempIndex[j]); cookTexCoord.append(faceTempIndex[j+1]); cookNormal.append(faceTempIndex[j+2]); // Update the index array to contain the three vertices we just added currentTriList->cpuIndex.append(cookVertex.size() - 3, cookVertex.size() - 2, cookVertex.size() - 1); } faceTempIndex.fastClear(); } // Read until the end of the line while (ti.hasMore() && (ti.read().type() != Token::NEWLINE)); } } debugPrintf("Creating TriLists\n"); // Copy geometry const int N = cookVertex.size(); part.geometry.vertexArray.resize(N); for (int i = 0; i < N; ++i) { part.geometry.vertexArray[i] = rawVertex[cookVertex[i]]; } // Optional normals if (rawNormal.size() > 0) { part.geometry.normalArray.resize(N); for (int i = 0; i < N; ++i) { part.geometry.normalArray[i] = rawNormal[cookNormal[i]]; } } // Optional texcoords if (rawTexCoord.size() > 0) { part.texCoordArray.resize(N); for (int i = 0; i < N; ++i) { part.texCoordArray[i] = rawTexCoord[cookTexCoord[i]]; } } // Create trilists for (Table<std::string, TriListSpec*>::Iterator it = groupTable.begin(); it.hasMore(); ++it) { TriListSpec* s = it->value; Material::Ref material; if (materialLibrary.containsKey(s->materialName)) { material = materialLibrary[s->materialName]; } else { material = Material::createDiffuse(Color3::white() * 0.8f); debugPrintf("Warning: unrecognized material: %s\n", s->materialName.c_str()); } Part::TriList::Ref triList = part.newTriList(material); triList->twoSided = false; triList->indexArray = s->cpuIndex; } groupTable.deleteValues(); groupTable.clear(); debugPrintf("Done loading. %d vertices, %d faces, %d frames\n\n", cookVertex.size(), numTris, N); loadTimer.after("Loading"); }