diff options
Diffstat (limited to 'source/blender/io/alembic/intern/abc_reader_mesh.cc')
-rw-r--r-- | source/blender/io/alembic/intern/abc_reader_mesh.cc | 161 |
1 files changed, 107 insertions, 54 deletions
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 5a42be2bb02..14c3d756d56 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -33,6 +33,7 @@ #include "DNA_object_types.h" #include "BLI_compiler_compat.h" +#include "BLI_listbase.h" #include "BLI_math_geom.h" #include "BKE_main.h" @@ -43,7 +44,10 @@ using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::P3fArraySamplePtr; +using Alembic::Abc::PropertyHeader; +using Alembic::AbcGeom::IC3fGeomParam; +using Alembic::AbcGeom::IC4fGeomParam; using Alembic::AbcGeom::IFaceSet; using Alembic::AbcGeom::IFaceSetSchema; using Alembic::AbcGeom::IN3fGeomParam; @@ -67,55 +71,44 @@ namespace blender::io::alembic { /* Some helpers for mesh generation */ namespace utils { -static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map) +static std::map<std::string, Material *> build_material_map(const Main *bmain) { - Material *material = static_cast<Material *>(bmain->materials.first); - - for (; material; material = static_cast<Material *>(material->id.next)) { + std::map<std::string, Material *> mat_map; + LISTBASE_FOREACH (Material *, material, &bmain->materials) { mat_map[material->id.name + 2] = material; } + return mat_map; } static void assign_materials(Main *bmain, Object *ob, const std::map<std::string, int> &mat_index_map) { - bool can_assign = true; - std::map<std::string, int>::const_iterator it = mat_index_map.begin(); - - int matcount = 0; - for (; it != mat_index_map.end(); ++it, matcount++) { + std::map<std::string, int>::const_iterator it; + for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) { if (!BKE_object_material_slot_add(bmain, ob)) { - can_assign = false; - break; + return; } } - /* TODO(kevin): use global map? */ - std::map<std::string, Material *> mat_map; - build_mat_map(bmain, mat_map); - + std::map<std::string, Material *> matname_to_material = build_material_map(bmain); std::map<std::string, Material *>::iterator mat_iter; - if (can_assign) { - it = mat_index_map.begin(); + for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) { + const std::string mat_name = it->first; + const int mat_index = it->second; - for (; it != mat_index_map.end(); ++it) { - std::string mat_name = it->first; - mat_iter = mat_map.find(mat_name); - - Material *assigned_mat; - - if (mat_iter == mat_map.end()) { - assigned_mat = BKE_material_add(bmain, mat_name.c_str()); - mat_map[mat_name] = assigned_mat; - } - else { - assigned_mat = mat_iter->second; - } - - BKE_object_material_assign(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA); + Material *assigned_mat; + mat_iter = matname_to_material.find(mat_name); + if (mat_iter == matname_to_material.end()) { + assigned_mat = BKE_material_add(bmain, mat_name.c_str()); + matname_to_material[mat_name] = assigned_mat; + } + else { + assigned_mat = mat_iter->second; } + + BKE_object_material_assign(bmain, ob, assigned_mat, mat_index, BKE_MAT_ASSIGN_OBDATA); } } @@ -155,7 +148,8 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data) MVert *mverts = config.mvert; const P3fArraySamplePtr &positions = mesh_data.positions; - if (config.weight != 0.0f && mesh_data.ceil_positions != NULL && + if (config.use_vertex_interpolation && config.weight != 0.0f && + mesh_data.ceil_positions != nullptr && mesh_data.ceil_positions->size() == positions->size()) { read_mverts_interp(mverts, positions, mesh_data.ceil_positions, config.weight); return; @@ -258,7 +252,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data) static void process_no_normals(CDStreamConfig &config) { - /* Absense of normals in the Alembic mesh is interpreted as 'smooth'. */ + /* Absence of normals in the Alembic mesh is interpreted as 'smooth'. */ BKE_mesh_calc_normals(config.mesh); } @@ -271,10 +265,19 @@ static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr return; } + Mesh *mesh = config.mesh; + if (loop_count != mesh->totloop) { + /* This happens in certain Houdini exports. When a mesh is animated and then replaced by a + * fluid simulation, Houdini will still write the original mesh's loop normals, but the mesh + * verts/loops/polys are from the simulation. In such cases the normals cannot be mapped to the + * mesh, so it's better to ignore them. */ + process_no_normals(config); + return; + } + float(*lnors)[3] = static_cast<float(*)[3]>( MEM_malloc_arrayN(loop_count, sizeof(float[3]), "ABC::FaceNormals")); - Mesh *mesh = config.mesh; MPoly *mpoly = mesh->mpoly; const N3fArraySample &loop_normals = *loop_normals_ptr; int abc_index = 0; @@ -327,11 +330,11 @@ static void process_normals(CDStreamConfig &config, Alembic::AbcGeom::GeometryScope scope = normals.getScope(); switch (scope) { - case Alembic::AbcGeom::kFacevaryingScope: // 'Vertex Normals' in Houdini. + case Alembic::AbcGeom::kFacevaryingScope: /* 'Vertex Normals' in Houdini. */ process_loop_normals(config, normsamp.getVals()); break; case Alembic::AbcGeom::kVertexScope: - case Alembic::AbcGeom::kVaryingScope: // 'Point Normals' in Houdini. + case Alembic::AbcGeom::kVaryingScope: /* 'Point Normals' in Houdini. */ process_vertex_normals(config, normsamp.getVals()); break; case Alembic::AbcGeom::kConstantScope: @@ -381,19 +384,19 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) /* unsupported custom data type -- don't do anything. */ if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { - return NULL; + return nullptr; } loopdata = &mesh->ldata; cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name); - if (cd_ptr != NULL) { + if (cd_ptr != nullptr) { /* layer already exists, so just return it. */ return cd_ptr; } /* Create a new layer. */ numloops = mesh->totloop; - cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, NULL, numloops, name); + cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, nullptr, numloops, name); return cd_ptr; } @@ -448,7 +451,7 @@ static void read_mesh_sample(const std::string &iobject_full_name, } } -CDStreamConfig get_config(Mesh *mesh) +CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation) { CDStreamConfig config; @@ -462,6 +465,7 @@ CDStreamConfig get_config(Mesh *mesh) config.totpoly = mesh->totpoly; config.loopdata = &mesh->ldata; config.add_customdata_cb = add_customdata_cb; + config.use_vertex_interpolation = use_vertex_interpolation; return config; } @@ -484,6 +488,39 @@ bool AbcMeshReader::valid() const return m_schema.valid(); } +template<class typedGeomParam> +bool is_valid_animated(const ICompoundProperty arbGeomParams, const PropertyHeader &prop_header) +{ + if (!typedGeomParam::matches(prop_header)) { + return false; + } + + typedGeomParam geom_param(arbGeomParams, prop_header.getName()); + return geom_param.valid() && !geom_param.isConstant(); +} + +static bool has_animated_geom_params(const ICompoundProperty arbGeomParams) +{ + if (!arbGeomParams.valid()) { + return false; + } + + const int num_props = arbGeomParams.getNumProperties(); + for (int i = 0; i < num_props; i++) { + const PropertyHeader &prop_header = arbGeomParams.getPropertyHeader(i); + + /* These are interpreted as vertex colors later (see 'read_custom_data'). */ + if (is_valid_animated<IC3fGeomParam>(arbGeomParams, prop_header)) { + return true; + } + if (is_valid_animated<IC4fGeomParam>(arbGeomParams, prop_header)) { + return true; + } + } + + return false; +} + /* Specialisation of has_animations() as defined in abc_reader_object.h. */ template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings) { @@ -492,9 +529,21 @@ template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, Import } IV2fGeomParam uvsParam = schema.getUVsParam(); + if (uvsParam.valid() && !uvsParam.isConstant()) { + return true; + } + IN3fGeomParam normalsParam = schema.getNormalsParam(); - return (uvsParam.valid() && !uvsParam.isConstant()) || - (normalsParam.valid() && !normalsParam.isConstant()); + if (normalsParam.valid() && !normalsParam.isConstant()) { + return true; + } + + ICompoundProperty arbGeomParams = schema.getArbGeomParams(); + if (has_animated_geom_params(arbGeomParams)) { + return true; + } + + return false; } void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) @@ -504,7 +553,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; - Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr); if (read_mesh != mesh) { /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_nomain_to_mesh() */ /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */ @@ -556,7 +605,7 @@ bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector m_schema.getName().c_str(), sample_sel.getRequestedTime(), ex.what()); - // A similar error in read_mesh() would just return existing_mesh. + /* A similar error in read_mesh() would just return existing_mesh. */ return false; } @@ -609,7 +658,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, return existing_mesh; } - Mesh *new_mesh = NULL; + Mesh *new_mesh = nullptr; /* Only read point data when streaming meshes, unless we need to create new ones. */ ImportSettings settings; @@ -637,7 +686,9 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, } } - CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); + Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh; + const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES; + CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation); config.time = sample_sel.getRequestedTime(); config.modifier_error_message = err_str; @@ -677,7 +728,7 @@ void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, const std::string &grp_name = face_sets[i]; if (r_mat_map.find(grp_name) == r_mat_map.end()) { - r_mat_map[grp_name] = 1 + current_mat++; + r_mat_map[grp_name] = ++current_mat; } const int assigned_mat = r_mat_map[grp_name]; @@ -727,7 +778,7 @@ BLI_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) } } - return NULL; + return nullptr; } static void read_subd_sample(const std::string &iobject_full_name, @@ -817,7 +868,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; - Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr); if (read_mesh != mesh) { BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); } @@ -853,7 +904,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec } MEdge *edge = find_edge(edges, totedge, v1, v2); - if (edge == NULL) { + if (edge == nullptr) { edge = find_edge(edges, totedge, v2, v1); } @@ -899,7 +950,7 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - Mesh *new_mesh = NULL; + Mesh *new_mesh = nullptr; ImportSettings settings; settings.read_flag |= read_flag; @@ -927,11 +978,13 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, } /* Only read point data when streaming meshes, unless we need to create new ones. */ - CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); + Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh; + const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES; + CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation); config.time = sample_sel.getRequestedTime(); read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); - return config.mesh; + return mesh_to_export; } } // namespace blender::io::alembic |