11#define TINYOBJLOADER_IMPLEMENTATION
12#define TINYOBJLOADER_USE_DOUBLE
13#include <tiny_obj_loader.h>
14#include <robin_hood.h>
24using tinyobj::ObjReader;
32 tinyobj::attrib_t attrib;
33 std::vector<tinyobj::shape_t> shapes;
34 std::vector<tinyobj::material_t> materials;
39 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename);
43 std::cerr <<
" Loading: " << err << std::endl;
52 for (
size_t s = 0; s < shapes.size(); s++)
56 num_faces += shapes[s].mesh.indices.size() / 3;
60 size_t num_vertices = attrib.vertices.size() / 3;
64 mesh.
vertices =
new double[num_vertices * 3];
67 mesh.
faces =
new unsigned int[num_faces * 3];
70 for (
size_t s = 0; s < shapes.size(); s++)
73 size_t index_offset = 0;
74 for (
size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++)
76 int fv = shapes[s].mesh.num_face_vertices[f];
79 for (
size_t v = 0; v < fv; v++)
82 tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
84 tinyobj::real_t vx = attrib.vertices[3 * idx.vertex_index + 0];
85 tinyobj::real_t vy = attrib.vertices[3 * idx.vertex_index + 1];
86 tinyobj::real_t vz = attrib.vertices[3 * idx.vertex_index + 2];
90 mesh.
vertices[3 * idx.vertex_index + 0] = vx;
91 mesh.
vertices[3 * idx.vertex_index + 1] = vy;
92 mesh.
vertices[3 * idx.vertex_index + 2] = vz;
98 for (
size_t vi = 0; vi < shapes[s].mesh.indices.size(); vi++)
101 mesh.
faces[vi] = shapes[s].mesh.indices[vi].vertex_index;
113 {
"teapot",
"teapot.obj"},
114 {
"plane",
"plane.obj" },
115 {
"big teapot",
"big_teapot.obj" },
116 {
"energy blob",
"energy_blob.obj" },
117 {
"sibenik",
"sibenik.obj" },
122 tinyobj::ObjReader objloader;
125 if (!std::filesystem::exists(path)) {
126 std::cerr <<
" No file exists at " << path << std::endl;
130 tinyobj::ObjReaderConfig config;
131 config.triangulate =
true;
133 objloader.ParseFromFile(path, config);
136 if (!objloader.Valid() || objloader.GetShapes().size() == 0)
138 std::cerr <<
" The given file did not produce a valid mesh " << std::endl;
145 template <
typename T>
149 const int num_indices = shape.mesh.
indices.size();
150 out_shape.
indices.resize(num_indices);
151 for (
int i = 0; i < num_indices; i++)
152 out_shape.
indices[i] = shape.mesh.indices[i].vertex_index;
154 out_shape.
mat_ids = shape.mesh.material_ids;
158 template <
typename T>
159 vector<tinyobj_shape<T>>
MakeShapes(
const vector<tinyobj::shape_t>& shapes) {
160 vector<tinyobj_shape<T>> out_shapes(shapes.size());
162 for (
int i = 0; i < shapes.size(); i++)
163 out_shapes[i] = MakeShape<T>(shapes[i]);
168 vector<tinyobj_material>
MakeMaterials(
const vector<tinyobj::material_t> & materials) {
169 vector<tinyobj_material> out_mats(materials.size());
171 for (
int i = 0; i < materials.size(); i++)
172 out_mats[i].name = materials[i].name;
183 auto mats = reader.GetMaterials();
184 tinyobj::attrib_t attributes = reader.GetAttrib();
185 vector<tinyobj::shape_t> shapes = reader.GetShapes();
188 out_obj.
attributes.vertices = attributes.vertices;
189 out_obj.
shapes = MakeShapes<double>(shapes);
198 tinyobj::ObjReader objloader;
201 if (!std::filesystem::exists(path)) {
202 std::cerr <<
" No file exists at " << path << std::endl;
207 objloader.ParseFromFile(path);
210 if (!objloader.Valid() || objloader.GetShapes().size() == 0)
212 std::cerr <<
" The given file did not produce a valid mesh " << std::endl;
217 vector<MeshInfo<float>> MI;
218 auto mats = objloader.GetMaterials();
219 tinyobj::attrib_t attributes = objloader.GetAttrib();
220 vector<tinyobj::shape_t> shapes = objloader.GetShapes();
221 const vector<tinyobj::real_t>& verts = attributes.vertices;
228 std::string name =
"EntireFile";
232 auto vert_array =
static_cast<vector<double>
>(verts);
233 auto vert_scaled = vert_array;
235 std::transform(vert_array.begin(), vert_array.end(), vert_scaled.begin(),[&](
float i) { return i * scale; });
239 vector<float> vertexes(vert_array.size());
240 for (
int i = 0; i < vert_array.size(); i++)
241 vertexes[i] =
static_cast<float>(vert_array[i]);
247 for (
auto& shape : shapes)
248 index_count += shape.mesh.indices.size();
251 vector<int> index_array(index_count);
255 for (
auto& shape : shapes)
256 for (
auto& this_shape_index : shape.mesh.indices)
257 index_array[last_index++] = this_shape_index.vertex_index;
260 MI.emplace_back(
MeshInfo(vertexes, index_array, 0, name));
263 if (change_coords) MI[0].ConvertToRhinoCoordinates();
272 MI.resize(shapes.size());
273 vector<array<float, 3>> current_vertices;
276 for (
int k = 0; k < shapes.size(); k++) {
277 auto& shape = shapes[k];
279 std::string name = shape.name;
281 auto& indicies = shape.mesh.indices;
284 for (
int i = 0; i < indicies.size(); i++) {
285 tinyobj::index_t idx = indicies[i];
287 int vertex_index = 3 * idx.vertex_index;
288 float x = verts[vertex_index];
289 float y = verts[1 + vertex_index];
290 float z = verts[2 + vertex_index];
292 current_vertices.emplace_back(array<float, 3>{x, y, z});
296 MI[k] =
MeshInfo(current_vertices,
id, name);
297 if (change_coords) MI[k].ConvertToRhinoCoordinates();
304 std::cerr <<
"[C++] No materials found in model " << path <<
". Grouping by obj group";
309 MI.resize(mats.size());
310 vector<vector< array<float, 3 >>> verts_by_mat_id(mats.size());
313 vector<std::string> names;
314 for (
int i = 0; i < mats.size(); i++)
315 names.emplace_back(path +
"/" + mats[i].name);
318 for (
int k = 0; k < shapes.size(); k++) {
319 auto& shape = shapes[k];
320 vector<int>& mat_ids = shape.mesh.material_ids;
321 vector<tinyobj::index_t>& indicies = shape.mesh.indices;
324 for (
int i = 0; i < indicies.size(); i++) {
325 tinyobj::index_t idx = indicies[i];
327 int vertex_index = 3 * idx.vertex_index;
329 float x = verts[vertex_index];
330 float y = verts[1 + vertex_index];
331 float z = verts[2 + vertex_index];
334 int face =
static_cast<int>(floor(i / 3));
337 if (mats.size() > 0 && mat_ids.size() > face) {
338 int mat_index = mat_ids[face];
340 verts_by_mat_id[mat_index].emplace_back(array<float, 3>{x, y, z});
346 for (
int i = 0; i < names.size(); i++) {
347 auto& mesh = verts_by_mat_id[i];
348 if (mesh.empty())
continue;
351 MI.push_back(
MeshInfo(mesh, i, names[i]));
352 if (change_coords) MI[i].ConvertToRhinoCoordinates();
359 std::cerr <<
"Mesh group mode" << gm <<
" doesn't exist!" << std::endl;
360 throw std::exception();
365 if (MI.size() == 0) {
374 tinyobj::ObjReader objloader;
375 objloader.ParseFromFile(path);
379 auto mats = objloader.GetMaterials();
380 tinyobj::attrib_t attributes = objloader.GetAttrib();
381 vector<tinyobj::shape_t> shapes = objloader.GetShapes();
382 vector<tinyobj::real_t>& verts = attributes.vertices;
385 vector<array<float, 3>> out_verts;
388 for (
auto& shape : shapes) {
389 auto& indicies = shape.mesh.indices;
392 for (
int i = 0; i < indicies.size(); i++) {
393 tinyobj::index_t idx = indicies[i];
395 int vertex_index = 3 * idx.vertex_index;
397 float x = verts[vertex_index];
398 float y = verts[1 + vertex_index];
399 float z = verts[2 + vertex_index];
400 out_verts.emplace_back(array<float, 3>{x, y, z});
415 vector<vector<MeshInfo<float>>> MeshObjects(path.size());
416 for (
int i = 0; i < path.size(); i++)
420 vector<MeshInfo<float>> MI;
422 for (
int i = 0; i < MeshObjects.size(); i++) {
423 for (
auto& mi : MeshObjects[i]) {
425 MI.back().SetMeshID(lid++);
Contains definitions for the Exceptions namespace.
Contains definitions for the MeshInfo class.
Contains definitions for the Geometry namespace.
Manipulate and load geometry from disk.
vector< tinyobj_shape< T > > MakeShapes(const vector< tinyobj::shape_t > &shapes)
vector< MeshInfo< float > > LoadMeshObjects(std::string path, GROUP_METHOD gm, bool change_coords, int scale)
Create MeshInfo instances from the OBJ at path.
std::vector< int > mat_ids
static robin_hood::unordered_map< string, string > test_model_paths
tinyobj_shape< T > MakeShape(const tinyobj::shape_t &shape)
std::vector< tinyobj_material > materials
tinyobj_attr< T > attributes
std::vector< tinyobj_shape< T > > shapes
tinyobj_geometry< double > LoadMeshesFromTinyOBJ(std::string path)
GROUP_METHOD
Method of grouping submeshes in OBJ files.
@ ONLY_FILE
Treat all the geometry in the file as a single mesh.
@ BY_MATERIAL
Create a new MeshInfo instance for every different material in the file.
@ BY_GROUP
Create a new MeshInfo instance for every OBJ group in the file.
vector< tinyobj_material > MakeMaterials(const vector< tinyobj::material_t > &materials)
std::vector< int > indices
std::string GetTestOBJPath(std::string key)
Get the path to the OBJ with the given key.
vector< array< float, 3 > > LoadRawVertices(std::string path)
Load a list of vertices directly from an OBJ file.
tinyobj::ObjReader CreateReader(const std::string &path)
unsigned int * faces
[xyz] * 3(triangle) * num_faces
bool LoadObj(Mesh &mesh, const char *filename)
Thrown when desired file is not found.
The OBJ file was not valid.
A collection of vertices and indices representing geometry.