Changeset View
Changeset View
Standalone View
Standalone View
source/blender/io/alembic/intern/abc_reader_mesh.cc
| Show All 21 Lines | |||||
| #include "abc_axis_conversion.h" | #include "abc_axis_conversion.h" | ||||
| #include "abc_reader_transform.h" | #include "abc_reader_transform.h" | ||||
| #include "abc_util.h" | #include "abc_util.h" | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "DNA_customdata_types.h" | |||||
| #include "DNA_material_types.h" | #include "DNA_material_types.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "BLI_compiler_compat.h" | #include "BLI_compiler_compat.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_math_geom.h" | #include "BLI_math_geom.h" | ||||
| #include "BKE_attribute.h" | |||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_material.h" | #include "BKE_material.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| using Alembic::Abc::Int32ArraySamplePtr; | using Alembic::Abc::Int32ArraySamplePtr; | ||||
| using Alembic::Abc::IV3fArrayProperty; | |||||
| using Alembic::Abc::P3fArraySamplePtr; | using Alembic::Abc::P3fArraySamplePtr; | ||||
| using Alembic::Abc::PropertyHeader; | using Alembic::Abc::PropertyHeader; | ||||
| using Alembic::Abc::V3fArraySamplePtr; | |||||
| using Alembic::AbcGeom::IC3fGeomParam; | using Alembic::AbcGeom::IC3fGeomParam; | ||||
| using Alembic::AbcGeom::IC4fGeomParam; | using Alembic::AbcGeom::IC4fGeomParam; | ||||
| using Alembic::AbcGeom::IFaceSet; | using Alembic::AbcGeom::IFaceSet; | ||||
| using Alembic::AbcGeom::IFaceSetSchema; | using Alembic::AbcGeom::IFaceSetSchema; | ||||
| using Alembic::AbcGeom::IN3fGeomParam; | using Alembic::AbcGeom::IN3fGeomParam; | ||||
| using Alembic::AbcGeom::IObject; | using Alembic::AbcGeom::IObject; | ||||
| using Alembic::AbcGeom::IPolyMesh; | using Alembic::AbcGeom::IPolyMesh; | ||||
| ▲ Show 20 Lines • Show All 359 Lines • ▼ Show 20 Lines | static void get_weight_and_index(CDStreamConfig &config, | ||||
| Alembic::AbcGeom::index_t i0, i1; | Alembic::AbcGeom::index_t i0, i1; | ||||
| config.weight = get_weight_and_index(config.time, time_sampling, samples_number, i0, i1); | config.weight = get_weight_and_index(config.time, time_sampling, samples_number, i0, i1); | ||||
| config.index = i0; | config.index = i0; | ||||
| config.ceil_index = i1; | config.ceil_index = i1; | ||||
| } | } | ||||
| template<typename GeomSchema> | |||||
kevindietrich: We could avoid some code bloat by taking an `ICompoundProperty` as input instead of an… | |||||
| static V3fArraySamplePtr get_velocity_prop(const GeomSchema &schema, | |||||
| const ISampleSelector &selector, | |||||
| const std::string &name) | |||||
| { | |||||
| const PropertyHeader *prop_header = schema.getPropertyHeader(name); | |||||
| if (prop_header) { | |||||
| const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0); | |||||
| return velocity_prop.getValue(selector); | |||||
| } | |||||
| const ICompoundProperty &prop = schema.getArbGeomParams(); | |||||
| if (!has_property(prop, name)) { | |||||
| return V3fArraySamplePtr(); | |||||
| } | |||||
| const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0); | |||||
| if (velocity_prop) { | |||||
| return velocity_prop.getValue(selector); | |||||
| } | |||||
| return V3fArraySamplePtr(); | |||||
| } | |||||
| static void read_velocity(const V3fArraySamplePtr &velocities, | |||||
| const CDStreamConfig &config, | |||||
| const float velocity_scale) | |||||
| { | |||||
| CustomDataLayer *velocity_layer = BKE_id_attribute_new( | |||||
| &config.mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, NULL); | |||||
| float(*velocity)[3] = (float(*)[3])velocity_layer->data; | |||||
| const int num_velocity_vectors = static_cast<int>(velocities->size()); | |||||
| BLI_assert(num_velocity_vectors == config.mesh->totvert); | |||||
| for (int i = 0; i < num_velocity_vectors; i++) { | |||||
| const Imath::V3f &vel_in = (*velocities)[i]; | |||||
| copy_zup_from_yup(velocity[i], vel_in.getValue()); | |||||
| mul_v3_fl(velocity[i], velocity_scale); | |||||
| } | |||||
| } | |||||
| static void read_mesh_sample(const std::string &iobject_full_name, | static void read_mesh_sample(const std::string &iobject_full_name, | ||||
| ImportSettings *settings, | ImportSettings *settings, | ||||
| const IPolyMeshSchema &schema, | const IPolyMeshSchema &schema, | ||||
| const ISampleSelector &selector, | const ISampleSelector &selector, | ||||
| CDStreamConfig &config) | CDStreamConfig &config) | ||||
| { | { | ||||
| const IPolyMeshSchema::Sample sample = schema.getValue(selector); | const IPolyMeshSchema::Sample sample = schema.getValue(selector); | ||||
| Show All 22 Lines | static void read_mesh_sample(const std::string &iobject_full_name, | ||||
| if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { | if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { | ||||
| read_mpolys(config, abc_mesh_data); | read_mpolys(config, abc_mesh_data); | ||||
| process_normals(config, schema.getNormalsParam(), selector); | process_normals(config, schema.getNormalsParam(), selector); | ||||
| } | } | ||||
| if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { | if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { | ||||
| read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector); | read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector); | ||||
| } | } | ||||
| if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) { | |||||
| V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name); | |||||
| if (velocities) { | |||||
| read_velocity(velocities, config, settings->velocity_scale); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation) | CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation) | ||||
| { | { | ||||
| CDStreamConfig config; | CDStreamConfig config; | ||||
| BLI_assert(mesh->mvert || mesh->totvert == 0); | BLI_assert(mesh->mvert || mesh->totvert == 0); | ||||
| ▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
| void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) | void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) | ||||
| { | { | ||||
| Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); | Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); | ||||
| m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); | m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); | ||||
| m_object->data = mesh; | m_object->data = mesh; | ||||
| Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr); | Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr); | ||||
| if (read_mesh != mesh) { | if (read_mesh != mesh) { | ||||
| /* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_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. */ | /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */ | ||||
| short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH); | short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH); | ||||
| BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true); | BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true); | ||||
| mesh->flag |= autosmooth; | mesh->flag |= autosmooth; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector &sample_sel) | ||||
| return positions->size() != existing_mesh->totvert || | return positions->size() != existing_mesh->totvert || | ||||
| face_counts->size() != existing_mesh->totpoly || | face_counts->size() != existing_mesh->totpoly || | ||||
| face_indices->size() != existing_mesh->totloop; | face_indices->size() != existing_mesh->totloop; | ||||
| } | } | ||||
| Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, | Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, | ||||
| const ISampleSelector &sample_sel, | const ISampleSelector &sample_sel, | ||||
| int read_flag, | const int read_flag, | ||||
| const char *velocity_name, | |||||
| const float velocity_scale, | |||||
| const char **err_str) | const char **err_str) | ||||
| { | { | ||||
| IPolyMeshSchema::Sample sample; | IPolyMeshSchema::Sample sample; | ||||
| try { | try { | ||||
| sample = m_schema.getValue(sample_sel); | sample = m_schema.getValue(sample_sel); | ||||
| } | } | ||||
| catch (Alembic::Util::Exception &ex) { | catch (Alembic::Util::Exception &ex) { | ||||
| if (err_str != nullptr) { | if (err_str != nullptr) { | ||||
| Show All 26 Lines | if (poly_count > 0 && loop_count < poly_count * 2) { | ||||
| return existing_mesh; | return existing_mesh; | ||||
| } | } | ||||
| Mesh *new_mesh = nullptr; | Mesh *new_mesh = nullptr; | ||||
| /* Only read point data when streaming meshes, unless we need to create new ones. */ | /* Only read point data when streaming meshes, unless we need to create new ones. */ | ||||
| ImportSettings settings; | ImportSettings settings; | ||||
| settings.read_flag |= read_flag; | settings.read_flag |= read_flag; | ||||
| settings.velocity_name = velocity_name; | |||||
| settings.velocity_scale = velocity_scale; | |||||
| if (topology_changed(existing_mesh, sample_sel)) { | if (topology_changed(existing_mesh, sample_sel)) { | ||||
| new_mesh = BKE_mesh_new_nomain_from_template( | new_mesh = BKE_mesh_new_nomain_from_template( | ||||
| existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size()); | existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size()); | ||||
| settings.read_flag |= MOD_MESHSEQ_READ_ALL; | settings.read_flag |= MOD_MESHSEQ_READ_ALL; | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { | ||||
| * assuming that the subdivided surface should be smooth. */ | * assuming that the subdivided surface should be smooth. */ | ||||
| read_mpolys(config, abc_mesh_data); | read_mpolys(config, abc_mesh_data); | ||||
| process_no_normals(config); | process_no_normals(config); | ||||
| } | } | ||||
| if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { | if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { | ||||
| read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector); | read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector); | ||||
| } | } | ||||
| if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) { | |||||
| V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name); | |||||
| if (velocities) { | |||||
| read_velocity(velocities, config, settings->velocity_scale); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings) | AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings) | ||||
| : AbcObjectReader(object, settings) | : AbcObjectReader(object, settings) | ||||
| { | { | ||||
| m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; | m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; | ||||
| Show All 31 Lines | |||||
| void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) | void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) | ||||
| { | { | ||||
| Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); | Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); | ||||
| m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); | m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); | ||||
| m_object->data = mesh; | m_object->data = mesh; | ||||
| Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr); | Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr); | ||||
| if (read_mesh != mesh) { | if (read_mesh != mesh) { | ||||
| BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true); | BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true); | ||||
| } | } | ||||
| ISubDSchema::Sample sample; | ISubDSchema::Sample sample; | ||||
| try { | try { | ||||
| sample = m_schema.getValue(sample_sel); | sample = m_schema.getValue(sample_sel); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) | ||||
| if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) { | if (m_settings->always_add_cache_reader || has_animations(m_schema, m_settings)) { | ||||
| addCacheModifier(); | addCacheModifier(); | ||||
| } | } | ||||
| } | } | ||||
| Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, | Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, | ||||
| const ISampleSelector &sample_sel, | const ISampleSelector &sample_sel, | ||||
| int read_flag, | const int read_flag, | ||||
| const char *velocity_name, | |||||
| const float velocity_scale, | |||||
| const char **err_str) | const char **err_str) | ||||
| { | { | ||||
| ISubDSchema::Sample sample; | ISubDSchema::Sample sample; | ||||
| try { | try { | ||||
| sample = m_schema.getValue(sample_sel); | sample = m_schema.getValue(sample_sel); | ||||
| } | } | ||||
| catch (Alembic::Util::Exception &ex) { | catch (Alembic::Util::Exception &ex) { | ||||
| if (err_str != nullptr) { | if (err_str != nullptr) { | ||||
| Show All 10 Lines | Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, | ||||
| const P3fArraySamplePtr &positions = sample.getPositions(); | const P3fArraySamplePtr &positions = sample.getPositions(); | ||||
| const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); | const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); | ||||
| const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); | const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); | ||||
| Mesh *new_mesh = nullptr; | Mesh *new_mesh = nullptr; | ||||
| ImportSettings settings; | ImportSettings settings; | ||||
| settings.read_flag |= read_flag; | settings.read_flag |= read_flag; | ||||
| settings.velocity_name = velocity_name; | |||||
| settings.velocity_scale = velocity_scale; | |||||
| if (existing_mesh->totvert != positions->size()) { | if (existing_mesh->totvert != positions->size()) { | ||||
| new_mesh = BKE_mesh_new_nomain_from_template( | new_mesh = BKE_mesh_new_nomain_from_template( | ||||
| existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size()); | existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size()); | ||||
| settings.read_flag |= MOD_MESHSEQ_READ_ALL; | settings.read_flag |= MOD_MESHSEQ_READ_ALL; | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 26 Lines | |||||
We could avoid some code bloat by taking an ICompoundProperty as input instead of an ISchema (which derives from ICompoundProperty anyway). I tested the following code, call sites don't need to be updated:
static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema, const ISampleSelector &selector, const std::string &name) { for (size_t i = 0; i < schema.getNumProperties(); i++) { const PropertyHeader &header = schema.getPropertyHeader(i); if (header.isCompound()) { const ICompoundProperty &prop = ICompoundProperty(schema, header.getName()); if (has_property(prop, name)) { const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0); if (velocity_prop) { return velocity_prop.getValue(selector); } } } else if (header.isArray()) { if (header.getName() == name) { const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0); return velocity_prop.getValue(selector); } } } return V3fArraySamplePtr(); }