Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/alembic/intern/abc_exporter.cc')
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc331
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);
}