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#include "viewer.h"
28
29#include <unordered_map>
30
31#include <easy3d/core/surface_mesh.h>
32#include <easy3d/core/surface_mesh_builder.h>
33#include <easy3d/renderer/texture_manager.h>
34#include <easy3d/renderer/camera.h>
35#include <easy3d/renderer/drawable_triangles.h>
36#include <easy3d/renderer/renderer.h>
37#include <easy3d/algo/tessellator.h>
38#include <easy3d/util/file_system.h>
39#include <easy3d/util/logging.h>
40
41#define FAST_OBJ_IMPLEMENTATION
42#include <3rd_party/fastobj/fast_obj.h>
43
44
46
47
48
49 TexturedViewer::TexturedViewer(const std::string &title)
50 : Viewer(title) {
51 camera()->setUpVector(
vec3(0, 1, 0));
52 }
53
54 namespace internal {
55
56
57 struct Group : public std::vector<SurfaceMesh::Face> {
58 vec3 ambient;
59 vec3 diffuse;
60 vec3 specular;
61 float shininess;
62 std::string tex_file;
63 };
64 }
65
66
67 Model* TexturedViewer::add_model(const std::string &file_name, bool create_default_drawables) {
68 clear_scene();
69
71 LOG(ERROR) << "file does not exist: " << file_name;
72 return nullptr;
73 }
74
77
78 fastObjMesh *fom = fast_obj_read(file_name.c_str());
79 if (!fom) {
80 LOG(ERROR) << "failed reading file: " + file_name;
81 return nullptr;
82 }
83
84
85
86
87
88
89
90
91 auto mesh = new SurfaceMesh;
92 mesh->set_name(file_name);
93
94 SurfaceMeshBuilder builder(mesh);
95 builder.begin_surface();
96
97
98
99 for (std::size_t v = 1; v < fom->position_count; ++v) {
100
101 builder.add_vertex(
vec3(fom->positions + v * 3));
102 }
103
104
105 SurfaceMesh::HalfedgeProperty<vec2> prop_texcoords;
106 if (fom->texcoord_count > 0 && fom->texcoords)
107 prop_texcoords = mesh->add_halfedge_property<
vec2>(
"h:texcoord");
108
109
110 SurfaceMesh::FaceProperty<vec3> prop_face_color;
111 if (fom->material_count > 0 && fom->materials)
112 prop_face_color = mesh->add_face_property<
vec3>(
"f:color");
113
114
115 auto find_face_halfedge = [](SurfaceMesh *mesh, SurfaceMesh::Face face,
116 SurfaceMesh::Vertex v) -> SurfaceMesh::Halfedge {
117 for (auto h : mesh->halfedges(face)) {
118 if (mesh->target(h) == v)
119 return h;
120 }
121 LOG_N_TIMES(3, ERROR) << "failed to find halfedge pointing to " << v << " in face " << face << ". " << COUNTER;
122 return SurfaceMesh::Halfedge();
123 };
124
125
126
127 std::vector<internal::Group> groups(fom->material_count);
128
129
130 for (std::size_t ii = 0; ii < fom->group_count; ii++) {
131 const fastObjGroup &grp = fom->groups[ii];
132
133
134
135
136 unsigned int idx = 0;
137 for (unsigned int jj = 0; jj < grp.face_count; ++jj) {
138
139 unsigned int fv = fom->face_vertices[grp.face_offset + jj];
140 std::vector<SurfaceMesh::Vertex> vertices;
141 std::vector<unsigned int> texcoord_ids;
142 for (unsigned int kk = 0; kk < fv; ++kk) {
143 const fastObjIndex &mi = fom->indices[grp.index_offset + idx];
144 if (mi.p)
145 vertices.emplace_back(SurfaceMesh::Vertex(static_cast<int>(mi.p - 1)));
146 if (mi.t)
147 texcoord_ids.emplace_back(mi.t);
148 ++idx;
149 }
150
151 SurfaceMesh::Face face = builder.add_face(vertices);
152 if (face.is_valid()) {
153
154 if (prop_texcoords && texcoord_ids.size() == vertices.size()) {
155 auto begin = find_face_halfedge(mesh, face, builder.face_vertices()[0]);
156 auto cur = begin;
157 unsigned int vid = 0;
158 do {
159 unsigned int tid = texcoord_ids[vid++];
160 prop_texcoords[cur] =
vec2(fom->texcoords + 2 * tid);
161 cur = mesh->next(cur);
162 } while (cur != begin);
163 }
164
165
166 if (prop_face_color) {
167 unsigned int mat_id = fom->face_materials[grp.face_offset + jj];
168 const fastObjMaterial &mat = fom->materials[mat_id];
169 prop_face_color[face] =
vec3(mat.Kd);
170 }
171
172 auto get_file_name = [](const char *name, const char* path) -> std::string {
173 std::string file_name;
175 file_name = std::string(name);
177 file_name = std::string(path);
178 else if (name && path){
179 const std::string test_name = std::string(path) + "/" + std::string(name);
181 file_name = test_name;
182 }
183 return file_name;
184 };
185
186 if (fom->material_count > 0 && fom->materials) {
187 unsigned int mat_id = fom->face_materials[grp.face_offset + jj];
188 const fastObjMaterial &mat = fom->materials[mat_id];
189 auto &g = groups[mat_id];
190 g.push_back(face);
191 g.ambient =
vec3(mat.Ka);
192 g.diffuse =
vec3(mat.Kd);
193 g.specular =
vec3(mat.Ks);
194 g.shininess = static_cast<float>(mat.Ns);
195 g.tex_file = get_file_name(mat.map_Ka.name, mat.map_Ka.path);
196 if (g.tex_file.empty())
197 g.tex_file = get_file_name(mat.map_Kd.name, mat.map_Kd.path);
198 if (g.tex_file.empty())
199 g.tex_file = get_file_name(mat.map_Ks.name, mat.map_Ks.path);
200 }
201 }
202 }
203 }
204
205 builder.end_surface();
206
207
208 if (fom->material_count == 0 || !fom->materials)
209 return Viewer::add_model(std::shared_ptr<SurfaceMesh>(mesh), create_default_drawables);
210 else
212
213 mesh->update_vertex_normals();
214 auto normals = mesh->get_vertex_property<
vec3>(
"v:normal");
215 auto points = mesh->get_vertex_property<
vec3>(
"v:point");
216
217 Tessellator tessellator;
218 for (std::size_t i = 0; i < groups.size(); ++i) {
219 const auto &group = groups[i];
220 if (group.empty())
221 continue;
222
223 tessellator.reset();
224
225 for (auto face : group) {
226 tessellator.begin_polygon(mesh->compute_face_normal(face));
227 tessellator.set_winding_rule(Tessellator::WINDING_NONZERO);
228 tessellator.begin_contour();
229 for (auto h : mesh->halfedges(face)) {
230 auto v = mesh->target(h);
231 Tessellator::Vertex vtx(points[v], v.idx());
232 vtx.append(normals[v]);
233 if (prop_texcoords)
234 vtx.append(prop_texcoords[h]);
235 if (prop_face_color)
236 vtx.append(prop_face_color[face]);
237 tessellator.add_vertex(vtx);
238 }
239 tessellator.end_contour();
240 tessellator.end_polygon();
241 }
242
243 std::vector<vec3> d_points, d_colors, d_normals;
244 std::vector<vec2> d_texcoords;
245 const std::vector<Tessellator::Vertex*>& vts = tessellator.vertices();
246 for (auto v :vts) {
247 std::size_t offset = 0;
248 d_points.emplace_back(v->data() + offset);
249 offset += 3;
250 d_normals.emplace_back(v->data() + offset);
251 offset += 3;
252 if (prop_texcoords) {
253 d_texcoords.emplace_back(v->data() + offset);
254 offset += 2;
255 }
256 if (prop_face_color)
257 d_colors.emplace_back(v->data() + offset);
258 }
259
260 const auto &d_indices = tessellator.elements();
261
262 auto drawable = mesh->renderer()->add_triangles_drawable("faces_" + std::to_string(i));
263
264 drawable->update_element_buffer(d_indices);
265 drawable->update_vertex_buffer(d_points);
266 drawable->update_normal_buffer(d_normals);
267 if (!d_colors.empty())
268 drawable->update_color_buffer(d_colors);
269 if (!d_texcoords.empty())
270 drawable->update_texcoord_buffer(d_texcoords);
271
272 drawable->set_smooth_shading(false);
273 drawable->set_distinct_back_color(false);
274 if (prop_texcoords) {
275 if (!group.tex_file.empty()) {
277 if (tex) {
279 drawable->set_distinct_back_color(false);
280 LOG(INFO) << "texture created from " << group.tex_file;
281 }
282 }
283 }
284
285 if (!drawable->texture()) {
286 if (prop_face_color)
288 else
289 drawable->set_uniform_coloring(
vec4(group.diffuse, 1.0f));
290 }
291 }
292
293 return mesh;
294 }
295
296
297
298}
@ FACE
Property defined on faces.
Definition state.h:70
@ HALFEDGE
Property defined on halfedges.
Definition state.h:72
@ REPEAT
Repeat the texture coordinate.
Definition texture.h:47
static Texture * request(const std::string &image_file, Texture::WrapMode wrap=Texture::CLAMP_TO_EDGE, Texture::FilterMode filter=Texture::LINEAR)
Request a texture from the image file.
Definition texture_manager.cpp:40
virtual Model * add_model(const std::string &file_name, bool create_default_drawables=true)
Add a model from a file to the viewer to be visualized. On success, the viewer will be in charge of t...
Definition viewer.cpp:1242
bool is_file(const std::string &path)
Tests if 'path' is an existing file.
std::string extension(const std::string &path, bool lower=true)
Query the file extension without dot (e.g., /a/b/c.Ext => Ext).
Vec< 3, float > vec3
A 3D point/vector of float type.
Definition types.h:44
Vec< 4, float > vec4
A 4D point/vector of float type.
Definition types.h:46
Vec< 2, float > vec2
A 2D point/vector of float type.
Definition types.h:42