From 0ee6f37736b75038a84462202cce464e1ee0c5a0 Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Tue, 7 Apr 2020 00:45:20 +0200 Subject: [PATCH] Adding OBJ model loading --- ext/obj/ObjLoader.cpp | 582 +++++++++++++++++++++++++++++++++++ ext/obj/ObjLoader.h | 82 +++++ rsc/images/shadow.png | Bin 0 -> 4172 bytes rsc/models/shadow.mtl | 10 + rsc/models/square_border.obj | 29 ++ 5 files changed, 703 insertions(+) create mode 100644 ext/obj/ObjLoader.cpp create mode 100644 ext/obj/ObjLoader.h create mode 100755 rsc/images/shadow.png create mode 100644 rsc/models/shadow.mtl create mode 100644 rsc/models/square_border.obj diff --git a/ext/obj/ObjLoader.cpp b/ext/obj/ObjLoader.cpp new file mode 100644 index 0000000..406716c --- /dev/null +++ b/ext/obj/ObjLoader.cpp @@ -0,0 +1,582 @@ +// +// ObjLoader.cpp -- modified for glm +// modified from https://github.com/mortennobel/OpenGL_3_2_Utils +// +/*! + * OpenGL 3.2 Utils - Extension to the Angel library (from the book Interactive Computer Graphics 6th ed + * https://github.com/mortennobel/OpenGL_3_2_Utils + * + * New BSD License + * + * Copyright (c) 2011, Morten Nobel-Joergensen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ObjLoader.h" + +#define GLM_ENABLE_EXPERIMENTAL +#include +using namespace glm; + +#include +#include +#include +#include +#include + +using namespace std; + +const int DEBUG = 1; + +void printDebug(vector &positions, vector &indices); +void printDebug(Material *m); + +vec3 toVec3(istringstream &iss){ + float x,y,z; + iss >> x; + iss >> y; + iss >> z; + return vec3(x,y,z); +} + +vec2 toVec2(istringstream &iss){ + float x,y; + iss >> x; + iss >> y; + return vec2(x,y); +} + +struct TriangleIndex{ + // this is a vertex, represented as the indices into their + // respective arrays of positions, normals, and texture coords + int position; + int normal; + int uv; + + bool replace(std::string& str, const std::string& from, const std::string& to) { + size_t start_pos = str.find(from); + if(start_pos == std::string::npos) + return false; + str.replace(start_pos, from.length(), to); + return true; + } + + TriangleIndex(string p):position(-1),normal(-1),uv(-1) { + // position/uv/normal + replace(p, "//","/-1/"); + stringstream ss(p); + char buffer[50]; + + ss.getline(buffer,50, '/'); + position = atoi(buffer); + if (ss.good()){ + ss.getline(buffer,50, '/'); + uv = atoi(buffer); + } + if (ss.good()){ + ss.getline(buffer,50, '/'); + normal = atoi(buffer); + } + } + + // needed to use TriangleIndex as key in map + bool operator <(const TriangleIndex& Rhs) const { + return (position < Rhs.position) || + (position == Rhs.position && normal < Rhs.normal) || + (position == Rhs.position && normal == Rhs.normal && uv < Rhs.uv); + } +}; + +struct TriangleString{ + TriangleIndex v0; + TriangleIndex v1; + TriangleIndex v2; + + TriangleString(string v0, string v1, string v2):v0(v0),v1(v1),v2(v2){ + } + + TriangleIndex get(int index){ + if (index == 0) { + return v0; + } else if (index == 1) { + return v1; + } + return v2; + } +}; + + + +std::string +makeMtlFilename ( std::string mtlfile, std::string objfile ) +{ + // pull off the path to the directory from the objfile + size_t pos = objfile.rfind ('/'); + // tack the directory onto the materal "mtllib" filename + if ( pos == std::string::npos ) { + return mtlfile; + } else { + std::string path; + path = objfile.substr(0,pos); + return path+"/"+mtlfile; + } +} + + +bool loadMaterialLibrary ( string mtlfilename, + string objfilename, + map &outMaterials) +{ + + string filename = makeMtlFilename( mtlfilename, objfilename ); + string path = filename; + ifstream ifs ( path.c_str(), ifstream::in ); + if (!ifs) { + std::cout << "can't open " << filename << std::endl; + // create a default texture + Material *m = new Material(); + outMaterials["dummy1"] = m; + return false; + } + char buffer[512]; + while (ifs.good()) { + ifs.getline(buffer,512); + string line(buffer); + istringstream iss(line); + string token; + vec3 color; + Material *mat; + iss >> token; + if (token.compare("newmtl") ==0) { + // create a new material and store in map + mat = new Material; + iss >> token; + outMaterials[token] = mat; + } else if (token.compare("Ka") == 0) { + mat->ambient = vec4 ( toVec3 ( iss ), 1.0 ); + } else if (token.compare("Kd") == 0) { + mat->diffuse = vec4 ( toVec3 ( iss ), 1.0); + } else if (token.compare("Ks") == 0) { + mat->specular = vec4 ( toVec3 ( iss ), 1.0); + } else if (token.compare("Ns") == 0) { + float shininess; + iss >> mat->shininess; + } else if (token.compare("map_Kd") == 0) { + string filename,path; + iss >> filename; + if (filename[0] == '/') { + mat->diffuseTexture = filename; // diffuse in unit 0 + } else { + path = makeMtlFilename ( filename, objfilename ); + mat->diffuseTexture = path; // diffuse in unit 0 + } + if (DEBUG) + std::cout << "map_Kd from " << filename << std::endl; + } else if (token.compare("map_Disp") == 0) { + string filename, path; + iss >> filename; + if ( filename[0] == '/' ) { + mat->bumpTexture = filename; // bump in unit 1 + } else { + path = makeMtlFilename ( filename, objfilename ); + mat->bumpTexture = path; // diffuse in unit 0 + } + } + } + + return true; +} + +bool loadObject(string filename, + vector &outPositions, + vector &outNormal, + vector &outUv, + vector &outIndices, + Material *outMaterial, + float scale) +{ + + vector positions; + vector normals; + vector uvs; + + + vector triangles; + ifstream ifs ( filename , ifstream::in ); + char buffer[512]; + while (ifs.good()){ + ifs.getline(buffer,512); + + string line(buffer); + istringstream iss(line); + string token; + iss >> token; + if (token.compare("o")==0){ + // does not support multiple objects + } else if (token.compare("g")==0){ + } else if (token.compare("mtllib")==0){ + // read the .mtl file and create the Materials + map materials; + string mtlfile; + iss >> mtlfile; + loadMaterialLibrary( mtlfile.c_str(), + filename, + materials); + outMaterial = materials[0]; + } else if (token.compare("usemtl")==0){ + // does not support multiple materials + } else if (token.compare("v")==0){ + positions.push_back( toVec3(iss)); + } else if (token.compare("vn")==0){ + normals.push_back( toVec3(iss)); + } else if (token.compare("vt")==0){ + uvs.push_back( toVec2(iss)); + } else if (token.compare("f")==0){ + vector polygon; + do { + string index; + iss >> index; + if (index.length() > 0) { + polygon.push_back(index); + } + } while (iss); + + // triangulate polygon (assumes convex ) + TriangleString triangle(polygon[0], polygon[1], polygon[2]); + triangles.push_back(triangle); + for (int i=3;i cache; + for (int i=0;i::iterator cachedIndex = cache.find(index); + if (cachedIndex != cache.end()) { + outIndices.push_back(cachedIndex->second); + } else { + int vertexIndex = outPositions.size(); + outPositions.push_back(positions[index.position-1] * scale); + if (index.normal != -1){ + outNormal.push_back(normals[index.normal-1]); + } + if (index.uv != -1) { + outUv.push_back(uvs[index.uv-1]); + } + outIndices.push_back(vertexIndex); + cache[index] = vertexIndex; + } + } + } + //cout <<"Indices "<< outIndices.size() << endl; + //cout <<"Positions "<< outPositions.size() << endl; + //printDebug(outPositions, outIndices); + return true; +} + + + +Material * +makeDefaultMaterial() +{ + Material *m = new Material; + m->ambient = vec4 ( 0.1, 0.1, 0.1, 1.0 ); + m->diffuse = vec4 ( 0.8, 0.8, 0.8, 1.0 ); + m->specular = vec4 ( 1.0, 1.0, 1.0, 1.0 ); + m->shininess = 200.0f; + return m; +} + + + +struct Group { + vector triangles; + Material *mat; +}; + +// +// loadObjectGroups loads a .obj file containing materials and textures, +// creating a ModelNode that draws it. +bool loadObjectGroups ( string filename, + vector &outPositions, + vector &outNormal, + vector &outUv, + vector< vector > &outIndices, // per group + vector< Material* >&outMaterials, // per group + float scale) +{ + + vector positions; + vector normals; + vector uvs; + + map groups; + string currentGroupName(""); + + + map materials; + vector diffuseTextures; + vector bumpTextures; + + static int groupnum = 1; + // currentGroupName = "dummy1"; + // groups[currentGroupName] = new Group; + // Material* defaultMaterial = makeDefaultMaterial(); + // groups[currentGroupName]->mat = defaultMaterial; + // materials[currentGroupName] = defaultMaterial; + // outMaterials.push_back ( defaultMaterial ); + + + string path = std::string( filename ); + ifstream ifs ( path.c_str() , ifstream::in ); + char buffer[512]; + while (ifs.good()){ + ifs.getline(buffer,512); + + string line(buffer); + istringstream iss(line); + string token; + iss >> token; + if (token.compare("o")==0){ + // does not support multiple objects + } else if (token.compare("g")==0){ + // for a new group of faces (eg with a diff material) + // create a group + iss >> currentGroupName; + groups[currentGroupName] = new Group; + } else if (token.compare("mtllib")==0){ + // read the .mtl file and create the Materials + string mtlfile; + iss >> mtlfile; + loadMaterialLibrary( mtlfile.c_str(), + filename, + materials); + } else if (token.compare("usemtl")==0){ + // create group if none exists, or if this is a "usemtl" line without a preceding "g" line + if ( currentGroupName=="" || groups[currentGroupName]->triangles.size() ) { + string name; + ostringstream oss(name); + // static int groupnum = 1; + oss << "dummy" << groupnum++; + currentGroupName=oss.str(); + groups[currentGroupName] = new Group; + } + iss >> token; + if (token=="usemtl") { + if (DEBUG) + std::cout << "null token" << std::endl; + token = "dummy1"; + } + if (DEBUG) { + std::cout << "group is " << currentGroupName << std::endl; + std::cout << "usemtl " << token << std::endl; + std::cout << "materials[token] == " << materials[token] << std::endl; + } + if ( materials[token] == 0 ) { + materials[token] = makeDefaultMaterial(); + } + printDebug ( materials[token] ); + groups[currentGroupName]->mat = materials[token]; + outMaterials.push_back((materials[token])); + + } else if (token.compare("v")==0){ + positions.push_back( toVec3(iss)); + } else if (token.compare("vn")==0){ + normals.push_back( toVec3(iss)); + } else if (token.compare("vt")==0){ + uvs.push_back( toVec2(iss)); + } else if (token.compare("f")==0){ + // assign face to current group + vector polygon; + do { + string index; + iss >> index; + if (index.length() > 0) { + polygon.push_back(index); + } + } while (iss); + + // oops no usemtl or mtllib or group seen + // if ( currentGroupName=="" || groups[currentGroupName]->triangles.size()==0 ) { + if ( currentGroupName=="" ) { + string name; + ostringstream oss(name); + // static int groupnum = 1; + oss << "dummy" << groupnum++; + currentGroupName=oss.str(); + groups[currentGroupName] = new Group; + outMaterials.push_back( groups[currentGroupName]->mat = makeDefaultMaterial() ); + } + + + // triangulate polygon + if ( polygon.size() >= 3 ) { + TriangleString triangle(polygon[0], polygon[1], polygon[2]); + groups[currentGroupName]->triangles.push_back(triangle); + for (int i=3;itriangles.push_back(triangle2); + } + } + } + } + ifs.close(); + + // XXX + // repeat this for each group. + // return vectors must be made vectors of vectors (or maybe just the indices?) + // for each group + // deref and pack the vertex positions, normal, and uv, + // pack the element array for each group separately + map cache; + for ( map::iterator g = groups.begin(); g != groups.end();g++ ) { + // each group gets its own element array + vector groupIndices; + for (int i=0;isecond->triangles.size();i++){ + TriangleString triangleString = g->second->triangles[i]; + for (int j=0;j<3;j++){ + TriangleIndex index = triangleString.get(j); + map::iterator cachedIndex = cache.find(index); + if (cachedIndex != cache.end()) { + groupIndices.push_back(cachedIndex->second); + } else { + int vertexIndex = outPositions.size(); + outPositions.push_back(positions[index.position-1] * scale); + if (index.normal != -1){ + outNormal.push_back(normals[index.normal-1]); + } + if (index.uv != -1) { + outUv.push_back(uvs[index.uv-1]); + } + groupIndices.push_back(vertexIndex); + cache[index] = vertexIndex; + } + } + } + // pack the indices for this group + outIndices.push_back(groupIndices); + } + //cout <<"Indices "<< outIndices.size() << endl; + //cout <<"Positions "<< outPositions.size() << endl; + //printDebug(outPositions, outIndices); + return true; +} + + +void printDebug(vector &positions, vector &indices){ + if (!DEBUG) + return; + for (int i=0;iambient) << endl; + cout << "diffuse " << glm::to_string(m->diffuse) << endl; + cout << "specular " << glm::to_string(m->specular) << endl; + cout << "shininess " << m->shininess << endl; + cout << "diffuse texture " << m->diffuseTexture << endl; + cout << "bump texture " << m->bumpTexture << endl; +} + + +//// +//// ObjFilePrimitive +//// + +//ObjFilePrimitive::ObjFilePrimitive ( const char *filename ) +//{ + +// bool okay = loadObjectGroups( filename, +// points_, +// normals_, +// texCoords_, +// groupIndices_, +// materials_, +// 1.0 ); +// if ( !okay ) { +// std::cout << "load error\n" ; +// } else { +// if (DEBUG) +// std::cout << "loaded " << filename << std::endl +// << points_.size() << " points\n" +// << normals_.size() << " normals\n" +// << texCoords_.size() << " tex coords\n" +// << groupIndices_.size() << " groups\n"; +// } +// // // copy to unsigned ints. *sigh* +// // for (int i = 0; i < tmp_indices.size(); i++ ) +// // indices_.push_back( static_cast (tmp_indices[i]) ); + +// drawingPrimitive_ = GL_TRIANGLES; + +// generateAndLoadArrayBuffer(); + +// // generate the element buffers +// for ( int i = 0; i < groupIndices_.size(); i++ ) { +// groupElementArrayIds_.push_back(0); +// glGenBuffers(1, &groupElementArrayIds_[i] ); +// int sizeofIndices = groupIndices_[i].size()*sizeof(unsigned int); +// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, groupElementArrayIds_[i] ); +// glBufferData ( GL_ELEMENT_ARRAY_BUFFER, sizeofIndices, &(groupIndices_[i][0]), GL_STATIC_DRAW); +// } + +// glBindVertexArray(0); +//} + + +//void +//ObjFilePrimitive::draw ( glm::mat4 modelview, +// glm::mat4 projection, +// Ptr material) { + +// // loop over all groups as they have different materials. +// for (int i = 0; i < groupIndices_.size(); i++ ) { + +// if (!material.get()) { +// setupShader ( modelview, projection, materials_[i] ); +// } else { +// setupShader ( modelview, projection, material ); +// } + +// // +// // draw +// // +// glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, groupElementArrayIds_[i] ); +// glDrawElements( drawingPrimitive_, groupIndices_[i].size(), GL_UNSIGNED_INT, 0 ); +// glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 ); + +// endShader(); +// } +//} diff --git a/ext/obj/ObjLoader.h b/ext/obj/ObjLoader.h new file mode 100644 index 0000000..5d5b504 --- /dev/null +++ b/ext/obj/ObjLoader.h @@ -0,0 +1,82 @@ +// +// ObjLoader.h -- modified for glm +// modified from https://github.com/mortennobel/OpenGL_3_2_Utils +// William.Thibault@csueastbay.edu +// + +/*! + * OpenGL 3.2 Utils - Extension to the Angel library (from the book Interactive Computer Graphics 6th ed + * https://github.com/mortennobel/OpenGL_3_2_Utils + * + * New BSD License + * + * Copyright (c) 2011, Morten Nobel-Joergensen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __OBJ_LOADER_H +#define __OBJ_LOADER_H + +#include +#include +#include + + +struct Material +{ +Material() : + ambient (0.1, 0.1, 0.1, 1.0), + diffuse (0.8, 0.8, 0.8, 1.0), + specular(1.0, 1.0, 1.0, 1.0 ), + shininess(75.0) + {} + virtual ~Material() { } + + glm::vec4 ambient; + glm::vec4 diffuse; + glm::vec4 specular; + float shininess; + + std::string diffuseTexture; + std::string bumpTexture; +}; + + +// The original version, modified for glm. +// Load an OBJ model into the out parameters. +// Note only simple OBJ files are supported. +bool loadObject (std::string filename, + std::vector &outPositions, + std::vector &outNormal, + std::vector &outUv, + std::vector &outIndices, + Material *outMaterial, + float scale = 1.0f + ); + +// this tries to handle multiple materials (w/textures) and groups of faces as per pcl_kinfu_largeScale, etc +bool loadObjectGroups (std::string filename, + std::vector &outPositions, + std::vector &outNormal, + std::vector &outUv, + std::vector > &outIndices, // per group + std::vector &outMaterials, // per group (w/textures) + float scale=1.0f +); + +#endif diff --git a/rsc/images/shadow.png b/rsc/images/shadow.png new file mode 100755 index 0000000000000000000000000000000000000000..74484527616aac676ead1685ed498987915964ca GIT binary patch literal 4172 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 literal 0 HcmV?d00001 diff --git a/rsc/models/shadow.mtl b/rsc/models/shadow.mtl new file mode 100644 index 0000000..d48fd57 --- /dev/null +++ b/rsc/models/shadow.mtl @@ -0,0 +1,10 @@ +newmtl Shadow +Ns 323.999994 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 +map_Kd images/shadow.png diff --git a/rsc/models/square_border.obj b/rsc/models/square_border.obj new file mode 100644 index 0000000..ec0a35c --- /dev/null +++ b/rsc/models/square_border.obj @@ -0,0 +1,29 @@ +mtllib shadow.mtl +o square_border +v -1.000000 -1.000000 0.000000 +v -1.300000 -1.300000 0.000000 +v 1.000000 -1.000000 0.000000 +v 1.300000 -1.300000 0.000000 +v -1.000000 1.000000 0.000000 +v -1.300000 1.300000 0.000000 +v 1.000000 1.000000 0.000000 +v 1.300000 1.300000 0.000000 +vt 0.2 0.80 +vt 1.00 1.00 +vt -0.00 1.00 +vt 0.80 0.80 +vt 1.00 -0.00 +vt 0.2 0.2 +vt -0.00 -0.00 +vt 0.8 0.2 +vn 0.0000 0.0000 -1.0000 +usemtl Shadow +s off +f 3/1/1 8/2/1 4/3/1 +f 7/4/1 6/5/1 8/2/1 +f 1/6/1 4/3/1 2/7/1 +f 5/8/1 2/7/1 6/5/1 +f 3/1/1 7/4/1 8/2/1 +f 7/4/1 5/8/1 6/5/1 +f 1/6/1 3/1/1 4/3/1 +f 5/8/1 1/6/1 2/7/1