Blender V4.5
obj_import_mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
12#include "DNA_material_types.h"
13#include "DNA_meshdata_types.h"
14
15#include "BKE_attribute.hh"
16#include "BKE_deform.hh"
17#include "BKE_lib_id.hh"
18#include "BKE_material.hh"
19#include "BKE_mesh.hh"
21#include "BKE_object.hh"
22#include "BKE_object_deform.h"
23
24#include "BLI_math_vector.h"
25#include "BLI_set.hh"
26
27#include "IO_wavefront_obj.hh"
29#include "obj_export_mtl.hh"
30#include "obj_import_mesh.hh"
31
32#include "CLG_log.h"
33static CLG_LogRef LOG = {"io.obj"};
34
35namespace blender::io::obj {
36
38{
39 const int64_t tot_verts_object{mesh_geometry_.get_vertex_count()};
40 if (tot_verts_object <= 0) {
41 /* Empty mesh */
42 return nullptr;
43 }
44
45 this->fixup_invalid_faces();
46
47 /* Includes explicitly imported edges, not the ones belonging the faces to be created. */
48 Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object,
49 mesh_geometry_.edges_.size(),
50 mesh_geometry_.face_elements_.size(),
51 mesh_geometry_.total_corner_);
52
53 this->create_vertices(mesh);
54 this->create_faces(mesh, import_params.import_vertex_groups && !import_params.use_split_groups);
55 this->create_edges(mesh);
56 this->create_uv_verts(mesh);
57 this->create_normals(mesh);
58 this->create_colors(mesh);
59
60 if (import_params.validate_meshes || mesh_geometry_.has_invalid_faces_) {
61 bool verbose_validate = false;
62#ifndef NDEBUG
63 verbose_validate = true;
64#endif
65 BKE_mesh_validate(mesh, verbose_validate, false);
66 }
67
68 return mesh;
69}
70
72 Main *bmain,
73 Map<std::string, std::unique_ptr<MTLMaterial>> &materials,
74 Map<std::string, Material *> &created_materials,
75 const OBJImportParams &import_params)
76{
77 Mesh *mesh = this->create_mesh(import_params);
78
79 if (mesh == nullptr) {
80 return nullptr;
81 }
82
83 std::string ob_name = get_geometry_name(mesh_geometry_.geometry_name_,
84 import_params.collection_separator);
85 if (ob_name.empty()) {
86 ob_name = "Untitled";
87 }
88
89 Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name.c_str());
90 obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str());
91
92 this->create_materials(bmain, materials, created_materials, obj, import_params.relative_paths);
93
94 BKE_mesh_nomain_to_mesh(mesh, static_cast<Mesh *>(obj->data), obj);
95
96 transform_object(obj, import_params);
97
98 /* NOTE: vertex groups have to be created after final mesh is assigned to the object. */
99 this->create_vertex_groups(obj);
100
101 return obj;
102}
103
104void MeshFromGeometry::fixup_invalid_faces()
105{
106 for (int64_t face_idx = 0; face_idx < mesh_geometry_.face_elements_.size(); ++face_idx) {
107 const FaceElem &curr_face = mesh_geometry_.face_elements_[face_idx];
108
109 if (curr_face.corner_count_ < 3) {
110 /* Skip and remove faces that have fewer than 3 corners. */
111 mesh_geometry_.total_corner_ -= curr_face.corner_count_;
112 mesh_geometry_.face_elements_.remove_and_reorder(face_idx);
113 --face_idx;
114 continue;
115 }
116
117 /* Check if face is invalid for Blender conventions:
118 * basically whether it has duplicate vertex indices. */
119 bool valid = true;
120 Set<int, 8> used_verts;
121 for (int i = 0; i < curr_face.corner_count_; ++i) {
122 int corner_idx = curr_face.start_index_ + i;
123 int vertex_idx = mesh_geometry_.face_corners_[corner_idx].vert_index;
124 if (used_verts.contains(vertex_idx)) {
125 valid = false;
126 break;
127 }
128 used_verts.add(vertex_idx);
129 }
130 if (valid) {
131 continue;
132 }
133
134 /* We have an invalid face, have to turn it into possibly
135 * multiple valid faces. */
136 Vector<int, 8> face_verts;
137 Vector<int, 8> face_uvs;
138 Vector<int, 8> face_normals;
139 face_verts.reserve(curr_face.corner_count_);
140 face_uvs.reserve(curr_face.corner_count_);
141 face_normals.reserve(curr_face.corner_count_);
142 for (int i = 0; i < curr_face.corner_count_; ++i) {
143 int corner_idx = curr_face.start_index_ + i;
144 const FaceCorner &corner = mesh_geometry_.face_corners_[corner_idx];
145 face_verts.append(corner.vert_index);
146 face_normals.append(corner.vertex_normal_index);
147 face_uvs.append(corner.uv_vert_index);
148 }
149 int face_vertex_group = curr_face.vertex_group_index;
150 int face_material = curr_face.material_index;
151 bool face_shaded_smooth = curr_face.shaded_smooth;
152
153 /* Remove the invalid face. */
154 mesh_geometry_.total_corner_ -= curr_face.corner_count_;
155 mesh_geometry_.face_elements_.remove_and_reorder(face_idx);
156 --face_idx;
157
158 Vector<Vector<int>> new_faces = fixup_invalid_face(global_vertices_.vertices, face_verts);
159
160 /* Create the newly formed faces. */
161 for (Span<int> face : new_faces) {
162 if (face.size() < 3) {
163 continue;
164 }
165 FaceElem new_face{};
166 new_face.vertex_group_index = face_vertex_group;
167 new_face.material_index = face_material;
168 new_face.shaded_smooth = face_shaded_smooth;
169 new_face.start_index_ = mesh_geometry_.face_corners_.size();
170 new_face.corner_count_ = face.size();
171 for (int idx : face) {
172 BLI_assert(idx >= 0 && idx < face_verts.size());
173 mesh_geometry_.face_corners_.append({face_verts[idx], face_uvs[idx], face_normals[idx]});
174 }
175 mesh_geometry_.face_elements_.append(new_face);
176 mesh_geometry_.total_corner_ += face.size();
177 }
178 }
179}
180
181void MeshFromGeometry::create_vertices(Mesh *mesh)
182{
183 MutableSpan<float3> positions = mesh->vert_positions_for_write();
184 /* Go through all the global vertex indices from min to max,
185 * checking which ones are actually and building a global->local
186 * index mapping. Write out the used vertex positions into the Mesh
187 * data. */
188 mesh_geometry_.global_to_local_vertices_.clear();
189 mesh_geometry_.global_to_local_vertices_.reserve(mesh_geometry_.vertices_.size());
190 for (int vi = mesh_geometry_.vertex_index_min_; vi <= mesh_geometry_.vertex_index_max_; ++vi) {
191 BLI_assert(vi >= 0 && vi < global_vertices_.vertices.size());
192 if (!mesh_geometry_.vertices_.contains(vi)) {
193 continue;
194 }
195 int local_vi = int(mesh_geometry_.global_to_local_vertices_.size());
196 BLI_assert(local_vi >= 0 && local_vi < mesh->verts_num);
197 copy_v3_v3(positions[local_vi], global_vertices_.vertices[vi]);
198 mesh_geometry_.global_to_local_vertices_.add_new(vi, local_vi);
199 }
200}
201
202void MeshFromGeometry::create_faces(Mesh *mesh, bool use_vertex_groups)
203{
204 MutableSpan<MDeformVert> dverts;
205 const int64_t total_verts = mesh_geometry_.get_vertex_count();
206 if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) {
207 dverts = mesh->deform_verts_for_write();
208 }
209
210 Span<float3> positions = mesh->vert_positions();
211 MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
212 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
213 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
214 bke::SpanAttributeWriter<int> material_indices =
215 attributes.lookup_or_add_for_write_only_span<int>("material_index", bke::AttrDomain::Face);
216
217 const bool set_face_sharpness = !has_normals();
218 bke::SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
219 "sharp_face", bke::AttrDomain::Face);
220
221 int corner_index = 0;
222
223 for (int face_idx = 0; face_idx < mesh->faces_num; ++face_idx) {
224 const FaceElem &curr_face = mesh_geometry_.face_elements_[face_idx];
225 if (curr_face.corner_count_ < 3) {
226 /* Don't add single vertex face, or edges. */
227 CLOG_WARN(&LOG, "Face with less than 3 vertices found, skipping.");
228 continue;
229 }
230
231 face_offsets[face_idx] = corner_index;
232 if (set_face_sharpness) {
233 /* If we have no vertex normals, set face sharpness flag based on
234 * whether smooth shading is off. */
235 sharp_faces.span[face_idx] = !curr_face.shaded_smooth;
236 }
237
238 material_indices.span[face_idx] = curr_face.material_index;
239 /* Importing obj files without any materials would result in negative indices, which is not
240 * supported. */
241 material_indices.span[face_idx] = std::max(material_indices.span[face_idx], 0);
242
243 for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
244 const FaceCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
245 corner_verts[corner_index] = mesh_geometry_.global_to_local_vertices_.lookup_default(
246 curr_corner.vert_index, 0);
247
248 /* Setup vertex group data, if needed. */
249 if (!dverts.is_empty()) {
250 const int group_index = curr_face.vertex_group_index;
251 /* NOTE: face might not belong to any group. */
252 if (group_index >= 0 || true) {
253 MDeformWeight *dw = BKE_defvert_ensure_index(&dverts[corner_verts[corner_index]],
254 group_index);
255 dw->weight = 1.0f;
256 }
257 }
258
259 corner_index++;
260 }
261
262 if (!set_face_sharpness) {
263 /* If we do have vertex normals, we do not want to set face sharpness.
264 * Exception is, if degenerate faces (zero area, with co-colocated
265 * vertices) are present in the input data; this confuses custom
266 * corner normals calculation in Blender. Set such faces as sharp,
267 * they will be not shared across smooth vertex face fans. */
268 const float area = bke::mesh::face_area_calc(
269 positions, corner_verts.slice(face_offsets[face_idx], curr_face.corner_count_));
270 if (area < 1.0e-12f) {
271 sharp_faces.span[face_idx] = true;
272 }
273 }
274 }
275
276 material_indices.finish();
277 sharp_faces.finish();
278}
279
280void MeshFromGeometry::create_vertex_groups(Object *obj)
281{
282 Mesh *mesh = static_cast<Mesh *>(obj->data);
283 if (mesh->deform_verts().is_empty()) {
284 return;
285 }
286 for (const std::string &name : mesh_geometry_.group_order_) {
287 BKE_object_defgroup_add_name(obj, name.data());
288 }
289}
290
291void MeshFromGeometry::create_edges(Mesh *mesh)
292{
293 MutableSpan<int2> edges = mesh->edges_for_write();
294
295 const int64_t tot_edges{mesh_geometry_.edges_.size()};
296 const int64_t total_verts{mesh_geometry_.get_vertex_count()};
297 UNUSED_VARS_NDEBUG(total_verts);
298 for (int i = 0; i < tot_edges; ++i) {
299 const int2 &src_edge = mesh_geometry_.edges_[i];
300 int2 &dst_edge = edges[i];
301 dst_edge[0] = mesh_geometry_.global_to_local_vertices_.lookup_default(src_edge[0], 0);
302 dst_edge[1] = mesh_geometry_.global_to_local_vertices_.lookup_default(src_edge[1], 0);
303 BLI_assert(dst_edge[0] < total_verts && dst_edge[1] < total_verts);
304 }
305
306 /* Set argument `update` to true so that existing, explicitly imported edges can be merged
307 * with the new ones created from faces. */
308 bke::mesh_calc_edges(*mesh, true, false);
309}
310
311void MeshFromGeometry::create_uv_verts(Mesh *mesh)
312{
313 if (global_vertices_.uv_vertices.size() <= 0) {
314 return;
315 }
316
317 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
318 bke::SpanAttributeWriter<float2> uv_map = attributes.lookup_or_add_for_write_only_span<float2>(
319 "UVMap", bke::AttrDomain::Corner);
320
321 int corner_index = 0;
322 bool added_uv = false;
323
324 for (const FaceElem &curr_face : mesh_geometry_.face_elements_) {
325 for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
326 const FaceCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
327 if (curr_corner.uv_vert_index >= 0 &&
328 curr_corner.uv_vert_index < global_vertices_.uv_vertices.size())
329 {
330 uv_map.span[corner_index] = global_vertices_.uv_vertices[curr_corner.uv_vert_index];
331 added_uv = true;
332 }
333 else {
334 uv_map.span[corner_index] = {0.0f, 0.0f};
335 }
336 corner_index++;
337 }
338 }
339
340 uv_map.finish();
341
342 /* If we have an object without UVs which resides in the same `.obj` file
343 * as an object which *does* have UVs we can end up adding a UV layer
344 * filled with zeroes.
345 * We could maybe check before creating this layer but that would need
346 * iterating over the whole mesh to check for UVs and as this is probably
347 * the exception rather than the rule, just delete it afterwards.
348 */
349 if (!added_uv) {
350 attributes.remove("UVMap");
351 }
352}
353
355 const std::string &name,
356 Map<std::string, std::unique_ptr<MTLMaterial>> &materials,
357 Map<std::string, Material *> &created_materials,
358 bool relative_paths)
359{
360 /* Have we created this material already? */
361 Material **found_mat = created_materials.lookup_ptr(name);
362 if (found_mat != nullptr) {
363 return *found_mat;
364 }
365
366 /* We have not, will have to create it. Create a new default
367 * MTLMaterial too, in case the OBJ file tries to use a material
368 * that was not in the MTL file. */
369 const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>());
370
371 Material *mat = BKE_material_add(bmain, name.c_str());
372 id_us_min(&mat->id);
373
374 mat->use_nodes = true;
375 mat->nodetree = create_mtl_node_tree(bmain, mtl, mat, relative_paths);
377
378 created_materials.add_new(name, mat);
379 return mat;
380}
381
382void MeshFromGeometry::create_materials(Main *bmain,
383 Map<std::string, std::unique_ptr<MTLMaterial>> &materials,
384 Map<std::string, Material *> &created_materials,
385 Object *obj,
386 bool relative_paths)
387{
388 for (const std::string &name : mesh_geometry_.material_order_) {
390 bmain, name, materials, created_materials, relative_paths);
391 if (mat == nullptr) {
392 continue;
393 }
394 BKE_object_material_assign_single_obdata(bmain, obj, mat, obj->totcol + 1);
395 }
396 if (obj->totcol > 0) {
397 obj->actcol = 1;
398 }
399}
400
401bool MeshFromGeometry::has_normals() const
402{
403 return !global_vertices_.vert_normals.is_empty() && mesh_geometry_.total_corner_ != 0;
404}
405
406void MeshFromGeometry::create_normals(Mesh *mesh)
407{
408 if (!has_normals()) {
409 return;
410 }
411
412 Array<float3> corner_normals(mesh_geometry_.total_corner_);
413 int corner_index = 0;
414 for (const FaceElem &curr_face : mesh_geometry_.face_elements_) {
415 for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
416 const FaceCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
417 int n_index = curr_corner.vertex_normal_index;
418 float3 normal(0, 0, 0);
419 if (n_index >= 0 && n_index < global_vertices_.vert_normals.size()) {
420 normal = global_vertices_.vert_normals[n_index];
421 }
422 corner_normals[corner_index] = normal;
423 corner_index++;
424 }
425 }
426 bke::mesh_set_custom_normals(*mesh, corner_normals);
427}
428
429void MeshFromGeometry::create_colors(Mesh *mesh)
430{
431 /* Nothing to do if we don't have vertex colors at all. */
432 if (global_vertices_.vertex_colors.is_empty()) {
433 return;
434 }
435
436 /* First pass to determine if we need to create a color attribute. */
437 for (int vi : mesh_geometry_.vertices_) {
438 if (!global_vertices_.has_vertex_color(vi)) {
439 return;
440 }
441 }
442
443 AttributeOwner owner = AttributeOwner::from_id(&mesh->id);
444 CustomDataLayer *color_layer = BKE_attribute_new(
445 owner, "Color", CD_PROP_COLOR, bke::AttrDomain::Point, nullptr);
446 BKE_id_attributes_active_color_set(&mesh->id, color_layer->name);
447 BKE_id_attributes_default_color_set(&mesh->id, color_layer->name);
448 float4 *colors = (float4 *)color_layer->data;
449
450 /* Second pass to fill out the data. */
451 for (auto item : mesh_geometry_.global_to_local_vertices_.items()) {
452 const int vi = item.key;
453 const int local_vi = item.value;
454 BLI_assert(vi >= 0 && vi < global_vertices_.vertex_colors.size());
455 BLI_assert(local_vi >= 0 && local_vi < mesh->verts_num);
456 const float3 &c = global_vertices_.vertex_colors[vi];
457 colors[local_vi] = float4(c.x, c.y, c.z, 1.0);
458 }
459}
460
461} // namespace blender::io::obj
void BKE_id_attributes_default_color_set(struct ID *id, std::optional< blender::StringRef > name)
struct CustomDataLayer * BKE_attribute_new(AttributeOwner &owner, blender::StringRef name, eCustomDataType type, blender::bke::AttrDomain domain, struct ReportList *reports)
Definition attribute.cc:391
void BKE_id_attributes_active_color_set(struct ID *id, std::optional< blender::StringRef > name)
Definition attribute.cc:986
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
void id_us_min(ID *id)
Definition lib_id.cc:361
General operations, lookup, etc. for materials.
void BKE_object_material_assign_single_obdata(Main *bmain, Object *ob, Material *ma, short act)
Material * BKE_material_add(Main *bmain, const char *name)
bool BKE_mesh_validate(Mesh *mesh, bool do_verbose, bool cddata_check_mask)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const NodeTreeUpdateExtraParams &params={})
General operations, lookup, etc. for blender objects.
void * BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) ATTR_NONNULL(1)
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
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)
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS_NDEBUG(...)
float[3] Vector
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
struct CustomDataLayer CustomDataLayer
@ CD_PROP_COLOR
struct Mesh Mesh
struct MDeformWeight MDeformWeight
@ OB_MESH
struct Object Object
long long int int64_t
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr bool is_empty() const
Definition BLI_span.hh:509
int64_t size() const
void append(const T &value)
void reserve(const int64_t min_capacity)
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
Mesh * create_mesh(const OBJImportParams &import_params)
Object * create_mesh_object(Main *bmain, Map< std::string, std::unique_ptr< MTLMaterial > > &materials, Map< std::string, Material * > &created_materials, const OBJImportParams &import_params)
#define LOG(severity)
Definition log.h:32
float face_area_calc(Span< float3 > vert_positions, Span< int > face_verts)
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges)
void mesh_set_custom_normals(Mesh &mesh, MutableSpan< float3 > corner_normals)
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)
bNodeTree * create_mtl_node_tree(Main *bmain, const MTLMaterial &mtl_mat, Material *mat, bool relative_paths)
void transform_object(Object *object, const OBJImportParams &import_params)
Vector< Vector< int > > fixup_invalid_face(Span< float3 > vert_positions, Span< int > face_verts)
std::string get_geometry_name(const std::string &full_name, char separator)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
struct bNodeTree * nodetree
void clear(bool preserve_shaders=false) override
int faces_num
Vector< std::string > material_order_
Vector< FaceCorner > face_corners_
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
i
Definition text_draw.cc:230