[Bf-blender-cvs] [2917df21adc] master: Alembic: new exporter based on the USD exporter structure

Sybren A. Stüvel noreply at git.blender.org
Tue Jun 30 11:38:50 CEST 2020


Commit: 2917df21adc8a1ce0423349909db61d22a38d451
Author: Sybren A. Stüvel
Date:   Fri Jun 19 16:36:10 2020 +0200
Branches: master
https://developer.blender.org/rB2917df21adc8a1ce0423349909db61d22a38d451

Alembic: new exporter based on the USD exporter structure

The Alembic exporter has been restructured by leverages the
`AbstractHierarchyIterator` introduced by the USD exporter. The produced
Alembic files have not changed much (details below), as the Alembic
writing code has simply been moved from the old exporter to the new. How
the export hierarchy is handled changed a lot, though, and also the way
in which transforms are computed. As a result, T71395 is fixed.

Differences between the old and new exporter, in terms of the produced
Alembic file:
- Duplicated objects now have a unique numerical suffix.
- Matrices are computed differently, namely by simply computing the
  evaluated transform of the object relative to the evaluated transform
  of its export-parent. This fixes {T71395}, but otherwise should
  produce the same result as before (but with simpler code).

Compared to the old Alembic exporter, Subdivision modifiers are now
disabled in a cleaner, more efficient way (they are disabled when
exporting with the "Apply Subdivisions" option is unchecked). Previously
the exporter would move to a new frame, disable the modifier, evaluate
the object, and enable the modifier again. This is now done before
exporting starts, and modifiers are only restored when exporting ends.

Some issues with the old Alembic exporter that have NOT been fixed in
this patch:
- Exporting NURBS patches and curves (see T49114 for example).
- Exporting flattened hierarchy in combination with dupli-objects. This
  seems to be broken in the old Alembic exporter as well, but nobody
  reported this yet.

Differential Revision: https://developer.blender.org/D7664

Reviewed By: Sergey

===================================================================

M	source/blender/io/alembic/CMakeLists.txt
A	source/blender/io/alembic/exporter/abc_archive.cc
A	source/blender/io/alembic/exporter/abc_archive.h
M	source/blender/io/alembic/exporter/abc_export_capi.cc
D	source/blender/io/alembic/exporter/abc_exporter.cc
D	source/blender/io/alembic/exporter/abc_exporter.h
A	source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc
A	source/blender/io/alembic/exporter/abc_hierarchy_iterator.h
A	source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
R055	source/blender/io/alembic/exporter/abc_writer_archive.h	source/blender/io/alembic/exporter/abc_subdiv_disabler.h
A	source/blender/io/alembic/exporter/abc_writer_abstract.cc
A	source/blender/io/alembic/exporter/abc_writer_abstract.h
D	source/blender/io/alembic/exporter/abc_writer_archive.cc
M	source/blender/io/alembic/exporter/abc_writer_camera.cc
M	source/blender/io/alembic/exporter/abc_writer_camera.h
M	source/blender/io/alembic/exporter/abc_writer_curves.cc
M	source/blender/io/alembic/exporter/abc_writer_curves.h
M	source/blender/io/alembic/exporter/abc_writer_hair.cc
M	source/blender/io/alembic/exporter/abc_writer_hair.h
M	source/blender/io/alembic/exporter/abc_writer_mball.cc
M	source/blender/io/alembic/exporter/abc_writer_mball.h
M	source/blender/io/alembic/exporter/abc_writer_mesh.cc
M	source/blender/io/alembic/exporter/abc_writer_mesh.h
M	source/blender/io/alembic/exporter/abc_writer_nurbs.cc
M	source/blender/io/alembic/exporter/abc_writer_nurbs.h
D	source/blender/io/alembic/exporter/abc_writer_object.cc
D	source/blender/io/alembic/exporter/abc_writer_object.h
M	source/blender/io/alembic/exporter/abc_writer_points.cc
M	source/blender/io/alembic/exporter/abc_writer_points.h
M	source/blender/io/alembic/exporter/abc_writer_transform.cc
M	source/blender/io/alembic/exporter/abc_writer_transform.h
M	source/blender/io/alembic/intern/alembic_capi.cc
M	source/blender/io/common/IO_abstract_hierarchy_iterator.h
M	tests/gtests/alembic/CMakeLists.txt
M	tests/gtests/alembic/abc_export_test.cc
M	tests/gtests/alembic/abc_matrix_test.cc
M	tests/python/alembic_tests.py

===================================================================

diff --git a/source/blender/io/alembic/CMakeLists.txt b/source/blender/io/alembic/CMakeLists.txt
index c0c91099ad2..da36272b850 100644
--- a/source/blender/io/alembic/CMakeLists.txt
+++ b/source/blender/io/alembic/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
   ../../makesdna
   ../../makesrna
   ../../windowmanager
+  ../../../../intern/clog
   ../../../../intern/guardedalloc
   ../../../../intern/utfconv
 )
@@ -54,16 +55,17 @@ set(SRC
   intern/abc_util.cc
   intern/alembic_capi.cc
 
+  exporter/abc_archive.cc
   exporter/abc_export_capi.cc
-  exporter/abc_exporter.cc
-  exporter/abc_writer_archive.cc
+  exporter/abc_hierarchy_iterator.cc
+  exporter/abc_subdiv_disabler.cc
+  exporter/abc_writer_abstract.cc
   exporter/abc_writer_camera.cc
   exporter/abc_writer_curves.cc
   exporter/abc_writer_hair.cc
-  exporter/abc_writer_mball.cc
   exporter/abc_writer_mesh.cc
+  exporter/abc_writer_mball.cc
   exporter/abc_writer_nurbs.cc
-  exporter/abc_writer_object.cc
   exporter/abc_writer_points.cc
   exporter/abc_writer_transform.cc
 
@@ -80,15 +82,16 @@ set(SRC
   intern/abc_reader_transform.h
   intern/abc_util.h
 
-  exporter/abc_exporter.h
-  exporter/abc_writer_archive.h
+  exporter/abc_archive.h
+  exporter/abc_hierarchy_iterator.h
+  exporter/abc_subdiv_disabler.h
+  exporter/abc_writer_abstract.h
   exporter/abc_writer_camera.h
   exporter/abc_writer_curves.h
   exporter/abc_writer_hair.h
-  exporter/abc_writer_mball.h
   exporter/abc_writer_mesh.h
+  exporter/abc_writer_mball.h
   exporter/abc_writer_nurbs.h
-  exporter/abc_writer_object.h
   exporter/abc_writer_points.h
   exporter/abc_writer_transform.h
 )
diff --git a/source/blender/io/alembic/exporter/abc_archive.cc b/source/blender/io/alembic/exporter/abc_archive.cc
new file mode 100644
index 00000000000..dbf046e6dfe
--- /dev/null
+++ b/source/blender/io/alembic/exporter/abc_archive.cc
@@ -0,0 +1,255 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "abc_archive.h"
+
+#include "BKE_blender_version.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_scene_types.h"
+
+#include <Alembic/AbcCoreOgawa/All.h>
+#include <Alembic/AbcGeom/All.h>
+
+namespace blender {
+namespace io {
+namespace alembic {
+
+using Alembic::Abc::ErrorHandler;
+using Alembic::Abc::kWrapExisting;
+using Alembic::Abc::MetaData;
+using Alembic::Abc::OArchive;
+using Alembic::Abc::TimeSampling;
+using Alembic::Abc::TimeSamplingPtr;
+using Alembic::Abc::TimeSamplingType;
+
+static MetaData create_abc_metadata(const Main *bmain, double scene_fps)
+{
+  MetaData abc_metadata;
+
+  std::string abc_user_description(bmain->name);
+  if (abc_user_description.empty()) {
+    abc_user_description = "unknown";
+  }
+
+  abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender");
+  abc_metadata.set(Alembic::Abc::kUserDescriptionKey, abc_user_description);
+  abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string());
+  abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps));
+
+  time_t raw_time;
+  time(&raw_time);
+  char buffer[128];
+
+#if defined _WIN32 || defined _WIN64
+  ctime_s(buffer, 128, &raw_time);
+#else
+  ctime_r(&raw_time, buffer);
+#endif
+
+  const std::size_t buffer_len = strlen(buffer);
+  if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
+    buffer[buffer_len - 1] = '\0';
+  }
+
+  abc_metadata.set(Alembic::Abc::kDateWrittenKey, buffer);
+  return abc_metadata;
+}
+
+static OArchive *create_archive(std::ofstream *abc_ostream,
+                                const std::string &filename,
+                                MetaData &abc_metadata)
+{
+  /* Use stream to support unicode character paths on Windows. */
+#ifdef WIN32
+  UTF16_ENCODE(filename);
+  std::wstring wstr(filename_16);
+  abc_ostream->open(wstr.c_str(), std::ios::out | std::ios::binary);
+  UTF16_UN_ENCODE(filename);
+#else
+  abc_ostream->open(filename, std::ios::out | std::ios::binary);
+#endif
+
+  ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy;
+
+  Alembic::AbcCoreOgawa::WriteArchive archive_writer;
+  return new OArchive(archive_writer(abc_ostream, abc_metadata), kWrapExisting, policy);
+}
+
+/* Construct list of shutter samples.
+ *
+ * These are taken from the interval [shutter open, shutter close),
+ * uniformly sampled with 'nr_of_samples' samples.
+ *
+ * TODO(Sybren): test that the above interval is indeed half-open.
+ *
+ * If 'time_relative' is true, samples are returned as time (in seconds) from params.frame_start.
+ * If 'time_relative' is false, samples are returned as fractional frames from 0.
+ * */
+static void get_shutter_samples(double scene_fps,
+                                const AlembicExportParams &params,
+                                int nr_of_samples,
+                                bool time_relative,
+                                std::vector<double> &r_samples)
+{
+  int frame_offset = time_relative ? params.frame_start : 0;
+  double time_factor = time_relative ? scene_fps : 1.0;
+  double shutter_open = params.shutter_open;
+  double shutter_close = params.shutter_close;
+  double time_inc = (shutter_close - shutter_open) / nr_of_samples;
+
+  /* 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;
+
+    r_samples.push_back(time);
+  }
+}
+
+static TimeSamplingPtr create_time_sampling(double scene_fps,
+                                            const AlembicExportParams &params,
+                                            int nr_of_samples)
+{
+  std::vector<double> samples;
+
+  if (params.frame_start == params.frame_end) {
+    return TimeSamplingPtr(new TimeSampling());
+  }
+
+  get_shutter_samples(scene_fps, params, nr_of_samples, true, samples);
+
+  TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / scene_fps);
+  return TimeSamplingPtr(new TimeSampling(ts, samples));
+}
+
+static void get_frames(double scene_fps,
+                       const AlembicExportParams &params,
+                       unsigned int nr_of_samples,
+                       std::set<double> &r_frames)
+{
+  /* Get one set of shutter samples, then add those around each frame to export. */
+  std::vector<double> shutter_samples;
+  get_shutter_samples(scene_fps, params, nr_of_samples, false, shutter_samples);
+
+  for (double frame = params.frame_start; frame <= params.frame_end; frame += 1.0) {
+    for (size_t j = 0; j < nr_of_samples; j++) {
+      r_frames.insert(frame + shutter_samples[j]);
+    }
+  }
+}
+
+/* ****************************************************************** */
+
+ABCArchive::ABCArchive(const Main *bmain,
+                       const Scene *scene,
+                       AlembicExportParams params,
+                       std::string filename)
+    : archive(nullptr)
+{
+  double scene_fps = FPS;
+  MetaData abc_metadata = create_abc_metadata(bmain, scene_fps);
+
+  // Create the Archive.
+  archive = create_archive(&abc_ostream_, filename, abc_metadata);
+
+  // Create time samples for transforms and shapes.
+  TimeSamplingPtr ts_xform;
+  TimeSamplingPtr ts_shapes;
+
+  ts_xform = create_time_sampling(scene_fps, params, params.frame_samples_xform);
+  time_sampling_index_transforms_ = archive->addTimeSampling(*ts_xform);
+
+  const bool export_animation = params.frame_start != params.frame_end;
+  if (!export_animation || params.frame_samples_shape == params.frame_samples_xform) {
+    ts_shapes = ts_xform;
+    time_sampling_index_shapes_ = time_sampling_index_transforms_;
+  }
+  else {
+    ts_shapes = create_time_sampling(scene_fps, params, params.frame_samples_shape);
+    time_sampling_index_shapes_ = archive->addTimeSampling(*ts_shapes);
+  }
+
+  // Construct the frames to export.
+  get_frames(scene_fps, params, params.frame_samples_xform, xform_frames_);
+  get_frames(scene_fps, params, params.frame_samples_shape, shape_frames_);
+
+  // Merge all frames to get the final set of frames to export.
+  export_frames_.insert(xform_frames_.begin(), xform_frames_.end());
+  export_frames_.insert(shape_frames_.begin(), shape_frames_.end());
+
+  abc_archive_bbox_ = Alembic::AbcGeom::CreateOArchiveBounds(*archive,
+                                                             time_sampling_index_transforms_);
+}
+
+ABCArchive::~ABCArchive()
+{
+  delete archive;
+}
+
+uint32_t ABCArchive::time_sampling_index_transforms() const
+{
+  return time_sampling_index_transforms_;
+}
+
+uint32_t ABCArchive::time_sampling_index_shapes() const
+{
+  return time_sampling_index_shapes_;
+}
+
+ABCArchive::Frames::const_iterator ABCArchive::frames_begin() const
+{
+  return export_frames_.begin();
+}
+ABCArchive::Frames::const_iterator ABCArchive::frames_end() const
+{
+  return export_frames_.end();
+}
+size_t ABCArchive::total_frame_count() const
+{
+  return export_frames_.size();
+}
+
+bool ABCArchive::is_xform_frame(double frame) const
+{
+  return xform_frames_.find(frame) != xform_frames_.end();
+}
+bool ABCArchive::is_shape_frame(double frame) const
+{
+  return shape_frames_.find(frame) != shape_frames_.end();
+}
+ExportSubset ABCArchive::export_subset_for_frame(double frame) const
+{
+  ExportSubset subset;
+  subset.transforms = is_xform_frame(frame);
+  subset.shapes = is_shape_frame(frame);
+  return subset;
+}
+
+void ABCArch

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list