Initial commit.
This commit is contained in:
commit
d3bb49b3f5
1073 changed files with 484757 additions and 0 deletions
715
Framework/scenegraph/obj_loader.cpp
Normal file
715
Framework/scenegraph/obj_loader.cpp
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
// Copyright 2009-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "obj_loader.h"
|
||||
// #include "texture.h"
|
||||
|
||||
namespace embree {
|
||||
/*! Three-index vertex, indexing start at 0, -1 means invalid vertex. */
|
||||
struct Vertex {
|
||||
unsigned int v, vt, vn;
|
||||
|
||||
Vertex() {
|
||||
};
|
||||
|
||||
Vertex(unsigned int v) : v(v), vt(v), vn(v) {
|
||||
};
|
||||
|
||||
Vertex(unsigned int v, unsigned int vt, unsigned int vn) : v(v), vt(vt), vn(vn) {
|
||||
};
|
||||
};
|
||||
|
||||
struct Crease {
|
||||
float w;
|
||||
unsigned int a, b;
|
||||
|
||||
Crease() : w(0), a(-1), b(-1) {
|
||||
};
|
||||
|
||||
Crease(float w, unsigned int a, unsigned int b) : w(w), a(a), b(b) {
|
||||
};
|
||||
};
|
||||
|
||||
static inline bool operator <(const Vertex& a, const Vertex& b) {
|
||||
if (a.v != b.v) return a.v < b.v;
|
||||
if (a.vn != b.vn) return a.vn < b.vn;
|
||||
if (a.vt != b.vt) return a.vt < b.vt;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Fill space at the end of the token with 0s. */
|
||||
static inline const char* trimEnd(const char* token) {
|
||||
if (*token == 0) return token;
|
||||
char* pe = (char *) token;
|
||||
while (*pe) pe++;
|
||||
pe--;
|
||||
while ((*pe == ' ' || *pe == '\t' || *pe == '\r') && pe >= token) *pe-- = 0;
|
||||
return token;
|
||||
}
|
||||
|
||||
/*! Determine if character is a separator. */
|
||||
static inline bool isSep(const char c) {
|
||||
return (c == ' ') || (c == '\t');
|
||||
}
|
||||
|
||||
/*! Parse separator. */
|
||||
static inline const char* parseSep(const char*& token) {
|
||||
size_t sep = strspn(token, " \t");
|
||||
if (!sep)
|
||||
THROW_RUNTIME_ERROR("separator expected");
|
||||
return token += sep;
|
||||
}
|
||||
|
||||
/*! Parse optional separator. */
|
||||
static inline const char* parseSepOpt(const char*& token) {
|
||||
return token += strspn(token, " \t");
|
||||
}
|
||||
|
||||
/*! Read float from a string. */
|
||||
static inline float getFloat(const char*& token) {
|
||||
token += strspn(token, " \t");
|
||||
float n = (float) atof(token);
|
||||
token += strcspn(token, " \t\r");
|
||||
return n;
|
||||
}
|
||||
|
||||
/*! Read int from a string. */
|
||||
static inline int getInt(const char*& token) {
|
||||
token += strspn(token, " \t");
|
||||
int n = atoi(token);
|
||||
token += strcspn(token, " \t\r");
|
||||
return n;
|
||||
}
|
||||
|
||||
/*! Read Vec2f from a string. */
|
||||
static inline Vec2f getVec2f(const char*& token) {
|
||||
float x = getFloat(token);
|
||||
float y = getFloat(token);
|
||||
return Vec2f(x, y);
|
||||
}
|
||||
|
||||
/*! Read Vec3f from a string. */
|
||||
static inline Vec3f getVec3f(const char*& token) {
|
||||
float x = getFloat(token);
|
||||
token += strspn(token, " \t");
|
||||
if (*token == 0) return Vec3f(x);
|
||||
float y = getFloat(token);
|
||||
float z = getFloat(token);
|
||||
return Vec3f(x, y, z);
|
||||
}
|
||||
|
||||
/*! Read Vec3fa from a string. */
|
||||
static inline Vec3fa getVec3fa(const char*& token) {
|
||||
float x = getFloat(token);
|
||||
token += strspn(token, " \t");
|
||||
if (*token == 0) return Vec3f(x);
|
||||
float y = getFloat(token);
|
||||
float z = getFloat(token);
|
||||
return Vec3fa(x, y, z);
|
||||
}
|
||||
|
||||
class OBJLoader {
|
||||
public:
|
||||
/*! Constructor. */
|
||||
OBJLoader(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject);
|
||||
|
||||
/*! output model */
|
||||
Ref<SceneGraph::GroupNode> group;
|
||||
|
||||
private:
|
||||
/*! file to load */
|
||||
FileName path;
|
||||
|
||||
/*! load only quads and ignore triangles */
|
||||
bool subdivMode;
|
||||
|
||||
/*! Geometry buffer. */
|
||||
avector<Vec3fa> v;
|
||||
avector<Vec3fa> vn;
|
||||
std::vector<Vec2f> vt;
|
||||
std::vector<Crease> ec;
|
||||
|
||||
std::vector<std::vector<Vertex> > curGroup;
|
||||
std::vector<avector<Vec3ff> > curGroupHair;
|
||||
|
||||
/*! Material handling. */
|
||||
std::string curMaterialName;
|
||||
Ref<SceneGraph::MaterialNode> curMaterial;
|
||||
std::map<std::string, Ref<SceneGraph::MaterialNode> > material;
|
||||
// std::map<std::string, std::shared_ptr<Texture>> textureMap;
|
||||
|
||||
private:
|
||||
void loadMTL(const FileName& fileName);
|
||||
|
||||
unsigned int fix_v(int index);
|
||||
|
||||
unsigned int fix_vt(int index);
|
||||
|
||||
unsigned int fix_vn(int index);
|
||||
|
||||
void flushFaceGroup();
|
||||
|
||||
void flushTriGroup();
|
||||
|
||||
// void flushHairGroup();
|
||||
Vertex getUInt3(const char*& token);
|
||||
|
||||
uint32_t getVertex(std::map<Vertex, uint32_t>& vertexMap, Ref<SceneGraph::TriangleMeshNode> mesh,
|
||||
const Vertex& i);
|
||||
|
||||
// std::shared_ptr<Texture> loadTexture(const FileName& fname);
|
||||
};
|
||||
|
||||
OBJLoader::OBJLoader(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject)
|
||||
: group(new SceneGraph::GroupNode), path(fileName.path()), subdivMode(subdivMode) {
|
||||
/* open file */
|
||||
std::ifstream cin;
|
||||
cin.open(fileName.c_str());
|
||||
if (!cin.is_open()) {
|
||||
THROW_RUNTIME_ERROR("cannot open " + fileName.str());
|
||||
return;
|
||||
}
|
||||
|
||||
/* generate default material */
|
||||
Ref<SceneGraph::MaterialNode> defaultMaterial = new OBJMaterial("default");
|
||||
curMaterialName = "default";
|
||||
curMaterial = defaultMaterial;
|
||||
|
||||
while (cin.peek() != -1) {
|
||||
/* load next multiline */
|
||||
std::string line;
|
||||
std::getline(cin, line);
|
||||
while (!line.empty() && line[line.size() - 1] == '\\') {
|
||||
line[line.size() - 1] = ' ';
|
||||
std::string next_line;
|
||||
std::getline(cin, next_line);
|
||||
if (next_line.empty()) break;
|
||||
line += next_line;
|
||||
}
|
||||
const char* token = trimEnd(line.c_str() + strspn(line.c_str(), " \t"));
|
||||
if (token[0] == 0) continue;
|
||||
|
||||
/*! parse position */
|
||||
if (token[0] == 'v' && isSep(token[1])) {
|
||||
v.push_back(getVec3f(token += 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse normal */
|
||||
if (token[0] == 'v' && token[1] == 'n' && isSep(token[2])) {
|
||||
vn.push_back(getVec3f(token += 3));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse texcoord */
|
||||
if (token[0] == 'v' && token[1] == 't' && isSep(token[2])) {
|
||||
vt.push_back(getVec2f(token += 3));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*! parse face */
|
||||
if (token[0] == 'f' && isSep(token[1])) {
|
||||
parseSep(token += 1);
|
||||
|
||||
std::vector<Vertex> face;
|
||||
while (token[0]) {
|
||||
Vertex vtx = getUInt3(token);
|
||||
face.push_back(vtx);
|
||||
parseSepOpt(token);
|
||||
}
|
||||
curGroup.push_back(face);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*! parse corona hair */
|
||||
if (!strncmp(token, "hair", 4) && isSep(token[4])) {
|
||||
throw std::runtime_error("corona hair is deimplemented");
|
||||
}
|
||||
|
||||
/*! parse edge crease */
|
||||
if (token[0] == 'e' && token[1] == 'c' && isSep(token[2])) {
|
||||
parseSep(token += 2);
|
||||
float w = getFloat(token);
|
||||
parseSepOpt(token);
|
||||
unsigned int a = fix_v(getInt(token));
|
||||
parseSepOpt(token);
|
||||
unsigned int b = fix_v(getInt(token));
|
||||
parseSepOpt(token);
|
||||
ec.push_back(Crease(w, a, b));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*! use material */
|
||||
if (!strncmp(token, "usemtl", 6) && isSep(token[6])) {
|
||||
if (!combineIntoSingleObject) flushFaceGroup();
|
||||
std::string name(parseSep(token += 6));
|
||||
if (material.find(name) == material.end()) {
|
||||
curMaterial = defaultMaterial;
|
||||
curMaterialName = "default";
|
||||
} else {
|
||||
curMaterial = material[name];
|
||||
curMaterialName = name;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* load material library */
|
||||
if (!strncmp(token, "mtllib", 6) && isSep(token[6])) {
|
||||
loadMTL(path + std::string(parseSep(token += 6)));
|
||||
continue;
|
||||
}
|
||||
|
||||
// ignore unknown stuff
|
||||
}
|
||||
flushFaceGroup();
|
||||
|
||||
cin.close();
|
||||
}
|
||||
|
||||
struct ExtObjMaterial {
|
||||
public:
|
||||
enum Type { NONE, MATTE, GLASS, METAL, METALLIC_PAINT };
|
||||
|
||||
Ref<SceneGraph::MaterialNode> select() const {
|
||||
// std::shared_ptr<Texture> nulltex;
|
||||
if (type == NONE) {
|
||||
// return new OBJMaterial(d,map_d,Ka,map_Ka,Kd,map_Kd,Ks,map_Ks,Kt,map_Kt,Ns,map_Ns,map_Displ);
|
||||
return new OBJMaterial(d, Ka, Kd, Ks, Kt, Ns);
|
||||
} else if (type == MATTE) {
|
||||
if (coat_eta != 1.0f)
|
||||
return new MetallicPaintMaterial(Kd, zero, 0.0f, eta.x);
|
||||
else
|
||||
// return new OBJMaterial(1.0f,nulltex,zero,nulltex,Kd,map_Kd,Ks,nulltex,zero,nulltex,1.0f/(1E-6f+roughness),nulltex,nulltex);
|
||||
return new OBJMaterial(1.0f, zero, Kd, Ks, zero, 1.0f / (1E-6f + roughness));
|
||||
} else if (type == GLASS) {
|
||||
return new ThinDielectricMaterial(Vec3fa(1.0f), eta.x, 0.1f);
|
||||
} else if (type == METAL) {
|
||||
if (roughness == 0.0f) {
|
||||
if (eta == Vec3fa(1.0f) && k == Vec3fa(0.0f)) return new MirrorMaterial(Kd);
|
||||
else return new MetalMaterial(Kd, eta, k);
|
||||
} else return new MetalMaterial(Kd, eta, k, roughness);
|
||||
} else if (type == METALLIC_PAINT) {
|
||||
return new MetallicPaintMaterial(Kd, Ks, 0.0f, coat_eta);
|
||||
}
|
||||
return new MatteMaterial(Vec3fa(0.5f));
|
||||
}
|
||||
|
||||
public:
|
||||
Type type = NONE;
|
||||
|
||||
int illum = 0; /*< illumination model */
|
||||
float d = 1.0f; /*< dissolve factor, 1=opaque, 0=transparent */
|
||||
float Ns = 1.0f; /*< specular exponent */
|
||||
float Ni = 1.0f; /*< optical density for the surface (index of refraction) */
|
||||
|
||||
Vec3fa Ka = zero; /*< ambient reflectivity */
|
||||
Vec3fa Kd = one; /*< diffuse reflectivity */
|
||||
Vec3fa Ks = zero; /*< specular reflectivity */
|
||||
// Vec3fa Kt = zero; /*< transmission filter */
|
||||
Vec3fa Kt = one; /*< transmission filter */
|
||||
// ^ Because many textures were deleted
|
||||
|
||||
// std::shared_ptr<Texture> map_d; /*< d texture */
|
||||
// std::shared_ptr<Texture> map_Ka; /*< Ka texture */
|
||||
// std::shared_ptr<Texture> map_Kd; /*< Kd texture */
|
||||
// std::shared_ptr<Texture> map_Ks; /*< Ks texture */
|
||||
// std::shared_ptr<Texture> map_Kt; /*< Kt texture */
|
||||
// std::shared_ptr<Texture> map_Ns; /*< Ns texture */
|
||||
// std::shared_ptr<Texture> map_Displ; /*< Displ texture */
|
||||
|
||||
float roughness = zero;
|
||||
// std::shared_ptr<Texture> roughnessMap;
|
||||
float coat_eta = one;
|
||||
float coat_roughness = zero;
|
||||
// std::shared_ptr<Texture> coat_roughnessMap;
|
||||
float bump = zero;
|
||||
Vec3f eta = Vec3f(1.4f);
|
||||
Vec3f k = Vec3f(3.0f);
|
||||
};
|
||||
|
||||
// std::shared_ptr<Texture> OBJLoader::loadTexture(const FileName& fname)
|
||||
// {
|
||||
// if (textureMap.find(fname.str()) != textureMap.end())
|
||||
// return textureMap[fname.str()];
|
||||
|
||||
// return std::shared_ptr<Texture>(Texture::load(path+fname));
|
||||
// }
|
||||
|
||||
/* load material file */
|
||||
void OBJLoader::loadMTL(const FileName& fileName) {
|
||||
std::ifstream cin;
|
||||
cin.open(fileName.c_str());
|
||||
if (!cin.is_open()) {
|
||||
std::cerr << "cannot open " << fileName.str() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
ExtObjMaterial cur;
|
||||
|
||||
while (cin.peek() != -1) {
|
||||
/* load next multiline */
|
||||
std::string line;
|
||||
std::getline(cin, line);
|
||||
while (!line.empty() && line[line.size() - 1] == '\\') {
|
||||
line[line.size() - 1] = ' ';
|
||||
std::string next_line;
|
||||
std::getline(cin, next_line);
|
||||
if (next_line.empty()) break;
|
||||
line += next_line;
|
||||
}
|
||||
const char* token = trimEnd(line.c_str() + strspn(line.c_str(), " \t"));
|
||||
|
||||
if (token[0] == 0) continue; // ignore empty lines
|
||||
if (token[0] == '#') continue; // ignore comments
|
||||
|
||||
if (!strncmp(token, "newmtl", 6)) {
|
||||
if (name != "") {
|
||||
material[name] = cur.select();
|
||||
material[name]->name = name;
|
||||
}
|
||||
|
||||
parseSep(token += 6);
|
||||
name = token;
|
||||
cur = ExtObjMaterial();
|
||||
continue;
|
||||
}
|
||||
if (name == "")
|
||||
THROW_RUNTIME_ERROR("invalid material file: newmtl expected first");
|
||||
|
||||
try {
|
||||
if (!strncmp(token, "illum", 5)) {
|
||||
parseSep(token += 5);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(token, "d", 1)) {
|
||||
parseSep(token += 1);
|
||||
cur.d = getFloat(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "Ns", 2)) {
|
||||
parseSep(token += 2);
|
||||
cur.Ns = getFloat(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "Ni", 2)) {
|
||||
parseSep(token += 2);
|
||||
cur.Ni = getFloat(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if (!strncmp(token, "map_d", 5) || !strncmp(token, "d_map", 5)) {
|
||||
// parseSep(token += 5);
|
||||
// cur.map_d = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
// if (!strncmp(token, "map_Ka", 6) || !strncmp(token, "Ka_map", 6)) {
|
||||
// parseSep(token += 6);
|
||||
// cur.map_Ka = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
// if (!strncmp(token, "map_Kd", 6) || !strncmp(token, "Kd_map", 6)) {
|
||||
// parseSep(token += 6);
|
||||
// cur.map_Kd = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
// if (!strncmp(token, "map_Ks", 6) || !strncmp(token, "Ks_map", 6)) {
|
||||
// parseSep(token += 6);
|
||||
// cur.map_Ks = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
// if (!strncmp(token, "map_Kt", 6) || !strncmp(token, "Kt_map", 6)) {
|
||||
// parseSep(token += 6);
|
||||
// cur.map_Kt = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
// if (!strncmp(token, "map_Tf", 6) || !strncmp(token, "Tf_map", 6)) {
|
||||
// parseSep(token += 6);
|
||||
// cur.map_Kt = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
// if (!strncmp(token, "map_Ns", 6) || !strncmp(token, "Ns_map", 6)) {
|
||||
// parseSep(token += 6);
|
||||
// cur.map_Ns = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
// if (!strncmp(token, "map_Displ", 9) || !strncmp(token, "Displ_map", 9)) {
|
||||
// parseSep(token += 9);
|
||||
// cur.map_Displ = loadTexture(FileName(token));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (!strncmp(token, "Ka", 2)) {
|
||||
parseSep(token += 2);
|
||||
cur.Ka = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "Kd", 2)) {
|
||||
parseSep(token += 2);
|
||||
cur.Kd = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "Ks", 2)) {
|
||||
parseSep(token += 2);
|
||||
cur.Ks = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "Kt", 2)) {
|
||||
parseSep(token += 2);
|
||||
cur.Kt = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "Tf", 2)) {
|
||||
parseSep(token += 2);
|
||||
cur.Kt = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* extended OBJ */
|
||||
if (!strncmp(token, "type", 4)) {
|
||||
parseSep(token += 4);
|
||||
std::string type = token;
|
||||
if (type == "matte") cur.type = ExtObjMaterial::MATTE;
|
||||
else if (type == "glass") cur.type = ExtObjMaterial::GLASS;
|
||||
else if (type == "metal") cur.type = ExtObjMaterial::METAL;
|
||||
else if (type == "metallicPaint") cur.type = ExtObjMaterial::METALLIC_PAINT;
|
||||
else if (type == "principled") cur.type = ExtObjMaterial::NONE;
|
||||
else if (type == "luminous") cur.type = ExtObjMaterial::NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* OSPRay principled material extensions */
|
||||
if (!strncmp(token, "baseColor", 9)) {
|
||||
parseSep(token += 9);
|
||||
cur.Kd = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "ior", 3)) {
|
||||
parseSep(token += 3);
|
||||
cur.Ni = getFloat(token);
|
||||
continue;
|
||||
}
|
||||
// if (!strncmp(token, "map_baseColor", 13)) { parseSep(token += 13); cur.map_Kd = loadTexture(FileName(token)); continue; }
|
||||
// if (!strncmp(token, "map_specular", 12)) { parseSep(token += 12); cur.map_Ks = loadTexture(FileName(token)); continue; }
|
||||
if (!strncmp(token, "map_normal.scale", 16)) {
|
||||
parseSep(token += 16);
|
||||
continue;
|
||||
}
|
||||
// if (!strncmp(token, "map_normal", 10)) { parseSep(token += 10); cur.map_Displ = loadTexture(FileName(token)); continue; }
|
||||
if (!strncmp(token, "transmissionColor", 17)) {
|
||||
parseSep(token += 17);
|
||||
cur.Kt = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "transmission", 12)) {
|
||||
parseSep(token += 12);
|
||||
cur.Kt = Vec3f(getFloat(token));
|
||||
continue;
|
||||
}
|
||||
|
||||
// if (!strncmp(token, "roughnessMap", 12)) { parseSep(token += 12); cur.roughnessMap = loadTexture(FileName(token)); continue; }
|
||||
if (!strncmp(token, "roughness", 9)) {
|
||||
parseSep(token += 9);
|
||||
cur.roughness = getFloat(token);
|
||||
cur.Ns = 1.0f / (cur.roughness + 1E-6f);
|
||||
continue;
|
||||
}
|
||||
// if (!strncmp(token, "colorMap", 8)) { parseSep(token += 8); cur.map_Kd = loadTexture(FileName(token)); continue; }
|
||||
if (!strncmp(token, "color", 5)) {
|
||||
parseSep(token += 5);
|
||||
cur.Kd = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "coat.color", 10)) {
|
||||
parseSep(token += 10);
|
||||
cur.Kd = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "coat.eta", 8)) {
|
||||
parseSep(token += 8);
|
||||
cur.coat_eta = getFloat(token);
|
||||
continue;
|
||||
}
|
||||
// if (!strncmp(token, "coat.roughnessMap",17)) { parseSep(token += 17); cur.coat_roughnessMap = loadTexture(FileName(token)); continue; }
|
||||
if (!strncmp(token, "coat.roughness", 14)) {
|
||||
parseSep(token += 14);
|
||||
cur.coat_roughness = getFloat(token);
|
||||
continue;
|
||||
}
|
||||
// if (!strncmp(token, "bumpMap", 7)) { parseSep(token += 7); cur.map_Displ = loadTexture(FileName(token)); continue; }
|
||||
if (!strncmp(token, "bump", 4)) {
|
||||
parseSep(token += 4);
|
||||
cur.bump = getFloat(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "eta", 3)) {
|
||||
parseSep(token += 3);
|
||||
cur.eta = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(token, "k", 1)) {
|
||||
parseSep(token += 1);
|
||||
cur.k = getVec3f(token);
|
||||
continue;
|
||||
}
|
||||
} catch (const std::runtime_error& e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (name != "") {
|
||||
material[name] = cur.select();
|
||||
material[name]->name = name;
|
||||
}
|
||||
|
||||
cin.close();
|
||||
}
|
||||
|
||||
/*! handles relative indices and starts indexing from 0 */
|
||||
unsigned int OBJLoader::fix_v(int index) {
|
||||
return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) v.size() + index));
|
||||
}
|
||||
|
||||
unsigned int OBJLoader::fix_vt(int index) {
|
||||
return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vt.size() + index));
|
||||
}
|
||||
|
||||
unsigned int OBJLoader::fix_vn(int index) {
|
||||
return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vn.size() + index));
|
||||
}
|
||||
|
||||
/*! Parse differently formatted triplets like: n0, n0/n1/n2, n0//n2, n0/n1. */
|
||||
/*! All indices are converted to C-style (from 0). Missing entries are assigned -1. */
|
||||
Vertex OBJLoader::getUInt3(const char*& token) {
|
||||
Vertex v(-1);
|
||||
v.v = fix_v(atoi(token));
|
||||
token += strcspn(token, "/ \t\r");
|
||||
if (token[0] != '/') return (v);
|
||||
token++;
|
||||
|
||||
// it is i//n
|
||||
if (token[0] == '/') {
|
||||
token++;
|
||||
v.vn = fix_vn(atoi(token));
|
||||
token += strcspn(token, " \t\r");
|
||||
return (v);
|
||||
}
|
||||
|
||||
// it is i/t/n or i/t
|
||||
v.vt = fix_vt(atoi(token));
|
||||
token += strcspn(token, "/ \t\r");
|
||||
if (token[0] != '/') return (v);
|
||||
token++;
|
||||
|
||||
// it is i/t/n
|
||||
v.vn = fix_vn(atoi(token));
|
||||
token += strcspn(token, " \t\r");
|
||||
return (v);
|
||||
}
|
||||
|
||||
uint32_t OBJLoader::getVertex(std::map<Vertex, uint32_t>& vertexMap, Ref<SceneGraph::TriangleMeshNode> mesh,
|
||||
const Vertex& i) {
|
||||
const std::map<Vertex, uint32_t>::iterator& entry = vertexMap.find(i);
|
||||
if (entry != vertexMap.end()) return (entry->second);
|
||||
|
||||
if (i.v >= v.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
|
||||
else mesh->positions[0].push_back(v[i.v]);
|
||||
|
||||
if (i.vn != -1) {
|
||||
while (mesh->normals[0].size() < mesh->positions[0].size()) mesh->normals[0].push_back(zero);
|
||||
// some vertices might not had a normal
|
||||
|
||||
if (i.vn >= vn.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
|
||||
else mesh->normals[0][mesh->positions[0].size() - 1] = vn[i.vn];
|
||||
}
|
||||
if (i.vt != -1) {
|
||||
while (mesh->texcoords.size() < mesh->positions[0].size()) mesh->texcoords.push_back(zero);
|
||||
// some vertices might not had a texture coordinate
|
||||
|
||||
if (i.vt >= vt.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
|
||||
else mesh->texcoords[mesh->positions[0].size() - 1] = vt[i.vt];
|
||||
}
|
||||
return (vertexMap[i] = (unsigned int) (mesh->positions[0].size()) - 1);
|
||||
}
|
||||
|
||||
void OBJLoader::flushFaceGroup() {
|
||||
flushTriGroup();
|
||||
// flushHairGroup();
|
||||
}
|
||||
|
||||
/*! end current facegroup and append to mesh */
|
||||
void OBJLoader::flushTriGroup() {
|
||||
if (curGroup.empty()) return;
|
||||
|
||||
if (subdivMode) {
|
||||
throw std::runtime_error("Deimplemented");
|
||||
// Ref<SceneGraph::SubdivMeshNode> mesh = new SceneGraph::SubdivMeshNode(curMaterial,BBox1f(0,1),1);
|
||||
// mesh->normals.resize(1);
|
||||
// group->add(mesh.cast<SceneGraph::Node>());
|
||||
|
||||
// for (size_t i=0; i<v.size(); i++) mesh->positions[0].push_back(v[i]);
|
||||
// for (size_t i=0; i<vn.size(); i++) mesh->normals[0].push_back(vn[i]);
|
||||
// for (size_t i=0; i<vt.size(); i++) mesh->texcoords.push_back(vt[i]);
|
||||
|
||||
// for (size_t i=0; i<ec.size(); ++i) {
|
||||
// assert(((size_t)ec[i].a < v.size()) && ((size_t)ec[i].b < v.size()));
|
||||
// mesh->edge_creases.push_back(Vec2i(ec[i].a, ec[i].b));
|
||||
// mesh->edge_crease_weights.push_back(ec[i].w);
|
||||
// }
|
||||
|
||||
// for (size_t j=0; j<curGroup.size(); j++)
|
||||
// {
|
||||
// const std::vector<Vertex>& face = curGroup[j];
|
||||
// mesh->verticesPerFace.push_back(int(face.size()));
|
||||
// for (size_t i=0; i<face.size(); i++)
|
||||
// mesh->position_indices.push_back(face[i].v);
|
||||
// }
|
||||
// if (mesh->normals[0].size() == 0)
|
||||
// mesh->normals.clear();
|
||||
// mesh->verify();
|
||||
} else {
|
||||
Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(curMaterial, BBox1f(0, 1), 1);
|
||||
mesh->normals.resize(1);
|
||||
group->add(mesh.cast<SceneGraph::Node>());
|
||||
// merge three indices into one
|
||||
std::map<Vertex, uint32_t> vertexMap;
|
||||
for (size_t j = 0; j < curGroup.size(); j++) {
|
||||
/* iterate over all faces */
|
||||
const std::vector<Vertex>& face = curGroup[j];
|
||||
|
||||
/* triangulate the face with a triangle fan */
|
||||
Vertex i0 = face[0], i1 = Vertex(-1), i2 = face[1];
|
||||
for (size_t k = 2; k < face.size(); k++) {
|
||||
i1 = i2;
|
||||
i2 = face[k];
|
||||
uint32_t v0, v1, v2;
|
||||
v0 = getVertex(vertexMap, mesh, i0);
|
||||
v1 = getVertex(vertexMap, mesh, i1);
|
||||
v2 = getVertex(vertexMap, mesh, i2);
|
||||
assert(v0 < mesh->numVertices());
|
||||
assert(v1 < mesh->numVertices());
|
||||
assert(v2 < mesh->numVertices());
|
||||
mesh->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle(v0, v1, v2));
|
||||
}
|
||||
}
|
||||
/* there may be vertices without normals or texture coordinates, thus we have to make these arrays the same size here */
|
||||
if (mesh->normals[0].size()) while (mesh->normals[0].size() < mesh->numVertices()) mesh->normals[0].
|
||||
push_back(zero);
|
||||
if (mesh->texcoords.size()) while (mesh->texcoords.size() < mesh->numVertices()) mesh->texcoords.
|
||||
push_back(zero);
|
||||
|
||||
if (mesh->normals[0].size() == 0)
|
||||
mesh->normals.clear();
|
||||
mesh->verify();
|
||||
}
|
||||
|
||||
curGroup.clear();
|
||||
ec.clear();
|
||||
}
|
||||
|
||||
Ref<SceneGraph::Node> loadOBJ(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject) {
|
||||
OBJLoader loader(fileName, subdivMode, combineIntoSingleObject);
|
||||
return loader.group.cast<SceneGraph::Node>();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue