diff options
Diffstat (limited to 'source/blender/alembic/intern/abc_exporter.cc')
-rw-r--r-- | source/blender/alembic/intern/abc_exporter.cc | 331 |
1 files changed, 191 insertions, 140 deletions
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index d259721e192..4fe65b96f36 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -47,7 +47,7 @@ extern "C" { #ifdef WIN32 /* needed for MSCV because of snprintf from BLI_string */ -# include "BLI_winstuff.h" +# include "BLI_winstuff.h" #endif #include "BKE_anim.h" @@ -66,13 +66,14 @@ using Alembic::Abc::OBox3dProperty; ExportSettings::ExportSettings() : scene(NULL) + , logger() , selected_only(false) , visible_layers_only(false) , renderable_only(false) , frame_start(1) , frame_end(1) - , frame_step_xform(1) - , frame_step_shape(1) + , frame_samples_xform(1) + , frame_samples_shape(1) , shutter_open(0.0) , shutter_close(1.0) , global_scale(1.0f) @@ -82,6 +83,8 @@ ExportSettings::ExportSettings() , export_vcols(false) , export_face_sets(false) , export_vweigths(false) + , export_hair(true) + , export_particles(true) , apply_subdiv(false) , use_subdiv_schema(false) , export_child_hairs(true) @@ -105,7 +108,7 @@ static bool object_is_smoke_sim(Object *ob) return false; } -static bool object_is_shape(Object *ob) +static bool object_type_is_exportable(Object *ob) { switch (ob->type) { case OB_MESH: @@ -114,6 +117,7 @@ static bool object_is_shape(Object *ob) } return true; + case OB_EMPTY: case OB_CURVE: case OB_SURF: case OB_CAMERA: @@ -123,14 +127,31 @@ static bool object_is_shape(Object *ob) } } -static bool export_object(const ExportSettings * const settings, Object *ob) + +/** + * Returns whether this object should be exported into the Alembic file. + * + * \param settings: export settings, used for options like 'selected only'. + * \param ob: the object in question. + * \param is_duplicated: Normally false; true when the object is instanced + * into the scene by a dupli-object (e.g. part of a dupligroup). + * This ignores selection and layer visibility, + * and assumes that the dupli-object itself (e.g. the group-instantiating empty) is exported. + */ +static bool export_object(const ExportSettings * const settings, Object *ob, + bool is_duplicated) { - if (settings->selected_only && !parent_selected(ob)) { - return false; - } + if (!is_duplicated) { + /* These two tests only make sense when the object isn't being instanced + * into the scene. When it is, its exportability is determined by + * its dupli-object and the DupliObject::no_draw property. */ + if (settings->selected_only && !parent_selected(ob)) { + return false; + } - if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) { - return false; + if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) { + return false; + } } if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { @@ -153,11 +174,13 @@ AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &set AbcExporter::~AbcExporter() { - std::map<std::string, AbcTransformWriter*>::iterator it, e; - for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) { - delete it->second; + /* Free xforms map */ + m_xforms_type::iterator it_x, e_x; + for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) { + delete it_x->second; } + /* Free shapes vector */ for (int i = 0, e = m_shapes.size(); i != e; ++i) { delete m_shapes[i]; } @@ -165,60 +188,56 @@ AbcExporter::~AbcExporter() delete m_writer; } -void AbcExporter::getShutterSamples(double step, bool time_relative, +void AbcExporter::getShutterSamples(unsigned int nr_of_samples, + bool time_relative, std::vector<double> &samples) { + Scene *scene = m_scene; /* for use in the FPS macro */ samples.clear(); - const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0; - const double shutter_open = m_settings.shutter_open; - const double shutter_close = m_settings.shutter_close; + unsigned int frame_offset = time_relative ? m_settings.frame_start : 0; + double time_factor = time_relative ? FPS : 1.0; + double shutter_open = m_settings.shutter_open; + double shutter_close = m_settings.shutter_close; + double time_inc = (shutter_close - shutter_open) / nr_of_samples; - /* sample all frame */ - if (shutter_open == 0.0 && shutter_close == 1.0) { - for (double t = 0; t < 1.0; t += step) { - samples.push_back((t + m_settings.frame_start) / time_factor); - } - } - else { - /* sample between shutter open & close */ - const int nsamples = std::max((1.0 / step) - 1.0, 1.0); - const double time_inc = (shutter_close - shutter_open) / nsamples; + /* sample between shutter open & close */ + for (int sample=0; sample < nr_of_samples; ++sample) { + double sample_time = shutter_open + time_inc * sample; + double time = (frame_offset + sample_time) / time_factor; - for (double t = shutter_open; t <= shutter_close; t += time_inc) { - samples.push_back((t + m_settings.frame_start) / time_factor); - } + samples.push_back(time); } } Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step) { - TimeSamplingPtr time_sampling; std::vector<double> samples; if (m_settings.frame_start == m_settings.frame_end) { - time_sampling.reset(new Alembic::Abc::TimeSampling()); - return time_sampling; + return TimeSamplingPtr(new Alembic::Abc::TimeSampling()); } getShutterSamples(step, true, samples); - Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec); - time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples)); + Alembic::Abc::TimeSamplingType ts( + static_cast<uint32_t>(samples.size()), + 1.0 / m_scene->r.frs_sec); - return time_sampling; + return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples)); } -void AbcExporter::getFrameSet(double step, std::set<double> &frames) +void AbcExporter::getFrameSet(unsigned int nr_of_samples, + std::set<double> &frames) { frames.clear(); std::vector<double> shutter_samples; - getShutterSamples(step, false, shutter_samples); + getShutterSamples(nr_of_samples, false, shutter_samples); - for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) { - for (int j = 0, e = shutter_samples.size(); j < e; ++j) { + for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) { + for (size_t j = 0; j < nr_of_samples; ++j) { frames.insert(frame + shutter_samples[j]); } } @@ -238,9 +257,9 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) } Scene *scene = m_scene; - const int fps = FPS; + const double fps = FPS; char buf[16]; - snprintf(buf, 15, "%d", fps); + snprintf(buf, 15, "%f", fps); const std::string str_fps = buf; Alembic::AbcCoreAbstract::MetaData md; @@ -250,44 +269,37 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) /* Create time samplings for transforms and shapes. */ - TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform); + TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform); m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time); TimeSamplingPtr shape_time; - if ((m_settings.frame_step_shape == m_settings.frame_step_xform) || + if ((m_settings.frame_samples_shape == m_settings.frame_samples_xform) || (m_settings.frame_start == m_settings.frame_end)) { shape_time = trans_time; m_shape_sampling_index = m_trans_sampling_index; } else { - shape_time = createTimeSampling(m_settings.frame_step_shape); + shape_time = createTimeSampling(m_settings.frame_samples_shape); m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time); } OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index); - if (m_settings.flatten_hierarchy) { - createTransformWritersFlat(); - } - else { - createTransformWritersHierarchy(bmain->eval_ctx); - } - + createTransformWritersHierarchy(bmain->eval_ctx); createShapeWriters(bmain->eval_ctx); /* Make a list of frames to export. */ std::set<double> xform_frames; - getFrameSet(m_settings.frame_step_xform, xform_frames); + getFrameSet(m_settings.frame_samples_xform, xform_frames); std::set<double> shape_frames; - getFrameSet(m_settings.frame_step_shape, shape_frames); + getFrameSet(m_settings.frame_samples_shape, shape_frames); /* Merge all frames needed. */ - std::set<double> frames(xform_frames); frames.insert(shape_frames.begin(), shape_frames.end()); @@ -310,7 +322,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) const double frame = *begin; /* 'frame' is offset by start frame, so need to cancel the offset. */ - setCurrentFrame(bmain, frame - m_settings.frame_start); + setCurrentFrame(bmain, frame); if (shape_frames.count(frame) != 0) { for (int i = 0, e = m_shapes.size(); i != e; ++i) { @@ -322,7 +334,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) continue; } - std::map<std::string, AbcTransformWriter *>::iterator xit, xe; + m_xforms_type::iterator xit, xe; for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { xit->second->write(); } @@ -346,34 +358,16 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx) while (base) { Object *ob = base->object; - if (export_object(&m_settings, ob)) { - switch(ob->type) { - case OB_LAMP: - case OB_LATTICE: - case OB_MBALL: - case OB_SPEAKER: - /* We do not export transforms for objects of these classes. */ - break; - - default: - exploreTransform(eval_ctx, ob, ob->parent, NULL); - } - } - - base = base->next; - } -} - -void AbcExporter::createTransformWritersFlat() -{ - Base *base = static_cast<Base *>(m_scene->base.first); + switch (ob->type) { + case OB_LAMP: + case OB_LATTICE: + case OB_MBALL: + case OB_SPEAKER: + /* We do not export transforms for objects of these classes. */ + break; - while (base) { - Object *ob = base->object; - - if (export_object(&m_settings, ob) && object_is_shape(ob)) { - std::string name = get_id_name(ob); - m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), 0, m_trans_sampling_index, m_settings); + default: + exploreTransform(eval_ctx, ob, ob->parent); } base = base->next; @@ -382,7 +376,15 @@ void AbcExporter::createTransformWritersFlat() void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent) { - createTransformWriter(ob, parent, dupliObParent); + /* If an object isn't exported itself, its duplilist shouldn't be + * exported either. */ + if (!export_object(&m_settings, ob, dupliObParent != NULL)) { + return; + } + + if (object_type_is_exportable(ob)) { + createTransformWriter(ob, parent, dupliObParent); + } ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); @@ -391,56 +393,91 @@ void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Obje Object *dupli_ob = NULL; Object *dupli_parent = NULL; - while (link) { + for (; link; link = link->next) { + /* This skips things like custom bone shapes. */ + if (m_settings.renderable_only && link->no_draw) { + continue; + } + if (link->type == OB_DUPLIGROUP) { dupli_ob = link->ob; dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob); } - - link = link->next; } } free_object_duplilist(lb); } -void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent) +AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent) { - const std::string name = get_object_dag_path_name(ob, dupliObParent); + /* An object should not be its own parent, or we'll get infinite loops. */ + BLI_assert(ob != parent); + BLI_assert(ob != dupliObParent); - /* check if we have already created a transform writer for this object */ - if (m_xforms.find(name) != m_xforms.end()){ - std::cerr << "xform " << name << " already exists\n"; - return; + std::string name; + if (m_settings.flatten_hierarchy) { + name = get_id_name(ob); + } + else { + name = get_object_dag_path_name(ob, dupliObParent); } - AbcTransformWriter *parent_xform = NULL; + /* check if we have already created a transform writer for this object */ + AbcTransformWriter *my_writer = getXForm(name); + if (my_writer != NULL) { + return my_writer; + } - if (parent) { - const std::string parentname = get_object_dag_path_name(parent, dupliObParent); - parent_xform = getXForm(parentname); + AbcTransformWriter *parent_writer = NULL; + Alembic::Abc::OObject alembic_parent; - if (!parent_xform) { - if (parent->parent) { - createTransformWriter(parent, parent->parent, dupliObParent); + if (m_settings.flatten_hierarchy || parent == NULL) { + /* Parentless objects still have the "top object" as parent + * in Alembic. */ + alembic_parent = m_writer->archive().getTop(); + } + else { + /* Since there are so many different ways to find parents (as evident + * in the number of conditions below), we can't really look up the + * parent by name. We'll just call createTransformWriter(), which will + * return the parent's AbcTransformWriter pointer. */ + if (parent->parent) { + if (parent == dupliObParent) { + parent_writer = createTransformWriter(parent, parent->parent, NULL); } else { - createTransformWriter(parent, dupliObParent, dupliObParent); + parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); } - - parent_xform = getXForm(parentname); } - } + else if (parent == dupliObParent) { + if (dupliObParent->parent == NULL) { + parent_writer = createTransformWriter(parent, NULL, NULL); + } + else { + parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent); + } + } + else { + parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent); + } - if (parent_xform) { - m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings); - m_xforms[name]->setParent(parent); + BLI_assert(parent_writer); + alembic_parent = parent_writer->alembicXform(); } - else { - m_xforms[name] = new AbcTransformWriter(ob, m_writer->archive().getTop(), NULL, m_trans_sampling_index, m_settings); + + my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer, + m_trans_sampling_index, m_settings); + + /* When flattening, the matrix of the dupliobject has to be added. */ + if (m_settings.flatten_hierarchy && dupliObParent) { + my_writer->m_proxy_from = dupliObParent; } + + m_xforms[name] = my_writer; + return my_writer; } void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx) @@ -457,32 +494,60 @@ void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx) void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent) { - ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); - + /* If an object isn't exported itself, its duplilist shouldn't be + * exported either. */ + if (!export_object(&m_settings, ob, dupliObParent != NULL)) { + return; + } + createShapeWriter(ob, dupliObParent); + ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); + if (lb) { - DupliObject *dupliob = static_cast<DupliObject *>(lb->first); + DupliObject *link = static_cast<DupliObject *>(lb->first); - while (dupliob) { - if (dupliob->type == OB_DUPLIGROUP) { - exploreObject(eval_ctx, dupliob->ob, ob); + for (; link; link = link->next) { + /* This skips things like custom bone shapes. */ + if (m_settings.renderable_only && link->no_draw) { + continue; } - dupliob = dupliob->next; + if (link->type == OB_DUPLIGROUP) { + exploreObject(eval_ctx, link->ob, ob); + } } } free_object_duplilist(lb); } -void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) +void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform) { - if (!object_is_shape(ob)) { + if (!m_settings.export_hair && !m_settings.export_particles) { return; } - if (!export_object(&m_settings, ob)) { + ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); + + for (; psys; psys = psys->next) { + if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { + continue; + } + + if (m_settings.export_hair && psys->part->type == PART_HAIR) { + m_settings.export_child_hairs = true; + m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); + } + else if (m_settings.export_particles && psys->part->type == PART_EMITTER) { + m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); + } + } +} + +void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) +{ + if (!object_type_is_exportable(ob)) { return; } @@ -498,32 +563,18 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) AbcTransformWriter *xform = getXForm(name); if (!xform) { - std::cerr << __func__ << ": xform " << name << " is NULL\n"; + ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n"; return; } - ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); - - for (; psys; psys = psys->next) { - if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { - continue; - } + createParticleSystemsWriters(ob, xform); - if (psys->part->type == PART_HAIR) { - m_settings.export_child_hairs = true; - m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); - } - else if (psys->part->type == PART_EMITTER) { - m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); - } - } - - switch(ob->type) { + switch (ob->type) { case OB_MESH: { Mesh *me = static_cast<Mesh *>(ob->data); - if (!me || me->totvert == 0) { + if (!me) { return; } @@ -578,7 +629,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name) void AbcExporter::setCurrentFrame(Main *bmain, double t) { - m_scene->r.cfra = std::floor(t); - m_scene->r.subframe = t - m_scene->r.cfra; + m_scene->r.cfra = static_cast<int>(t); + m_scene->r.subframe = static_cast<float>(t) - m_scene->r.cfra; BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay); } |