Repository navigation
Expand file tree
/
Copy pathObj_loader.cpp
More file actions
108 lines (95 loc) · 4.48 KB
/
Copy pathObj_loader.cpp
File metadata and controls
108 lines (95 loc) · 4.48 KB
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
#include "Obj_loader.h"
#include <sstream>
#include <iostream>
#include <array>
// Load OBJ file and create Object
Object ObjLoader::load_object(std::string obj_path, std::string texture_path, float3 position, float3 rotation, std::string name){
// Resolve full paths
obj_path = std::filesystem::current_path().string() + obj_path;
texture_path = std::filesystem::current_path().string() + texture_path;
std::string obj_string = StringHelper::readFileToString(obj_path);
// Load and parse OBJ
auto mesh_data = load_obj_file(obj_string);
std::vector<float3> object_points = std::get<0>(mesh_data);
std::vector<float3> object_normals = std::get<1>(mesh_data);
std::vector<float2> texture_coords = std::get<2>(mesh_data);
if (object_points.empty()) {
std::cerr << "Failed to load model or model is empty!" << std::endl;
throw std::runtime_error("Failed to load model: " + obj_path);
}
// Create random colors
std::vector<float3> triangle_colors(object_points.size() / 3);
for (size_t i = 0; i < triangle_colors.size(); i++) {
triangle_colors[i] = Math::random_color();
}
// Load texture + shader
auto texture = std::make_shared<MeshTexture>(
MeshTexture::CreateFromBytes(ImageLoader::png_file_to_bytes(texture_path))
);
if(!texture){
std::cerr << "Failed to load texture" << std::endl;
throw std::runtime_error("Failed to load texture: " + texture_path);
}
// Create shader
auto shader = std::make_shared<LitTextureShader>(texture, float3(0, 1, 0));
// Create mesh and object
ObjectMesh mesh(object_points, object_normals, texture_coords);
return Object(mesh, shader, name, triangle_colors, position, rotation);
}
// OBJ parser
std::tuple<std::vector<float3>, std::vector<float3>, std::vector<float2>>
ObjLoader::load_obj_file(std::string objString) {
std::vector<float3> positions;
std::vector<float3> normals_all;
std::vector<float2> texcoords_all;
std::vector<float3> out_vertices;
std::vector<float3> out_normals;
std::vector<float2> out_texcoords;
// Parse OBJ line by line
std::istringstream stream(objString);
std::string line;
while (std::getline(stream, line)) {
if (line.rfind("v ", 0) == 0) { // vertex position
auto parts = StringHelper::split(line.substr(2), ' ');
if (parts.size() < 3) continue;
positions.emplace_back(std::stof(parts[0]), std::stof(parts[1]), std::stof(parts[2]));
}
// Texture coordinate
else if (line.rfind("vt", 0) == 0) {
auto parts = StringHelper::split(line.substr(3), ' ');
if (parts.size() < 2) continue;
float u = std::stof(parts[0]);
float v = std::stof(parts[1]);
texcoords_all.emplace_back(u, 1.0f - v); // flip V
}
// Normal vector
else if (line.rfind("vn", 0) == 0) {
auto parts = StringHelper::split(line.substr(3), ' ');
if (parts.size() < 3) continue;
normals_all.emplace_back(std::stof(parts[0]), std::stof(parts[1]), std::stof(parts[2]));
}
// Face definition
else if (line.rfind("f ", 0) == 0) {
auto faceIndexGroups = StringHelper::split(line.substr(2), ' ');
// Triangulate (fan method)
for (int i = 1; i + 1 < (int)faceIndexGroups.size(); i++) {
std::array<std::string,3> tri = { faceIndexGroups[0], faceIndexGroups[i], faceIndexGroups[i+1] };
for (auto& vertStr : tri) {
// Parse vertex/texcoord/normal indices
auto idx = StringHelper::split(vertStr, '/');
int vi = (idx.size() > 0 && !idx[0].empty()) ? std::stoi(idx[0]) - 1 : -1;
int ti = (idx.size() > 1 && !idx[1].empty()) ? std::stoi(idx[1]) - 1 : -1;
int ni = (idx.size() > 2 && !idx[2].empty()) ? std::stoi(idx[2]) - 1 : -1;
// Add vertex data to output arrays
if (vi >= 0) out_vertices.push_back(positions[vi]);
if (ti >= 0) out_texcoords.push_back(texcoords_all[ti]);
else out_texcoords.emplace_back(0,0);
if (ni >= 0) out_normals.push_back(normals_all[ni]);
else out_normals.emplace_back(0,0,1);
}
}
}
}
// Return parsed data
return std::make_tuple(out_vertices, out_normals, out_texcoords);
}