diff options
Diffstat (limited to 'source/blender/io/alembic/exporter/abc_writer_mesh.cc')
-rw-r--r-- | source/blender/io/alembic/exporter/abc_writer_mesh.cc | 578 |
1 files changed, 276 insertions, 302 deletions
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 512768bcd98..07196f2b81f 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -19,29 +19,37 @@ */ #include "abc_writer_mesh.h" -#include "abc_writer_transform.h" +#include "abc_hierarchy_iterator.h" #include "intern/abc_axis_conversion.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_fluidsim_types.h" +#include "BLI_assert.h" +#include "BLI_math_vector.h" -#include "BKE_anim_data.h" -#include "BKE_key.h" +#include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" #include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "bmesh.h" #include "bmesh_tools.h" -#include "DEG_depsgraph_query.h" +#include "DEG_depsgraph.h" + +#include "DNA_layer_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_fluidsim_types.h" +#include "DNA_particle_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; using Alembic::Abc::FloatArraySample; using Alembic::Abc::Int32ArraySample; +using Alembic::Abc::OObject; using Alembic::Abc::V2fArraySample; using Alembic::Abc::V3fArraySample; @@ -64,136 +72,77 @@ namespace alembic { /* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ -static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) -{ - points.clear(); - points.resize(mesh->totvert); - - MVert *verts = mesh->mvert; - - for (int i = 0, e = mesh->totvert; i < e; i++) { - copy_yup_from_zup(points[i].getValue(), verts[i].co); - } -} - +static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points); static void get_topology(struct Mesh *mesh, std::vector<int32_t> &poly_verts, std::vector<int32_t> &loop_counts, - bool &r_has_flat_shaded_poly) -{ - const int num_poly = mesh->totpoly; - const int num_loops = mesh->totloop; - MLoop *mloop = mesh->mloop; - MPoly *mpoly = mesh->mpoly; - r_has_flat_shaded_poly = false; - - poly_verts.clear(); - loop_counts.clear(); - poly_verts.reserve(num_loops); - loop_counts.reserve(num_poly); - - /* NOTE: data needs to be written in the reverse order. */ - for (int i = 0; i < num_poly; i++) { - MPoly &poly = mpoly[i]; - loop_counts.push_back(poly.totloop); - - r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0; - - MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); - - for (int j = 0; j < poly.totloop; j++, loop--) { - poly_verts.push_back(loop->v); - } - } -} - + bool &r_has_flat_shaded_poly); static void get_creases(struct Mesh *mesh, std::vector<int32_t> &indices, std::vector<int32_t> &lengths, - std::vector<float> &sharpnesses) -{ - const float factor = 1.0f / 255.0f; + std::vector<float> &sharpnesses); +static void get_loop_normals(struct Mesh *mesh, + std::vector<Imath::V3f> &normals, + bool has_flat_shaded_poly); - indices.clear(); - lengths.clear(); - sharpnesses.clear(); +ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args) + : ABCAbstractWriter(args), is_subd_(false) +{ +} - MEdge *edge = mesh->medge; +void ABCGenericMeshWriter::create_alembic_objects(const HierarchyContext *context) +{ + if (!args_.export_params->apply_subdiv && export_as_subdivision_surface(context->object)) { + is_subd_ = args_.export_params->use_subdiv_schema; + } - for (int i = 0, e = mesh->totedge; i < e; i++) { - const float sharpness = static_cast<float>(edge[i].crease) * factor; + if (is_subd_) { + CLOG_INFO(&LOG, 2, "exporting OSubD %s", args_.abc_path.c_str()); + abc_subdiv_ = OSubD(args_.abc_parent, args_.abc_name, timesample_index_); + abc_subdiv_schema_ = abc_subdiv_.getSchema(); + } + else { + CLOG_INFO(&LOG, 2, "exporting OPolyMesh %s", args_.abc_path.c_str()); + abc_poly_mesh_ = OPolyMesh(args_.abc_parent, args_.abc_name, timesample_index_); + abc_poly_mesh_schema_ = abc_poly_mesh_.getSchema(); - if (sharpness != 0.0f) { - indices.push_back(edge[i].v1); - indices.push_back(edge[i].v2); - sharpnesses.push_back(sharpness); - } + OCompoundProperty typeContainer = abc_poly_mesh_.getSchema().getUserProperties(); + OBoolProperty type(typeContainer, "meshtype"); + type.set(subsurf_modifier_ == nullptr); } - lengths.resize(sharpnesses.size(), 2); + Scene *scene_eval = DEG_get_evaluated_scene(args_.depsgraph); + liquid_sim_modifier_ = get_liquid_sim_modifier(scene_eval, context->object); } -static void get_loop_normals(struct Mesh *mesh, - std::vector<Imath::V3f> &normals, - bool has_flat_shaded_poly) +ABCGenericMeshWriter::~ABCGenericMeshWriter() { - normals.clear(); - - /* If all polygons are smooth shaded, and there are no custom normals, we don't need to export - * normals at all. This is also done by other software, see T71246. */ - if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL) && - (mesh->flag & ME_AUTOSMOOTH) == 0) { - return; - } - - BKE_mesh_calc_normals_split(mesh); - const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); - BLI_assert(lnors != NULL || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL"); - - normals.resize(mesh->totloop); +} - /* NOTE: data needs to be written in the reverse order. */ - int abc_index = 0; - MPoly *mp = mesh->mpoly; - for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) { - for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) { - int blender_index = mp->loopstart + j; - copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]); - } +const Alembic::Abc::OObject ABCGenericMeshWriter::get_alembic_object() const +{ + if (is_subd_) { + return abc_subdiv_; } + return abc_poly_mesh_; } -/* *************** Modifiers *************** */ - -/* check if the mesh is a subsurf, ignoring disabled modifiers and - * displace if it's after subsurf. */ -static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob) +bool ABCGenericMeshWriter::export_as_subdivision_surface(Object *ob_eval) const { - ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); + ModifierData *md = static_cast<ModifierData *>(ob_eval->modifiers.last); for (; md; md = md->prev) { - if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) { - continue; - } - - if (md->type == eModifierType_Subsurf) { - SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(md); - - if (smd->subdivType == ME_CC_SUBSURF) { - return md; - } - } - - /* mesh is not a subsurf. break */ - if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) { - return NULL; + /* This modifier has been temporarily disabled by SubdivModifierDisabler, + * so this indicates this is to be exported as subdivision surface. */ + if (md->type == eModifierType_Subsurf && (md->mode & eModifierMode_DisableTemporary)) { + return true; } } - return NULL; + return false; } -static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) +ModifierData *ABCGenericMeshWriter::get_liquid_sim_modifier(Scene *scene, Object *ob) { ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluidsim); @@ -205,122 +154,99 @@ static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) } } - return NULL; + return nullptr; } -/* ************************************************************************** */ - -AbcGenericMeshWriter::AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) +bool ABCGenericMeshWriter::is_supported(const HierarchyContext *context) const { - m_is_animated = isAnimated(); - m_subsurf_mod = NULL; - m_is_subd = false; - - /* If the object is static, use the default static time sampling. */ - if (!m_is_animated) { - time_sampling = 0; - } + Object *object = context->object; + bool is_dupli = context->duplicator != nullptr; + int base_flag; - if (!m_settings.apply_subdiv) { - m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object); - m_is_subd = (m_subsurf_mod != NULL); + if (is_dupli) { + /* Construct the object's base flags from its dupli-parent, just like is done in + * deg_objects_dupli_iterator_next(). Without this, the visibility check below will fail. Doing + * this here, instead of a more suitable location in AbstractHierarchyIterator, prevents + * copying the Object for every dupli. */ + base_flag = object->base_flag; + object->base_flag = context->duplicator->base_flag | BASE_FROM_DUPLI; } - m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL); + int visibility = BKE_object_visibility( + object, DAG_EVAL_RENDER /* TODO(Sybren): add evaluation mode to export options? */); - while (parent->alembicXform().getChildHeader(m_name)) { - m_name.append("_"); + if (is_dupli) { + object->base_flag = base_flag; } - if (m_settings.use_subdiv_schema && m_is_subd) { - OSubD subd(parent->alembicXform(), m_name, m_time_sampling); - m_subdiv_schema = subd.getSchema(); - } - else { - OPolyMesh mesh(parent->alembicXform(), m_name, m_time_sampling); - m_mesh_schema = mesh.getSchema(); - - OCompoundProperty typeContainer = m_mesh_schema.getUserProperties(); - OBoolProperty type(typeContainer, "meshtype"); - type.set(m_is_subd); - } + return (visibility & OB_VISIBLE_SELF) != 0; } -AbcGenericMeshWriter::~AbcGenericMeshWriter() +void ABCGenericMeshWriter::do_write(HierarchyContext &context) { - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } -} + Object *object = context.object; + bool needsfree = false; -bool AbcGenericMeshWriter::isAnimated() const -{ - if (BKE_animdata_id_is_animated(static_cast<ID *>(m_object->data))) { - return true; - } - if (BKE_key_from_object(m_object) != NULL) { - return true; - } + Mesh *mesh = get_export_mesh(object, needsfree); - /* Test modifiers. */ - ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first); - while (md) { + if (mesh == nullptr) { + return; + } - if (md->type != eModifierType_Subsurf) { - return true; - } + if (args_.export_params->triangulate) { + const bool tag_only = false; + const int quad_method = args_.export_params->quad_method; + const int ngon_method = args_.export_params->ngon_method; - md = md->next; - } + struct BMeshCreateParams bmcp = {false}; + struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); - return false; -} + BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr); -void AbcGenericMeshWriter::setIsAnimated(bool is_animated) -{ - m_is_animated = is_animated; -} + Mesh *triangulated_mesh = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); + BM_mesh_free(bm); -void AbcGenericMeshWriter::do_write() -{ - /* We have already stored a sample for this object. */ - if (!m_first_frame && !m_is_animated) { - return; + if (needsfree) { + free_export_mesh(mesh); + } + mesh = triangulated_mesh; + needsfree = true; } - bool needsfree; - struct Mesh *mesh = getFinalMesh(needsfree); + m_custom_data_config.pack_uvs = args_.export_params->packuv; + m_custom_data_config.mpoly = mesh->mpoly; + m_custom_data_config.mloop = mesh->mloop; + m_custom_data_config.totpoly = mesh->totpoly; + m_custom_data_config.totloop = mesh->totloop; + m_custom_data_config.totvert = mesh->totvert; try { - if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) { - writeSubD(mesh); + if (is_subd_) { + write_subd(context, mesh); } else { - writeMesh(mesh); + write_mesh(context, mesh); } if (needsfree) { - freeEvaluatedMesh(mesh); + free_export_mesh(mesh); } } catch (...) { if (needsfree) { - freeEvaluatedMesh(mesh); + free_export_mesh(mesh); } throw; } } -void AbcGenericMeshWriter::freeEvaluatedMesh(struct Mesh *mesh) +void ABCGenericMeshWriter::free_export_mesh(Mesh *mesh) { - BKE_id_free(NULL, mesh); + BKE_id_free(nullptr, mesh); } -void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) +void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh) { std::vector<Imath::V3f> points, normals; std::vector<int32_t> poly_verts, loop_counts; @@ -330,32 +256,33 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) get_vertices(mesh, points); get_topology(mesh, poly_verts, loop_counts, has_flat_shaded_poly); - if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(mesh, m_mesh_schema); + if (!frame_has_been_written_ && args_.export_params->face_sets) { + write_face_sets(context.object, mesh, abc_poly_mesh_schema_); } - m_mesh_sample = OPolyMeshSchema::Sample( + OPolyMeshSchema::Sample mesh_sample = OPolyMeshSchema::Sample( V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); - UVSample sample; - if (m_settings.export_uvs) { - const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); + UVSample uvs_and_indices; - if (!sample.indices.empty() && !sample.uvs.empty()) { + if (!frame_has_been_written_ && args_.export_params->uvs) { + const char *name = get_uv_sample(uvs_and_indices, m_custom_data_config, &mesh->ldata); + + if (!uvs_and_indices.indices.empty() && !uvs_and_indices.uvs.empty()) { OV2fGeomParam::Sample uv_sample; - uv_sample.setVals(V2fArraySample(sample.uvs)); - uv_sample.setIndices(UInt32ArraySample(sample.indices)); + uv_sample.setVals(V2fArraySample(uvs_and_indices.uvs)); + uv_sample.setIndices(UInt32ArraySample(uvs_and_indices.indices)); uv_sample.setScope(kFacevaryingScope); - m_mesh_schema.setUVSourceName(name); - m_mesh_sample.setUVs(uv_sample); + abc_poly_mesh_schema_.setUVSourceName(name); + mesh_sample.setUVs(uv_sample); } write_custom_data( - m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); } - if (m_settings.export_normals) { + if (args_.export_params->normals) { get_loop_normals(mesh, normals, has_flat_shaded_poly); ON3fGeomParam::Sample normals_sample; @@ -364,22 +291,23 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) normals_sample.setVals(V3fArraySample(normals)); } - m_mesh_sample.setNormals(normals_sample); + mesh_sample.setNormals(normals_sample); } - if (m_is_liquid) { - getVelocities(mesh, velocities); - m_mesh_sample.setVelocities(V3fArraySample(velocities)); + if (liquid_sim_modifier_ != nullptr) { + get_velocities(mesh, velocities); + mesh_sample.setVelocities(V3fArraySample(velocities)); } - m_mesh_sample.setSelfBounds(bounds()); + update_bounding_box(context.object); + mesh_sample.setSelfBounds(bounding_box_); - m_mesh_schema.set(m_mesh_sample); + abc_poly_mesh_schema_.set(mesh_sample); - writeArbGeoParams(mesh); + write_arb_geo_params(mesh); } -void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) +void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *mesh) { std::vector<float> crease_sharpness; std::vector<Imath::V3f> points; @@ -391,15 +319,15 @@ void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) get_topology(mesh, poly_verts, loop_counts, has_flat_poly); get_creases(mesh, crease_indices, crease_lengths, crease_sharpness); - if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(mesh, m_subdiv_schema); + if (!frame_has_been_written_ && args_.export_params->face_sets) { + write_face_sets(context.object, mesh, abc_subdiv_schema_); } - m_subdiv_sample = OSubDSchema::Sample( + OSubDSchema::Sample subdiv_sample = OSubDSchema::Sample( V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); UVSample sample; - if (m_first_frame && m_settings.export_uvs) { + if (!frame_has_been_written_ && args_.export_params->uvs) { const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); if (!sample.indices.empty() && !sample.uvs.empty()) { @@ -408,30 +336,32 @@ void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) uv_sample.setIndices(UInt32ArraySample(sample.indices)); uv_sample.setScope(kFacevaryingScope); - m_subdiv_schema.setUVSourceName(name); - m_subdiv_sample.setUVs(uv_sample); + abc_subdiv_schema_.setUVSourceName(name); + subdiv_sample.setUVs(uv_sample); } write_custom_data( - m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + abc_subdiv_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); } if (!crease_indices.empty()) { - m_subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); - m_subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); - m_subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); + subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); + subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); + subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); } - m_subdiv_sample.setSelfBounds(bounds()); - m_subdiv_schema.set(m_subdiv_sample); + update_bounding_box(context.object); + subdiv_sample.setSelfBounds(bounding_box_); + abc_subdiv_schema_.set(subdiv_sample); - writeArbGeoParams(mesh); + write_arb_geo_params(mesh); } -template<typename Schema> void AbcGenericMeshWriter::writeFaceSets(struct Mesh *me, Schema &schema) +template<typename Schema> +void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Schema &schema) { std::map<std::string, std::vector<int32_t>> geo_groups; - getGeoGroups(me, geo_groups); + get_geo_groups(object, mesh, geo_groups); std::map<std::string, std::vector<int32_t>>::iterator it; for (it = geo_groups.begin(); it != geo_groups.end(); ++it) { @@ -442,83 +372,35 @@ template<typename Schema> void AbcGenericMeshWriter::writeFaceSets(struct Mesh * } } -Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree) +void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me) { - /* We don't want subdivided mesh data */ - if (m_subsurf_mod) { - m_subsurf_mod->mode |= eModifierMode_DisableTemporary; - } - - r_needsfree = false; - - Scene *scene = DEG_get_evaluated_scene(m_settings.depsgraph); - Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); - struct Mesh *mesh = getEvaluatedMesh(scene, ob_eval, r_needsfree); - - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } - - if (m_settings.triangulate) { - const bool tag_only = false; - const int quad_method = m_settings.quad_method; - const int ngon_method = m_settings.ngon_method; - - struct BMeshCreateParams bmcp = {false}; - struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; - BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); - - BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL); - - Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); - BM_mesh_free(bm); - - if (r_needsfree) { - BKE_id_free(NULL, mesh); - } - - mesh = result; - r_needsfree = true; + if (liquid_sim_modifier_ != nullptr) { + /* We don't need anything more for liquid meshes. */ + return; } - m_custom_data_config.pack_uvs = m_settings.pack_uv; - m_custom_data_config.mpoly = mesh->mpoly; - m_custom_data_config.mloop = mesh->mloop; - m_custom_data_config.totpoly = mesh->totpoly; - m_custom_data_config.totloop = mesh->totloop; - m_custom_data_config.totvert = mesh->totvert; - - return mesh; -} - -void AbcGenericMeshWriter::writeArbGeoParams(struct Mesh *me) -{ - if (m_is_liquid) { - /* We don't need anything more for liquid meshes. */ + if (frame_has_been_written_ || !args_.export_params->vcolors) { return; } - if (m_first_frame && m_settings.export_vcols) { - if (m_subdiv_schema.valid()) { - write_custom_data( - m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); - } - else { - write_custom_data( - m_mesh_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); - } + OCompoundProperty arb_geom_params; + if (is_subd_) { + arb_geom_params = abc_subdiv_.getSchema().getArbGeomParams(); + } + else { + arb_geom_params = abc_poly_mesh_.getSchema().getArbGeomParams(); } + write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_MLOOPCOL); } -void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels) +void ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels) { const int totverts = mesh->totvert; vels.clear(); vels.resize(totverts); - ModifierData *md = get_liquid_sim_modifier(m_settings.scene, m_object); - FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md); + FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(liquid_sim_modifier_); FluidsimSettings *fss = fmd->fss; if (fss->meshVelocities) { @@ -534,8 +416,9 @@ void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V } } -void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, - std::map<std::string, std::vector<int32_t>> &geo_groups) +void ABCGenericMeshWriter::get_geo_groups(Object *object, + struct Mesh *mesh, + std::map<std::string, std::vector<int32_t>> &geo_groups) { const int num_poly = mesh->totpoly; MPoly *polygons = mesh->mpoly; @@ -544,13 +427,13 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, MPoly ¤t_poly = polygons[i]; short mnr = current_poly.mat_nr; - Material *mat = BKE_object_material_get(m_object, mnr + 1); + Material *mat = BKE_object_material_get(object, mnr + 1); if (!mat) { continue; } - std::string name = get_id_name(&mat->id); + std::string name = args_.hierarchy_iterator->get_id_name(&mat->id); if (geo_groups.find(name) == geo_groups.end()) { std::vector<int32_t> faceArray; @@ -561,9 +444,9 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, } if (geo_groups.size() == 0) { - Material *mat = BKE_object_material_get(m_object, 1); + Material *mat = BKE_object_material_get(object, 1); - std::string name = (mat) ? get_id_name(&mat->id) : "default"; + std::string name = (mat) ? args_.hierarchy_iterator->get_id_name(&mat->id) : "default"; std::vector<int32_t> faceArray; @@ -575,23 +458,114 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, } } -AbcMeshWriter::AbcMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings) +/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ + +static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) +{ + points.clear(); + points.resize(mesh->totvert); + + MVert *verts = mesh->mvert; + + for (int i = 0, e = mesh->totvert; i < e; i++) { + copy_yup_from_zup(points[i].getValue(), verts[i].co); + } +} + +static void get_topology(struct Mesh *mesh, + std::vector<int32_t> &poly_verts, + std::vector<int32_t> &loop_counts, + bool &r_has_flat_shaded_poly) +{ + const int num_poly = mesh->totpoly; + const int num_loops = mesh->totloop; + MLoop *mloop = mesh->mloop; + MPoly *mpoly = mesh->mpoly; + r_has_flat_shaded_poly = false; + + poly_verts.clear(); + loop_counts.clear(); + poly_verts.reserve(num_loops); + loop_counts.reserve(num_poly); + + /* NOTE: data needs to be written in the reverse order. */ + for (int i = 0; i < num_poly; i++) { + MPoly &poly = mpoly[i]; + loop_counts.push_back(poly.totloop); + + r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0; + + MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); + + for (int j = 0; j < poly.totloop; j++, loop--) { + poly_verts.push_back(loop->v); + } + } +} + +static void get_creases(struct Mesh *mesh, + std::vector<int32_t> &indices, + std::vector<int32_t> &lengths, + std::vector<float> &sharpnesses) +{ + const float factor = 1.0f / 255.0f; + + indices.clear(); + lengths.clear(); + sharpnesses.clear(); + + MEdge *edge = mesh->medge; + + for (int i = 0, e = mesh->totedge; i < e; i++) { + const float sharpness = static_cast<float>(edge[i].crease) * factor; + + if (sharpness != 0.0f) { + indices.push_back(edge[i].v1); + indices.push_back(edge[i].v2); + sharpnesses.push_back(sharpness); + } + } + + lengths.resize(sharpnesses.size(), 2); +} + +static void get_loop_normals(struct Mesh *mesh, + std::vector<Imath::V3f> &normals, + bool has_flat_shaded_poly) { + normals.clear(); + + /* If all polygons are smooth shaded, and there are no custom normals, we don't need to export + * normals at all. This is also done by other software, see T71246. */ + if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL) && + (mesh->flag & ME_AUTOSMOOTH) == 0) { + return; + } + + BKE_mesh_calc_normals_split(mesh); + const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); + BLI_assert(lnors != nullptr || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL"); + + normals.resize(mesh->totloop); + + /* NOTE: data needs to be written in the reverse order. */ + int abc_index = 0; + MPoly *mp = mesh->mpoly; + for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) { + for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) { + int blender_index = mp->loopstart + j; + copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]); + } + } } -AbcMeshWriter::~AbcMeshWriter() +ABCMeshWriter::ABCMeshWriter(const ABCWriterConstructorArgs &args) : ABCGenericMeshWriter(args) { } -Mesh *AbcMeshWriter::getEvaluatedMesh(Scene *scene_eval, - Object *ob_eval, - bool &UNUSED(r_needsfree)) +Mesh *ABCMeshWriter::get_export_mesh(Object *object_eval, bool & /*r_needsfree*/) { - return mesh_get_eval_final(m_settings.depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); + return BKE_object_get_evaluated_mesh(object_eval); } } // namespace alembic |