forked from textiles-lab/autoknit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
load_obj.cpp
139 lines (125 loc) · 4.1 KB
/
load_obj.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "pipeline.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_set>
#include <glm/gtx/hash.hpp>
void ak::load_obj(
std::string const &file,
ak::Model *model_
) {
assert(model_);
auto &model = *model_;
model.vertices.clear();
model.triangles.clear();
std::ifstream in(file);
uint32_t tri_faces = 0;
std::string line;
while (std::getline(in, line)) {
{ //strip comments
auto idx = line.find('#');
if (idx != std::string::npos) {
line = line.substr(0, idx);
}
}
std::istringstream iss(line);
std::vector< std::string > tokens;
{
std::string tok;
while (iss >> tok) {
tokens.emplace_back(tok);
}
}
if (tokens.empty()) continue; //blank line
if (tokens[0] == "v") {
//vertex position (x,y,z, [w])
if (!(tokens.size() == 3 || tokens.size() == 4)) {
throw std::runtime_error("'v' command should have 3 or 4 arguments");
}
glm::vec3 pos;
pos.x = std::stof(tokens[1]);
pos.y = std::stof(tokens[2]);
pos.z = std::stof(tokens[3]);
model.vertices.emplace_back(pos);
} else if (tokens[0] == "f") {
//face
if (tokens.size() < 4) {
throw std::runtime_error("'f' command should have at least 3 arguments");
}
if (tokens.size() > 4) {
++tri_faces;
}
glm::ivec3 tri;
tri.x = std::stoi(tokens[1]);
if (tri.x < 0) tri.x += model.vertices.size();
tri.y = std::stoi(tokens[2]);
if (tri.y < 0) tri.y += model.vertices.size();
//turn face into a triangle fan:
for (uint32_t i = 3; i < tokens.size(); ++i) {
tri.z = std::stoi(tokens[i]);
if (tri.z < 0) tri.z += model.vertices.size();
model.triangles.emplace_back(tri);
tri.y = tri.z;
}
} else if (tokens[0] == "vt") {
//"texture coordinate" -- ignored
} else if (tokens[0] == "vn") {
//"vertex normal" -- ignored
} else if (tokens[0] == "vp") {
//"parameter-space vertex" -- ignored
} else if (tokens[0] == "l") {
//"line" -- ignored
} else if (tokens[0] == "mtllib") {
//"material template library" -- ignored
} else if (tokens[0] == "usemtl") {
//"material name" -- ignored
} else if (tokens[0] == "o") {
//"object" -- ignored
} else if (tokens[0] == "g") {
//"group" -- ignored
} else {
std::cerr << "WARNING: unknown obj command '" << tokens[0] << "'" << std::endl;
}
}
std::cout << "Read " << model.vertices.size() << " vertices and " << model.triangles.size() << " triangles from '" << file << "'." << std::endl;
if (tri_faces) {
std::cerr << "WARNING: had to triangulate " << tri_faces << " faces." << std::endl;
}
//validate + properly index triangles:
for (auto &t : model.triangles) {
for (uint32_t i = 0; i < 3; ++i) {
if (t[i] < 1 || t[i] > model.vertices.size()) {
throw std::runtime_error("Invalid triangle index.");
}
t[i] -= 1;
}
}
//PARANOIA: degenerate triangle check.
uint32_t topologically_degenerate = 0;
uint32_t numerically_degenerate = 0;
for (auto const &tri : model.triangles) {
glm::vec3 const &x = model.vertices[tri.x];
glm::vec3 const &y = model.vertices[tri.y];
glm::vec3 const &z = model.vertices[tri.z];
if (tri.x == tri.y || tri.x == tri.z || tri.y == tri.z) {
++topologically_degenerate;
}
if (x == y || x == z || y == z) {
++numerically_degenerate;
}
}
if (topologically_degenerate || numerically_degenerate) {
std::cerr << "WARNING: have " << topologically_degenerate << " topologically degenerate and " << numerically_degenerate << " numerically degenerate triangles. This is likely to mess things up!" << std::endl;
}
//PARANOIA: manifold + oriented
uint32_t nonmanifold = 0;
std::unordered_set< glm::uvec2 > oriented_edges;
for (auto const &tri : model.triangles) {
if (!oriented_edges.insert(glm::uvec2(tri.x, tri.y)).second) ++nonmanifold;
if (!oriented_edges.insert(glm::uvec2(tri.y, tri.z)).second) ++nonmanifold;
if (!oriented_edges.insert(glm::uvec2(tri.z, tri.x)).second) ++nonmanifold;
}
if (nonmanifold) {
std::cerr << "WARNING: have " << nonmanifold << " oriented edges that appear more than once; this means the mesh is probably not an orientable manifold, which is likely to mess things up!" << std::endl;
}
}