Changeset View
Changeset View
Standalone View
Standalone View
source/blender/alembic/intern/abc_mesh.cc
| Show All 40 Lines | |||||
| #include "BKE_library.h" | #include "BKE_library.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_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "MEM_guardedalloc.h" | |||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "ED_mesh.h" | #include "ED_mesh.h" | ||||
| #include "bmesh.h" | #include "bmesh.h" | ||||
| #include "bmesh_tools.h" | #include "bmesh_tools.h" | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) | ||||
| for (int i = 0, e = mesh->totvert; i < e; ++i) { | for (int i = 0, e = mesh->totvert; i < e; ++i) { | ||||
| copy_yup_from_zup(points[i].getValue(), verts[i].co); | copy_yup_from_zup(points[i].getValue(), verts[i].co); | ||||
| } | } | ||||
| } | } | ||||
| static void get_topology(struct Mesh *mesh, | static void get_topology(struct Mesh *mesh, | ||||
| std::vector<int32_t> &poly_verts, | std::vector<int32_t> &poly_verts, | ||||
| std::vector<int32_t> &loop_counts, | std::vector<int32_t> &loop_counts, | ||||
| bool &smooth_normal) | bool &r_smooth_normal) | ||||
| { | { | ||||
| const int num_poly = mesh->totpoly; | const int num_poly = mesh->totpoly; | ||||
| const int num_loops = mesh->totloop; | const int num_loops = mesh->totloop; | ||||
| MLoop *mloop = mesh->mloop; | MLoop *mloop = mesh->mloop; | ||||
| MPoly *mpoly = mesh->mpoly; | MPoly *mpoly = mesh->mpoly; | ||||
| poly_verts.clear(); | poly_verts.clear(); | ||||
| loop_counts.clear(); | loop_counts.clear(); | ||||
| poly_verts.reserve(num_loops); | poly_verts.reserve(num_loops); | ||||
| loop_counts.reserve(num_poly); | loop_counts.reserve(num_poly); | ||||
| /* NOTE: data needs to be written in the reverse order. */ | /* NOTE: data needs to be written in the reverse order. */ | ||||
| for (int i = 0; i < num_poly; ++i) { | for (int i = 0; i < num_poly; ++i) { | ||||
| MPoly &poly = mpoly[i]; | MPoly &poly = mpoly[i]; | ||||
| loop_counts.push_back(poly.totloop); | loop_counts.push_back(poly.totloop); | ||||
| smooth_normal |= ((poly.flag & ME_SMOOTH) != 0); | r_smooth_normal |= ((poly.flag & ME_SMOOTH) != 0); | ||||
| MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); | MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); | ||||
| for (int j = 0; j < poly.totloop; ++j, --loop) { | for (int j = 0; j < poly.totloop; ++j, --loop) { | ||||
| poly_verts.push_back(loop->v); | poly_verts.push_back(loop->v); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 603 Lines • ▼ Show 20 Lines | |||||
| struct AbcMeshData { | struct AbcMeshData { | ||||
| Int32ArraySamplePtr face_indices; | Int32ArraySamplePtr face_indices; | ||||
| Int32ArraySamplePtr face_counts; | Int32ArraySamplePtr face_counts; | ||||
| P3fArraySamplePtr positions; | P3fArraySamplePtr positions; | ||||
| P3fArraySamplePtr ceil_positions; | P3fArraySamplePtr ceil_positions; | ||||
| N3fArraySamplePtr vertex_normals; | N3fArraySamplePtr vertex_normals; | ||||
| N3fArraySamplePtr face_normals; | N3fArraySamplePtr loop_normals; | ||||
| bool poly_flag_smooth; | |||||
| V2fArraySamplePtr uvs; | V2fArraySamplePtr uvs; | ||||
| UInt32ArraySamplePtr uvs_indices; | UInt32ArraySamplePtr uvs_indices; | ||||
| }; | }; | ||||
| static void read_mverts_interp(MVert *mverts, | static void read_mverts_interp(MVert *mverts, | ||||
| const P3fArraySamplePtr &positions, | const P3fArraySamplePtr &positions, | ||||
| const P3fArraySamplePtr &ceil_positions, | const P3fArraySamplePtr &ceil_positions, | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data) | ||||
| MLoopUV *mloopuvs = config.mloopuv; | MLoopUV *mloopuvs = config.mloopuv; | ||||
| const Int32ArraySamplePtr &face_indices = mesh_data.face_indices; | const Int32ArraySamplePtr &face_indices = mesh_data.face_indices; | ||||
| const Int32ArraySamplePtr &face_counts = mesh_data.face_counts; | const Int32ArraySamplePtr &face_counts = mesh_data.face_counts; | ||||
| const V2fArraySamplePtr &uvs = mesh_data.uvs; | const V2fArraySamplePtr &uvs = mesh_data.uvs; | ||||
| const size_t uvs_size = uvs == nullptr ? 0 : uvs->size(); | const size_t uvs_size = uvs == nullptr ? 0 : uvs->size(); | ||||
| const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices; | const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices; | ||||
| const N3fArraySamplePtr &normals = mesh_data.face_normals; | |||||
| const bool do_uvs = (mloopuvs && uvs && uvs_indices) && | const bool do_uvs = (mloopuvs && uvs && uvs_indices) && | ||||
| (uvs_indices->size() == face_indices->size()); | (uvs_indices->size() == face_indices->size()); | ||||
| unsigned int loop_index = 0; | unsigned int loop_index = 0; | ||||
| unsigned int rev_loop_index = 0; | unsigned int rev_loop_index = 0; | ||||
| unsigned int uv_index = 0; | unsigned int uv_index = 0; | ||||
| for (int i = 0; i < face_counts->size(); ++i) { | for (int i = 0; i < face_counts->size(); ++i) { | ||||
| const int face_size = (*face_counts)[i]; | const int face_size = (*face_counts)[i]; | ||||
| MPoly &poly = mpolys[i]; | MPoly &poly = mpolys[i]; | ||||
| poly.loopstart = loop_index; | poly.loopstart = loop_index; | ||||
| poly.totloop = face_size; | poly.totloop = face_size; | ||||
| if (normals != NULL) { | if (mesh_data.poly_flag_smooth) { | ||||
| poly.flag |= ME_SMOOTH; | poly.flag |= ME_SMOOTH; | ||||
| } | } | ||||
| else { | |||||
| poly.flag &= ~ME_SMOOTH; | |||||
| } | |||||
| /* NOTE: Alembic data is stored in the reverse order. */ | /* NOTE: Alembic data is stored in the reverse order. */ | ||||
| rev_loop_index = loop_index + (face_size - 1); | rev_loop_index = loop_index + (face_size - 1); | ||||
| for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) { | for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) { | ||||
| MLoop &loop = mloops[rev_loop_index]; | MLoop &loop = mloops[rev_loop_index]; | ||||
| loop.v = (*face_indices)[loop_index]; | loop.v = (*face_indices)[loop_index]; | ||||
| if (do_uvs) { | if (do_uvs) { | ||||
| MLoopUV &loopuv = mloopuvs[rev_loop_index]; | MLoopUV &loopuv = mloopuvs[rev_loop_index]; | ||||
| uv_index = (*uvs_indices)[loop_index]; | uv_index = (*uvs_indices)[loop_index]; | ||||
| /* Some Alembic files are broken (or at least export UVs in a way we don't expect). */ | /* Some Alembic files are broken (or at least export UVs in a way we don't expect). */ | ||||
| if (uv_index >= uvs_size) { | if (uv_index >= uvs_size) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| loopuv.uv[0] = (*uvs)[uv_index][0]; | loopuv.uv[0] = (*uvs)[uv_index][0]; | ||||
| loopuv.uv[1] = (*uvs)[uv_index][1]; | loopuv.uv[1] = (*uvs)[uv_index][1]; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BKE_mesh_calc_edges(config.mesh, false, false); | |||||
| } | |||||
| static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data) | |||||
| { | |||||
| Mesh *mesh = config.mesh; | |||||
| if (!mesh_data.loop_normals) { | |||||
| BKE_mesh_calc_normals(config.mesh); | |||||
| config.mesh->flag &= ~ME_AUTOSMOOTH; | |||||
| return; | |||||
| } | |||||
| config.mesh->flag |= ME_AUTOSMOOTH; | |||||
| const Alembic::AbcGeom::N3fArraySample &loop_normals = *mesh_data.loop_normals; | |||||
| long int loop_count = loop_normals.size(); | |||||
| float(*lnors)[3] = static_cast<float(*)[3]>( | |||||
| MEM_malloc_arrayN(loop_count, sizeof(float[3]), "ABC::FaceNormals")); | |||||
| MPoly *mpoly = mesh->mpoly; | |||||
| int abc_index = 0; | |||||
| for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mpoly) { | |||||
| /* As usual, ABC orders the loops in reverse. */ | |||||
| for (int j = mpoly->totloop - 1; j >= 0; --j, ++abc_index) { | |||||
| int blender_index = mpoly->loopstart + j; | |||||
| copy_zup_from_yup(lnors[blender_index], loop_normals[abc_index].getValue()); | |||||
| } | |||||
| } | |||||
| BKE_mesh_set_custom_normals(config.mesh, lnors); | |||||
| MEM_freeN(lnors); | |||||
| } | } | ||||
| ABC_INLINE void read_uvs_params(CDStreamConfig &config, | ABC_INLINE void read_uvs_params(CDStreamConfig &config, | ||||
| AbcMeshData &abc_data, | AbcMeshData &abc_data, | ||||
| const IV2fGeomParam &uv, | const IV2fGeomParam &uv, | ||||
| const ISampleSelector &selector) | const ISampleSelector &selector) | ||||
| { | { | ||||
| if (!uv.valid()) { | if (!uv.valid()) { | ||||
| Show All 11 Lines | if (abc_data.uvs_indices->size() == config.totloop) { | ||||
| /* According to the convention, primary UVs should have had their name | /* According to the convention, primary UVs should have had their name | ||||
| * set using Alembic::Abc::SetSourceName, but you can't expect everyone | * set using Alembic::Abc::SetSourceName, but you can't expect everyone | ||||
| * to follow it! :) */ | * to follow it! :) */ | ||||
| if (name.empty()) { | if (name.empty()) { | ||||
| name = uv.getName(); | name = uv.getName(); | ||||
| } | } | ||||
| void *cd_ptr = config.add_customdata_cb(config.user_data, name.c_str(), CD_MLOOPUV); | void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV); | ||||
| config.mloopuv = static_cast<MLoopUV *>(cd_ptr); | config.mloopuv = static_cast<MLoopUV *>(cd_ptr); | ||||
| } | } | ||||
| } | } | ||||
| /* TODO(kevin): normals from Alembic files are not read in anymore, this is due | |||||
| * to the fact that there are many issues that are not so easy to solve, mainly | |||||
| * regarding the way normals are handled in Blender (MPoly.flag vs loop normals). | |||||
| */ | |||||
| ABC_INLINE void read_normals_params(AbcMeshData &abc_data, | ABC_INLINE void read_normals_params(AbcMeshData &abc_data, | ||||
| const IN3fGeomParam &normals, | const IN3fGeomParam &normals, | ||||
| const ISampleSelector &selector) | const ISampleSelector &selector) | ||||
| { | { | ||||
| if (!normals.valid()) { | if (!normals.valid()) { | ||||
| return; | return; | ||||
| } | } | ||||
| IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector); | IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector); | ||||
| if (normals.getScope() == kFacevaryingScope) { | Alembic::AbcGeom::GeometryScope scope = normals.getScope(); | ||||
| abc_data.face_normals = normsamp.getVals(); | switch (scope) { | ||||
| } | case Alembic::AbcGeom::kFacevaryingScope: | ||||
| else if ((normals.getScope() == kVertexScope) || (normals.getScope() == kVaryingScope)) { | abc_data.loop_normals = normsamp.getVals(); | ||||
| break; | |||||
| case Alembic::AbcGeom::kVertexScope: | |||||
| case Alembic::AbcGeom::kVaryingScope: | |||||
| /* Vertex normals from ABC aren't handled for now. */ | |||||
| abc_data.poly_flag_smooth = true; | |||||
| abc_data.vertex_normals = N3fArraySamplePtr(); | abc_data.vertex_normals = N3fArraySamplePtr(); | ||||
| break; | |||||
| case Alembic::AbcGeom::kConstantScope: | |||||
| case Alembic::AbcGeom::kUniformScope: | |||||
| case Alembic::AbcGeom::kUnknownScope: | |||||
| break; | |||||
| } | } | ||||
| } | } | ||||
| static bool check_smooth_poly_flag(Mesh *mesh) | static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) | ||||
| { | |||||
| MPoly *mpolys = mesh->mpoly; | |||||
| for (int i = 0, e = mesh->totpoly; i < e; ++i) { | |||||
| MPoly &poly = mpolys[i]; | |||||
| if ((poly.flag & ME_SMOOTH) != 0) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static void set_smooth_poly_flag(Mesh *mesh) | |||||
| { | |||||
| MPoly *mpolys = mesh->mpoly; | |||||
| for (int i = 0, e = mesh->totpoly; i < e; ++i) { | |||||
| MPoly &poly = mpolys[i]; | |||||
| poly.flag |= ME_SMOOTH; | |||||
| } | |||||
| } | |||||
| static void *add_customdata_cb(void *user_data, const char *name, int data_type) | |||||
| { | { | ||||
| Mesh *mesh = static_cast<Mesh *>(user_data); | |||||
| CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); | CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); | ||||
| void *cd_ptr; | void *cd_ptr; | ||||
| CustomData *loopdata; | CustomData *loopdata; | ||||
| int numloops; | int numloops; | ||||
| /* unsupported custom data type -- don't do anything. */ | /* unsupported custom data type -- don't do anything. */ | ||||
| if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { | if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { | ||||
| return NULL; | return NULL; | ||||
| Show All 23 Lines | static void get_weight_and_index(CDStreamConfig &config, | ||||
| config.index = i0; | config.index = i0; | ||||
| config.ceil_index = i1; | config.ceil_index = i1; | ||||
| } | } | ||||
| 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) | ||||
| bool &do_normals) | |||||
| { | { | ||||
| const IPolyMeshSchema::Sample sample = schema.getValue(selector); | const IPolyMeshSchema::Sample sample = schema.getValue(selector); | ||||
| AbcMeshData abc_mesh_data; | AbcMeshData abc_mesh_data; | ||||
| abc_mesh_data.face_counts = sample.getFaceCounts(); | abc_mesh_data.face_counts = sample.getFaceCounts(); | ||||
| abc_mesh_data.face_indices = sample.getFaceIndices(); | abc_mesh_data.face_indices = sample.getFaceIndices(); | ||||
| abc_mesh_data.positions = sample.getPositions(); | abc_mesh_data.positions = sample.getPositions(); | ||||
| abc_mesh_data.poly_flag_smooth = false; | |||||
| read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector); | read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector); | ||||
| do_normals = (abc_mesh_data.face_normals != NULL); | |||||
| get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); | get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); | ||||
| if (config.weight != 0.0f) { | if (config.weight != 0.0f) { | ||||
| Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; | Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; | ||||
| schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); | schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); | ||||
| abc_mesh_data.ceil_positions = ceil_sample.getPositions(); | abc_mesh_data.ceil_positions = ceil_sample.getPositions(); | ||||
| } | } | ||||
| if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { | if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { | ||||
| read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); | read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); | ||||
| } | } | ||||
| if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { | if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { | ||||
| read_mverts(config, abc_mesh_data); | read_mverts(config, abc_mesh_data); | ||||
| } | } | ||||
| 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, abc_mesh_data); | |||||
| } | } | ||||
| 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); | ||||
| } | } | ||||
| } | } | ||||
| CDStreamConfig get_config(Mesh *mesh) | CDStreamConfig get_config(Mesh *mesh) | ||||
| { | { | ||||
| CDStreamConfig config; | CDStreamConfig config; | ||||
| BLI_assert(mesh->mvert || mesh->totvert == 0); | BLI_assert(mesh->mvert || mesh->totvert == 0); | ||||
| config.user_data = mesh; | config.mesh = mesh; | ||||
| config.mvert = mesh->mvert; | config.mvert = mesh->mvert; | ||||
| config.mloop = mesh->mloop; | config.mloop = mesh->mloop; | ||||
| config.mpoly = mesh->mpoly; | config.mpoly = mesh->mpoly; | ||||
| config.totloop = mesh->totloop; | config.totloop = mesh->totloop; | ||||
| config.totpoly = mesh->totpoly; | config.totpoly = mesh->totpoly; | ||||
| config.loopdata = &mesh->ldata; | config.loopdata = &mesh->ldata; | ||||
| config.add_customdata_cb = add_customdata_cb; | config.add_customdata_cb = add_customdata_cb; | ||||
| Show All 23 Lines | 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, NULL); | Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); | ||||
| if (read_mesh != mesh) { | if (read_mesh != mesh) { | ||||
| BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); | BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); | ||||
| /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_nomain_to_mesh() */ | |||||
| mesh->flag |= (read_mesh->flag & ME_AUTOSMOOTH); | |||||
| } | } | ||||
| if (m_settings->validate_meshes) { | if (m_settings->validate_meshes) { | ||||
| BKE_mesh_validate(mesh, false, false); | BKE_mesh_validate(mesh, false, false); | ||||
| } | } | ||||
| readFaceSetsSample(bmain, mesh, 0, sample_sel); | readFaceSetsSample(bmain, mesh, sample_sel); | ||||
| if (has_animations(m_schema, m_settings)) { | if (has_animations(m_schema, m_settings)) { | ||||
| addCacheModifier(); | addCacheModifier(); | ||||
| } | } | ||||
| } | } | ||||
| bool AbcMeshReader::accepts_object_type( | bool AbcMeshReader::accepts_object_type( | ||||
| const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, | const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, | ||||
| bool topology_changed = positions->size() != existing_mesh->totvert || | bool topology_changed = 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; | ||||
| if (topology_changed) { | if (topology_changed) { | ||||
| 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; | ||||
| /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_new_nomain_from_template() */ | |||||
| new_mesh->flag |= (existing_mesh->flag & ME_AUTOSMOOTH); | |||||
| } | } | ||||
| else { | else { | ||||
| /* If the face count changed (e.g. by triangulation), only read points. | /* If the face count changed (e.g. by triangulation), only read points. | ||||
| * This prevents crash from T49813. | * This prevents crash from T49813. | ||||
| * TODO(kevin): perhaps find a better way to do this? */ | * TODO(kevin): perhaps find a better way to do this? */ | ||||
| if (face_counts->size() != existing_mesh->totpoly || | if (face_counts->size() != existing_mesh->totpoly || | ||||
| face_indices->size() != existing_mesh->totloop) { | face_indices->size() != existing_mesh->totloop) { | ||||
| settings.read_flag = MOD_MESHSEQ_READ_VERT; | settings.read_flag = MOD_MESHSEQ_READ_VERT; | ||||
| if (err_str) { | if (err_str) { | ||||
| *err_str = | *err_str = | ||||
| "Topology has changed, perhaps by triangulating the" | "Topology has changed, perhaps by triangulating the" | ||||
| " mesh. Only vertices will be read!"; | " mesh. Only vertices will be read!"; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); | CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); | ||||
| config.time = sample_sel.getRequestedTime(); | config.time = sample_sel.getRequestedTime(); | ||||
| bool do_normals = false; | read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); | ||||
| read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config, do_normals); | |||||
| if (new_mesh) { | if (new_mesh) { | ||||
| /* Check if we had ME_SMOOTH flag set to restore it. */ | |||||
| if (!do_normals && check_smooth_poly_flag(existing_mesh)) { | |||||
| set_smooth_poly_flag(new_mesh); | |||||
| } | |||||
| BKE_mesh_calc_normals(new_mesh); | |||||
| BKE_mesh_calc_edges(new_mesh, false, false); | |||||
| /* Here we assume that the number of materials doesn't change, i.e. that | /* Here we assume that the number of materials doesn't change, i.e. that | ||||
| * the material slots that were created when the object was loaded from | * the material slots that were created when the object was loaded from | ||||
| * Alembic are still valid now. */ | * Alembic are still valid now. */ | ||||
| size_t num_polys = new_mesh->totpoly; | size_t num_polys = new_mesh->totpoly; | ||||
| if (num_polys > 0) { | if (num_polys > 0) { | ||||
| std::map<std::string, int> mat_map; | std::map<std::string, int> mat_map; | ||||
| assign_facesets_to_mpoly(sample_sel, 0, new_mesh->mpoly, num_polys, mat_map); | assign_facesets_to_mpoly(sample_sel, new_mesh->mpoly, num_polys, mat_map); | ||||
| } | } | ||||
| return new_mesh; | return new_mesh; | ||||
| } | } | ||||
| if (do_normals) { | |||||
| BKE_mesh_calc_normals(existing_mesh); | |||||
| } | |||||
| return existing_mesh; | return existing_mesh; | ||||
| } | } | ||||
| void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, | void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, | ||||
| size_t poly_start, | |||||
| MPoly *mpoly, | MPoly *mpoly, | ||||
| int totpoly, | int totpoly, | ||||
| std::map<std::string, int> &r_mat_map) | std::map<std::string, int> &r_mat_map) | ||||
| { | { | ||||
| std::vector<std::string> face_sets; | std::vector<std::string> face_sets; | ||||
| m_schema.getFaceSetNames(face_sets); | m_schema.getFaceSetNames(face_sets); | ||||
| if (face_sets.empty()) { | if (face_sets.empty()) { | ||||
| Show All 19 Lines | for (int i = 0; i < face_sets.size(); ++i) { | ||||
| } | } | ||||
| const IFaceSetSchema face_schem = faceset.getSchema(); | const IFaceSetSchema face_schem = faceset.getSchema(); | ||||
| const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel); | const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel); | ||||
| const Int32ArraySamplePtr group_faces = face_sample.getFaces(); | const Int32ArraySamplePtr group_faces = face_sample.getFaces(); | ||||
| const size_t num_group_faces = group_faces->size(); | const size_t num_group_faces = group_faces->size(); | ||||
| for (size_t l = 0; l < num_group_faces; l++) { | for (size_t l = 0; l < num_group_faces; l++) { | ||||
| size_t pos = (*group_faces)[l] + poly_start; | size_t pos = (*group_faces)[l]; | ||||
| if (pos >= totpoly) { | if (pos >= totpoly) { | ||||
| std::cerr << "Faceset overflow on " << faceset.getName() << '\n'; | std::cerr << "Faceset overflow on " << faceset.getName() << '\n'; | ||||
| break; | break; | ||||
| } | } | ||||
| MPoly &poly = mpoly[pos]; | MPoly &poly = mpoly[pos]; | ||||
| poly.mat_nr = assigned_mat - 1; | poly.mat_nr = assigned_mat - 1; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void AbcMeshReader::readFaceSetsSample(Main *bmain, | void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSelector &sample_sel) | ||||
| Mesh *mesh, | |||||
| size_t poly_start, | |||||
| const ISampleSelector &sample_sel) | |||||
| { | { | ||||
| std::map<std::string, int> mat_map; | std::map<std::string, int> mat_map; | ||||
| assign_facesets_to_mpoly(sample_sel, poly_start, mesh->mpoly, mesh->totpoly, mat_map); | assign_facesets_to_mpoly(sample_sel, mesh->mpoly, mesh->totpoly, mat_map); | ||||
| utils::assign_materials(bmain, m_object, mat_map); | utils::assign_materials(bmain, m_object, mat_map); | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) | ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) | ||||
| { | { | ||||
| for (int i = 0, e = totedge; i < e; ++i) { | for (int i = 0, e = totedge; i < e; ++i) { | ||||
| Show All 14 Lines | static void read_subd_sample(const std::string &iobject_full_name, | ||||
| CDStreamConfig &config) | CDStreamConfig &config) | ||||
| { | { | ||||
| const ISubDSchema::Sample sample = schema.getValue(selector); | const ISubDSchema::Sample sample = schema.getValue(selector); | ||||
| AbcMeshData abc_mesh_data; | AbcMeshData abc_mesh_data; | ||||
| abc_mesh_data.face_counts = sample.getFaceCounts(); | abc_mesh_data.face_counts = sample.getFaceCounts(); | ||||
| abc_mesh_data.face_indices = sample.getFaceIndices(); | abc_mesh_data.face_indices = sample.getFaceIndices(); | ||||
| abc_mesh_data.vertex_normals = N3fArraySamplePtr(); | abc_mesh_data.vertex_normals = N3fArraySamplePtr(); | ||||
| abc_mesh_data.face_normals = N3fArraySamplePtr(); | abc_mesh_data.loop_normals = N3fArraySamplePtr(); | ||||
| abc_mesh_data.positions = sample.getPositions(); | abc_mesh_data.positions = sample.getPositions(); | ||||
| get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); | get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); | ||||
| if (config.weight != 0.0f) { | if (config.weight != 0.0f) { | ||||
| Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; | Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; | ||||
| schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); | schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); | ||||
| abc_mesh_data.ceil_positions = ceil_sample.getPositions(); | abc_mesh_data.ceil_positions = ceil_sample.getPositions(); | ||||
| } | } | ||||
| if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { | if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { | ||||
| read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); | read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); | ||||
| } | } | ||||
| if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { | if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { | ||||
| read_mverts(config, abc_mesh_data); | read_mverts(config, abc_mesh_data); | ||||
| } | } | ||||
| if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { | if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { | ||||
| abc_mesh_data.poly_flag_smooth = true; | |||||
sergey: This seems a bit weird to me. Can you elaborate a bit? | |||||
sybrenAuthorUnsubmitted Done Inline ActionsAlembic's 'SubD' scheme is used to store subdivision surfaces, i.e. the pre-subdivision mesh. Currently we don't even add a subdivison modifier when we load such data. This code is assuming (so it should have a comment stating this) that the subdivided surface should be smooth, and sets a flag that will eventually mark all polygons as such. Before this commit the mesh data was just loaded as-is and presented flat shaded. sybren: Alembic's 'SubD' scheme is used to store subdivision surfaces, i.e. the pre-subdivision mesh. | |||||
| read_mpolys(config, abc_mesh_data); | read_mpolys(config, abc_mesh_data); | ||||
| process_normals(config, abc_mesh_data); | |||||
| } | } | ||||
| 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); | ||||
| } | } | ||||
| } | } | ||||
| /* ************************************************************************** */ | /* ************************************************************************** */ | ||||
| ▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) { | ||||
| if (edge) { | if (edge) { | ||||
| edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]); | edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]); | ||||
| } | } | ||||
| } | } | ||||
| mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE; | mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE; | ||||
| } | } | ||||
| BKE_mesh_calc_normals(mesh); | |||||
| BKE_mesh_calc_edges(mesh, false, false); | |||||
| if (m_settings->validate_meshes) { | if (m_settings->validate_meshes) { | ||||
| BKE_mesh_validate(mesh, false, false); | BKE_mesh_validate(mesh, false, false); | ||||
| } | } | ||||
| if (has_animations(m_schema, m_settings)) { | if (has_animations(m_schema, m_settings)) { | ||||
| addCacheModifier(); | addCacheModifier(); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | else { | ||||
| } | } | ||||
| } | } | ||||
| /* 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. */ | ||||
| CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); | CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); | ||||
| config.time = sample_sel.getRequestedTime(); | config.time = sample_sel.getRequestedTime(); | ||||
| read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); | read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); | ||||
| if (new_mesh) { | return config.mesh; | ||||
| /* Check if we had ME_SMOOTH flag set to restore it. */ | |||||
| if (check_smooth_poly_flag(existing_mesh)) { | |||||
| set_smooth_poly_flag(new_mesh); | |||||
| } | |||||
| BKE_mesh_calc_normals(new_mesh); | |||||
| BKE_mesh_calc_edges(new_mesh, false, false); | |||||
| return new_mesh; | |||||
| } | |||||
| return existing_mesh; | |||||
| } | } | ||||
This seems a bit weird to me. Can you elaborate a bit?