Blender  V3.3
obj_import_mesh.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "DNA_material_types.h"
8 #include "DNA_mesh_types.h"
9 #include "DNA_scene_types.h"
10 
11 #include "BKE_attribute.h"
12 #include "BKE_customdata.h"
13 #include "BKE_deform.h"
14 #include "BKE_material.h"
15 #include "BKE_mesh.h"
16 #include "BKE_node_tree_update.h"
17 #include "BKE_object.h"
18 #include "BKE_object_deform.h"
19 
20 #include "BLI_math_vector.h"
21 #include "BLI_set.hh"
22 
23 #include "IO_wavefront_obj.h"
24 #include "importer_mesh_utils.hh"
25 #include "obj_import_mesh.hh"
26 
27 namespace blender::io::obj {
28 
30  Map<std::string, std::unique_ptr<MTLMaterial>> &materials,
31  Map<std::string, Material *> &created_materials,
32  const OBJImportParams &import_params)
33 {
34  const int64_t tot_verts_object{mesh_geometry_.get_vertex_count()};
35  if (tot_verts_object <= 0) {
36  /* Empty mesh */
37  return nullptr;
38  }
39  std::string ob_name{mesh_geometry_.geometry_name_};
40  if (ob_name.empty()) {
41  ob_name = "Untitled";
42  }
43  fixup_invalid_faces();
44 
45  /* Total explicitly imported edges, not the ones belonging the polygons to be created. */
46  const int64_t tot_edges{mesh_geometry_.edges_.size()};
47  const int64_t tot_face_elems{mesh_geometry_.face_elements_.size()};
48  const int64_t tot_loops{mesh_geometry_.total_loops_};
49 
50  Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object, tot_edges, 0, tot_loops, tot_face_elems);
51  Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name.c_str());
52  obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str());
53 
54  create_vertices(mesh);
55  create_polys_loops(mesh, import_params.import_vertex_groups);
56  create_edges(mesh);
57  create_uv_verts(mesh);
58  create_normals(mesh);
59  create_colors(mesh);
60  create_materials(bmain, materials, created_materials, obj, import_params.relative_paths);
61 
62  if (import_params.validate_meshes || mesh_geometry_.has_invalid_polys_) {
63  bool verbose_validate = false;
64 #ifdef DEBUG
65  verbose_validate = true;
66 #endif
67  BKE_mesh_validate(mesh, verbose_validate, false);
68  }
69  transform_object(obj, import_params);
70 
71  /* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
72  const uint16_t autosmooth = (mesh->flag & ME_AUTOSMOOTH);
73  Mesh *dst = static_cast<Mesh *>(obj->data);
75  dst->flag |= autosmooth;
76 
77  /* NOTE: vertex groups have to be created after final mesh is assigned to the object. */
78  create_vertex_groups(obj);
79 
80  return obj;
81 }
82 
83 void MeshFromGeometry::fixup_invalid_faces()
84 {
85  for (int64_t face_idx = 0; face_idx < mesh_geometry_.face_elements_.size(); ++face_idx) {
86  const PolyElem &curr_face = mesh_geometry_.face_elements_[face_idx];
87 
88  if (curr_face.corner_count_ < 3) {
89  /* Skip and remove faces that have fewer than 3 corners. */
90  mesh_geometry_.total_loops_ -= curr_face.corner_count_;
91  mesh_geometry_.face_elements_.remove_and_reorder(face_idx);
92  continue;
93  }
94 
95  /* Check if face is invalid for Blender conventions:
96  * basically whether it has duplicate vertex indices. */
97  bool valid = true;
98  Set<int, 8> used_verts;
99  for (int i = 0; i < curr_face.corner_count_; ++i) {
100  int corner_idx = curr_face.start_index_ + i;
101  int vertex_idx = mesh_geometry_.face_corners_[corner_idx].vert_index;
102  if (used_verts.contains(vertex_idx)) {
103  valid = false;
104  break;
105  }
106  used_verts.add(vertex_idx);
107  }
108  if (valid) {
109  continue;
110  }
111 
112  /* We have an invalid face, have to turn it into possibly
113  * multiple valid faces. */
114  Vector<int, 8> face_verts;
115  Vector<int, 8> face_uvs;
116  Vector<int, 8> face_normals;
117  face_verts.reserve(curr_face.corner_count_);
118  face_uvs.reserve(curr_face.corner_count_);
119  face_normals.reserve(curr_face.corner_count_);
120  for (int i = 0; i < curr_face.corner_count_; ++i) {
121  int corner_idx = curr_face.start_index_ + i;
122  const PolyCorner &corner = mesh_geometry_.face_corners_[corner_idx];
123  face_verts.append(corner.vert_index);
124  face_normals.append(corner.vertex_normal_index);
125  face_uvs.append(corner.uv_vert_index);
126  }
127  int face_vertex_group = curr_face.vertex_group_index;
128  int face_material = curr_face.material_index;
129  bool face_shaded_smooth = curr_face.shaded_smooth;
130 
131  /* Remove the invalid face. */
132  mesh_geometry_.total_loops_ -= curr_face.corner_count_;
133  mesh_geometry_.face_elements_.remove_and_reorder(face_idx);
134 
135  Vector<Vector<int>> new_faces = fixup_invalid_polygon(global_vertices_.vertices, face_verts);
136 
137  /* Create the newly formed faces. */
138  for (Span<int> face : new_faces) {
139  if (face.size() < 3) {
140  continue;
141  }
142  PolyElem new_face{};
143  new_face.vertex_group_index = face_vertex_group;
144  new_face.material_index = face_material;
145  new_face.shaded_smooth = face_shaded_smooth;
146  new_face.start_index_ = mesh_geometry_.face_corners_.size();
147  new_face.corner_count_ = face.size();
148  for (int idx : face) {
149  BLI_assert(idx >= 0 && idx < face_verts.size());
150  mesh_geometry_.face_corners_.append({face_verts[idx], face_uvs[idx], face_normals[idx]});
151  }
152  mesh_geometry_.face_elements_.append(new_face);
153  mesh_geometry_.total_loops_ += face.size();
154  }
155  }
156 }
157 
158 void MeshFromGeometry::create_vertices(Mesh *mesh)
159 {
160  /* Go through all the global vertex indices from min to max,
161  * checking which ones are actually and building a global->local
162  * index mapping. Write out the used vertex positions into the Mesh
163  * data. */
164  mesh_geometry_.global_to_local_vertices_.clear();
165  mesh_geometry_.global_to_local_vertices_.reserve(mesh_geometry_.vertices_.size());
166  for (int vi = mesh_geometry_.vertex_index_min_; vi <= mesh_geometry_.vertex_index_max_; ++vi) {
167  BLI_assert(vi >= 0 && vi < global_vertices_.vertices.size());
168  if (!mesh_geometry_.vertices_.contains(vi)) {
169  continue;
170  }
171  int local_vi = (int)mesh_geometry_.global_to_local_vertices_.size();
172  BLI_assert(local_vi >= 0 && local_vi < mesh->totvert);
173  copy_v3_v3(mesh->mvert[local_vi].co, global_vertices_.vertices[vi]);
174  mesh_geometry_.global_to_local_vertices_.add_new(vi, local_vi);
175  }
176 }
177 
178 void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
179 {
180  mesh->dvert = nullptr;
181  const int64_t total_verts = mesh_geometry_.get_vertex_count();
182  if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) {
183  mesh->dvert = static_cast<MDeformVert *>(
184  CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, total_verts));
185  }
186 
187  const int64_t tot_face_elems{mesh->totpoly};
188  int tot_loop_idx = 0;
189 
190  for (int poly_idx = 0; poly_idx < tot_face_elems; ++poly_idx) {
191  const PolyElem &curr_face = mesh_geometry_.face_elements_[poly_idx];
192  if (curr_face.corner_count_ < 3) {
193  /* Don't add single vertex face, or edges. */
194  std::cerr << "Face with less than 3 vertices found, skipping." << std::endl;
195  continue;
196  }
197 
198  MPoly &mpoly = mesh->mpoly[poly_idx];
199  mpoly.totloop = curr_face.corner_count_;
200  mpoly.loopstart = tot_loop_idx;
201  if (curr_face.shaded_smooth) {
202  mpoly.flag |= ME_SMOOTH;
203  }
204  mpoly.mat_nr = curr_face.material_index;
205  /* Importing obj files without any materials would result in negative indices, which is not
206  * supported. */
207  if (mpoly.mat_nr < 0) {
208  mpoly.mat_nr = 0;
209  }
210 
211  for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
212  const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
213  MLoop &mloop = mesh->mloop[tot_loop_idx];
214  tot_loop_idx++;
215  mloop.v = mesh_geometry_.global_to_local_vertices_.lookup_default(curr_corner.vert_index, 0);
216 
217  /* Setup vertex group data, if needed. */
218  if (!mesh->dvert) {
219  continue;
220  }
221  const int group_index = curr_face.vertex_group_index;
222  MDeformWeight *dw = BKE_defvert_ensure_index(mesh->dvert + mloop.v, group_index);
223  dw->weight = 1.0f;
224  }
225  }
226 }
227 
228 void MeshFromGeometry::create_vertex_groups(Object *obj)
229 {
230  Mesh *mesh = static_cast<Mesh *>(obj->data);
231  if (mesh->dvert == nullptr) {
232  return;
233  }
234  for (const std::string &name : mesh_geometry_.group_order_) {
235  BKE_object_defgroup_add_name(obj, name.data());
236  }
237 }
238 
239 void MeshFromGeometry::create_edges(Mesh *mesh)
240 {
241  const int64_t tot_edges{mesh_geometry_.edges_.size()};
242  const int64_t total_verts{mesh_geometry_.get_vertex_count()};
243  UNUSED_VARS_NDEBUG(total_verts);
244  for (int i = 0; i < tot_edges; ++i) {
245  const MEdge &src_edge = mesh_geometry_.edges_[i];
246  MEdge &dst_edge = mesh->medge[i];
247  dst_edge.v1 = mesh_geometry_.global_to_local_vertices_.lookup_default(src_edge.v1, 0);
248  dst_edge.v2 = mesh_geometry_.global_to_local_vertices_.lookup_default(src_edge.v2, 0);
249  BLI_assert(dst_edge.v1 < total_verts && dst_edge.v2 < total_verts);
250  dst_edge.flag = ME_LOOSEEDGE;
251  }
252 
253  /* Set argument `update` to true so that existing, explicitly imported edges can be merged
254  * with the new ones created from polygons. */
255  BKE_mesh_calc_edges(mesh, true, false);
257 }
258 
259 void MeshFromGeometry::create_uv_verts(Mesh *mesh)
260 {
261  if (global_vertices_.uv_vertices.size() <= 0) {
262  return;
263  }
264  MLoopUV *mluv_dst = static_cast<MLoopUV *>(CustomData_add_layer(
265  &mesh->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, mesh_geometry_.total_loops_));
266  int tot_loop_idx = 0;
267 
268  for (const PolyElem &curr_face : mesh_geometry_.face_elements_) {
269  for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
270  const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
271  const int uv_index = curr_corner.uv_vert_index;
272  float2 uv(0, 0);
273  if (uv_index >= 0 && uv_index < global_vertices_.uv_vertices.size()) {
274  uv = global_vertices_.uv_vertices[uv_index];
275  }
276  copy_v2_v2(mluv_dst[tot_loop_idx].uv, uv);
277  tot_loop_idx++;
278  }
279  }
280 }
281 
283  const std::string &name,
284  Map<std::string, std::unique_ptr<MTLMaterial>> &materials,
285  Map<std::string, Material *> &created_materials,
286  bool relative_paths)
287 {
288  /* Have we created this material already? */
289  Material **found_mat = created_materials.lookup_ptr(name);
290  if (found_mat != nullptr) {
291  return *found_mat;
292  }
293 
294  /* We have not, will have to create it. Create a new default
295  * MTLMaterial too, in case the OBJ file tries to use a material
296  * that was not in the MTL file. */
297  const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>());
298 
299  Material *mat = BKE_material_add(bmain, name.c_str());
300  id_us_min(&mat->id);
301 
302  ShaderNodetreeWrap mat_wrap{bmain, mtl, mat, relative_paths};
303  mat->use_nodes = true;
304  mat->nodetree = mat_wrap.get_nodetree();
305  BKE_ntree_update_main_tree(bmain, mat->nodetree, nullptr);
306 
307  created_materials.add_new(name, mat);
308  return mat;
309 }
310 
311 void MeshFromGeometry::create_materials(Main *bmain,
312  Map<std::string, std::unique_ptr<MTLMaterial>> &materials,
313  Map<std::string, Material *> &created_materials,
314  Object *obj,
315  bool relative_paths)
316 {
317  for (const std::string &name : mesh_geometry_.material_order_) {
319  bmain, name, materials, created_materials, relative_paths);
320  if (mat == nullptr) {
321  continue;
322  }
323  BKE_object_material_assign_single_obdata(bmain, obj, mat, obj->totcol + 1);
324  }
325  if (obj->totcol > 0) {
326  obj->actcol = 1;
327  }
328 }
329 
330 void MeshFromGeometry::create_normals(Mesh *mesh)
331 {
332  /* No normal data: nothing to do. */
333  if (global_vertices_.vertex_normals.is_empty()) {
334  return;
335  }
336  /* Custom normals can only be stored on face corners. */
337  if (mesh_geometry_.total_loops_ == 0) {
338  return;
339  }
340 
341  float(*loop_normals)[3] = static_cast<float(*)[3]>(
342  MEM_malloc_arrayN(mesh_geometry_.total_loops_, sizeof(float[3]), __func__));
343  int tot_loop_idx = 0;
344  for (const PolyElem &curr_face : mesh_geometry_.face_elements_) {
345  for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
346  const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
347  int n_index = curr_corner.vertex_normal_index;
348  float3 normal(0, 0, 0);
349  if (n_index >= 0) {
350  normal = global_vertices_.vertex_normals[n_index];
351  }
352  copy_v3_v3(loop_normals[tot_loop_idx], normal);
353  tot_loop_idx++;
354  }
355  }
356  mesh->flag |= ME_AUTOSMOOTH;
357  BKE_mesh_set_custom_normals(mesh, loop_normals);
358  MEM_freeN(loop_normals);
359 }
360 
361 void MeshFromGeometry::create_colors(Mesh *mesh)
362 {
363  /* Nothing to do if we don't have vertex colors at all. */
364  if (global_vertices_.vertex_colors.is_empty()) {
365  return;
366  }
367 
368  /* Find which vertex color block is for this mesh (if any). */
369  for (const auto &block : global_vertices_.vertex_colors) {
370  if (mesh_geometry_.vertex_index_min_ >= block.start_vertex_index &&
371  mesh_geometry_.vertex_index_max_ < block.start_vertex_index + block.colors.size()) {
372  /* This block is suitable, use colors from it. */
373  CustomDataLayer *color_layer = BKE_id_attribute_new(
374  &mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
375  float4 *colors = (float4 *)color_layer->data;
376  int offset = mesh_geometry_.vertex_index_min_ - block.start_vertex_index;
377  for (int i = 0, n = mesh_geometry_.get_vertex_count(); i != n; ++i) {
378  float3 c = block.colors[offset + i];
379  colors[i] = float4(c.x, c.y, c.z, 1.0f);
380  }
381  return;
382  }
383  }
384 }
385 
386 } // namespace blender::io::obj
typedef float(TangentPoint)[2]
Generic geometry attributes built on CustomData.
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
struct CustomDataLayer * BKE_id_attribute_new(struct ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports)
Definition: attribute.cc:220
CustomData interface, see also DNA_customdata_types.h.
const CustomData_MeshMasks CD_MASK_EVERYTHING
Definition: customdata.cc:2101
@ CD_CALLOC
@ CD_DEFAULT
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
void id_us_min(struct ID *id)
Definition: lib_id.c:313
General operations, lookup, etc. for materials.
void BKE_object_material_assign_single_obdata(struct Main *bmain, struct Object *ob, struct Material *ma, short act)
Definition: material.c:1052
struct Material * BKE_material_add(struct Main *bmain, const char *name)
Definition: material.c:289
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, const struct CustomData_MeshMasks *mask, bool take_ownership)
void BKE_mesh_calc_edges_loose(struct Mesh *mesh)
bool BKE_mesh_validate(struct Mesh *me, bool do_verbose, bool cddata_check_mask)
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
void BKE_mesh_set_custom_normals(struct Mesh *mesh, float(*r_custom_loopnors)[3])
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
void BKE_ntree_update_main_tree(struct Main *bmain, struct bNodeTree *ntree, struct NodeTreeUpdateExtraParams *params)
General operations, lookup, etc. for blender objects.
void * BKE_object_obdata_add_from_type(struct Main *bmain, int type, const char *name) ATTR_NONNULL(1)
Definition: object.cc:2161
struct Object * BKE_object_add_only_object(struct Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
Definition: object.cc:2241
Functions for dealing with objects and deform verts, used by painting and tools.
struct bDeformGroup * BKE_object_defgroup_add_name(struct Object *ob, const char *name)
Definition: object_deform.c:95
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS_NDEBUG(...)
@ CD_MDEFORMVERT
@ CD_PROP_COLOR
@ CD_MLOOPUV
@ ME_AUTOSMOOTH
@ ME_SMOOTH
@ ME_LOOSEEDGE
@ OB_MESH
void clear()
Definition: BLI_map.hh:963
Value lookup_default(const Key &key, const Value &default_value) const
Definition: BLI_map.hh:510
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:220
int64_t size() const
Definition: BLI_map.hh:901
void reserve(int64_t n)
Definition: BLI_map.hh:953
const Value * lookup_ptr(const Key &key) const
Definition: BLI_map.hh:463
int64_t size() const
Definition: BLI_set.hh:539
bool contains(const Key &key) const
Definition: BLI_set.hh:296
bool add(const Key &key)
Definition: BLI_set.hh:253
int64_t size() const
Definition: BLI_vector.hh:694
Object * create_mesh(Main *bmain, Map< std::string, std::unique_ptr< MTLMaterial >> &materials, Map< std::string, Material * > &created_materials, const OBJImportParams &import_params)
smooth(Type::VEC4, "color_mul") .smooth(Type gpFillTexture gpSceneDepthTexture materials[GPENCIL_MATERIAL_BUFFER_LEN]
Definition: gpencil_info.hh:29
IconTextureDrawCall normal
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
static unsigned c
Definition: RandGen.cpp:83
Vector< Vector< int > > fixup_invalid_polygon(Span< float3 > vertex_coords, Span< int > face_vertex_indices)
static Material * get_or_create_material(Main *bmain, const std::string &name, Map< std::string, std::unique_ptr< MTLMaterial >> &materials, Map< std::string, Material * > &created_materials, bool relative_paths)
void transform_object(Object *object, const OBJImportParams &import_params)
vec_base< float, 4 > float4
unsigned short uint16_t
Definition: stdint.h:79
__int64 int64_t
Definition: stdint.h:89
unsigned int v1
unsigned int v2
unsigned int v
short mat_nr
float co[3]
Definition: BKE_main.h:121
struct bNodeTree * nodetree
struct MEdge * medge
CustomData vdata
struct MVert * mvert
uint16_t flag
struct MDeformVert * dvert
struct MLoop * mloop
int totpoly
struct MPoly * mpoly
CustomData ldata
void * data
Vector< PolyElem > face_elements_
Vector< std::string > material_order_
Map< int, int > global_to_local_vertices_
Vector< std::string > group_order_
Vector< PolyCorner > face_corners_
Vector< VertexColorsBlock > vertex_colors