-
Notifications
You must be signed in to change notification settings - Fork 126
Expand file tree
/
Copy pathOBJ.cpp
More file actions
143 lines (122 loc) · 4.84 KB
/
OBJ.cpp
File metadata and controls
143 lines (122 loc) · 4.84 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
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
140
141
142
143
#include "check_gl.hpp"
#include "OBJ.hpp"
#include "Game.hpp"
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <sstream>
void OBJ::load_obj(std::string path, bool grouped) {
std::ifstream file(path);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << path << '\n';
return;
}
std::string line;
unsigned int current_group = 0;
while (std::getline(file, line)) {
if (line.substr(0, 2) == "v ") {
std::istringstream s(line.substr(2));
glm::vec3 vertex;
s >> vertex.x >> vertex.y >> vertex.z;
vertices.push_back(vertex);
} else if (line.substr(0, 2) == "f ") {
std::istringstream s(line.substr(2));
std::string splitted;
std::vector<unsigned int> indices;
while (std::getline(s, splitted, ' ')) {
unsigned int index = 1;
std::istringstream(splitted) >> index;
indices.push_back(index - 1);
}
for (size_t i = 2; i < indices.size(); i++) {
glm::uvec3 face = glm::uvec3(indices[0], indices[i - 1], indices[i]);
faces.push_back(face);
smoothing_groups[current_group].push_back(faces.size() - 1);
}
} else if (line.substr(0, 7) == "#group ") {
std::istringstream s(line.substr(7));
unsigned int group;
s >> group;
if (grouped) current_group = group;
}
}
file.close();
std::cout << "Loaded " << vertices.size() << " vertices, " << faces.size() << " faces.\n";
}
static glm::vec3 perspective_divide(glm::vec4 pos) {
return glm::vec3(pos.x / pos.w, pos.y / pos.w, pos.z / pos.w);
}
static glm::vec3 compute_normal(glm::vec3 a, glm::vec3 b, glm::vec3 c) {
// jisuan sanjiaoxin faxian
glm::vec3 ab = b - a;
glm::vec3 ac = c - a;
return glm::normalize(glm::cross(ab, ac));
}
static glm::vec3 compute_contrib_normal(glm::vec3 v0, glm::vec3 v1, glm::vec3 v2, uint32_t vert) {
std::vector<glm::vec3> face = {v0, v1, v2};
auto const& a = face.at(vert);
auto const& b = face.at((vert + 1) % 3);
auto const& c = face.at((vert + 2) % 3);
glm::vec3 ab = b - a;
glm::vec3 ac = c - a;
glm::vec3 norm = glm::cross(ab, ac);
float contrib_w = asinf(static_cast<float>(norm.length()) / (ab.length() * ac.length()));
return glm::normalize(norm) * contrib_w;
}
static void object_draw_flat_pass(OBJ const& obj) {
glBegin(GL_TRIANGLES);
for (auto face : obj.faces) {
auto const& a = obj.vertices.at(face[0]);
auto const& b = obj.vertices.at(face[1]);
auto const& c = obj.vertices.at(face[2]);
glm::vec3 norm = compute_normal(a, b, c);
glNormal3fv(glm::value_ptr(norm));
glVertex3fv(glm::value_ptr(a));
glVertex3fv(glm::value_ptr(b));
glVertex3fv(glm::value_ptr(c));
}
CHECK_GL(glEnd());
}
static void normal_compute_pass(OBJ const& obj, std::vector<unsigned int> const& face_indices, std::vector<glm::vec3>& vertex_normal_buffer) {
for (auto const& index : face_indices) {
auto const& face = obj.faces.at(index);
auto const& a = obj.vertices.at(face[0]);
auto const& b = obj.vertices.at(face[1]);
auto const& c = obj.vertices.at(face[2]);
vertex_normal_buffer[face[0]] += compute_contrib_normal(a, b, c, 0);
vertex_normal_buffer[face[1]] += compute_contrib_normal(a, b, c, 1);
vertex_normal_buffer[face[2]] += compute_contrib_normal(a, b, c, 2);
}
for (auto& vn : vertex_normal_buffer) {
vn = glm::normalize(vn);
}
}
static void object_draw_smooth_pass(OBJ const& obj, std::vector<unsigned int> const& face_indices, std::vector<glm::vec3> const& vertex_normal_buffer) {
glBegin(GL_TRIANGLES);
for (auto const& index : face_indices) {
auto const& face = obj.faces.at(index);
auto const& a = obj.vertices.at(face[0]);
auto const& b = obj.vertices.at(face[1]);
auto const& c = obj.vertices.at(face[2]);
auto const& n0 = vertex_normal_buffer.at(face[0]);
auto const& n1 = vertex_normal_buffer.at(face[1]);
auto const& n2 = vertex_normal_buffer.at(face[2]);
glNormal3fv(glm::value_ptr(n0));
glVertex3fv(glm::value_ptr(a));
glNormal3fv(glm::value_ptr(n1));
glVertex3fv(glm::value_ptr(b));
glNormal3fv(glm::value_ptr(n2));
glVertex3fv(glm::value_ptr(c));
}
CHECK_GL(glEnd());
}
void OBJ::draw_obj() {
object_draw_flat_pass(*this);
}
void OBJ::draw_obj_smooth() {
for (auto const& [i, group] : smoothing_groups) {
std::vector<glm::vec3> vert_norm_buffer(vertices.size(), glm::vec3(0.0f));
normal_compute_pass(*this, group, vert_norm_buffer);
object_draw_smooth_pass(*this, group, vert_norm_buffer);
}
}