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:
authorSybren A. Stüvel <sybren@blender.org>2020-06-19 17:36:10 +0300
committerSybren A. Stüvel <sybren@blender.org>2020-06-30 12:38:46 +0300
commit2917df21adc8a1ce0423349909db61d22a38d451 (patch)
tree35b8ccdf0078fda4f186821b016701f46cb42c86 /source/blender/io/alembic/exporter/abc_export_capi.cc
parenta2b7c84ae8eadf5983ee42091ce4e33315ca83ce (diff)
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
Diffstat (limited to 'source/blender/io/alembic/exporter/abc_export_capi.cc')
-rw-r--r--source/blender/io/alembic/exporter/abc_export_capi.cc229
1 files changed, 105 insertions, 124 deletions
diff --git a/source/blender/io/alembic/exporter/abc_export_capi.cc b/source/blender/io/alembic/exporter/abc_export_capi.cc
index c0d04b50acd..fbc5b2d5c02 100644
--- a/source/blender/io/alembic/exporter/abc_export_capi.cc
+++ b/source/blender/io/alembic/exporter/abc_export_capi.cc
@@ -18,18 +18,15 @@
*/
#include "ABC_alembic.h"
-#include "abc_writer_camera.h"
-#include "abc_writer_curves.h"
-#include "abc_writer_hair.h"
-#include "abc_writer_mesh.h"
-#include "abc_writer_nurbs.h"
-#include "abc_writer_points.h"
-#include "abc_writer_transform.h"
+#include "abc_archive.h"
+#include "abc_hierarchy_iterator.h"
+#include "abc_subdiv_disabler.h"
#include "MEM_guardedalloc.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
@@ -47,179 +44,163 @@
#include "WM_api.h"
#include "WM_types.h"
-using namespace blender::io::alembic;
+#include "CLG_log.h"
+static CLG_LogRef LOG = {"io.alembic"};
+
+#include <algorithm>
struct ExportJobData {
- ViewLayer *view_layer;
Main *bmain;
+ Depsgraph *depsgraph;
wmWindowManager *wm;
- char filename[1024];
- ExportSettings settings;
-
- short *stop;
- short *do_update;
- float *progress;
+ char filename[FILE_MAX];
+ AlembicExportParams params;
bool was_canceled;
bool export_ok;
};
+namespace blender {
+namespace io {
+namespace alembic {
+
+// Construct the depsgraph for exporting.
+static void build_depsgraph(Depsgraph *depsgraph, Main *bmain)
+{
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
+}
+
static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
ExportJobData *data = static_cast<ExportJobData *>(customdata);
+ data->was_canceled = false;
- data->stop = stop;
- data->do_update = do_update;
- data->progress = progress;
-
- /* XXX annoying hack: needed to prevent data corruption when changing
- * scene frame in separate threads
- */
G.is_rendering = true;
WM_set_locked_interface(data->wm, true);
G.is_break = false;
- DEG_graph_build_from_view_layer(
- data->settings.depsgraph, data->bmain, data->settings.scene, data->view_layer);
- BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain);
+ *progress = 0.0f;
+ *do_update = true;
- try {
- AbcExporter exporter(data->bmain, data->filename, data->settings);
+ build_depsgraph(data->depsgraph, data->bmain);
+ SubdivModifierDisabler subdiv_disabler(data->depsgraph);
+ if (!data->params.apply_subdiv) {
+ subdiv_disabler.disable_modifiers();
+ }
+ BKE_scene_graph_update_tagged(data->depsgraph, data->bmain);
- Scene *scene = data->settings.scene; /* for the CFRA macro */
- const int orig_frame = CFRA;
+ // For restoring the current frame after exporting animation is done.
+ Scene *scene = DEG_get_input_scene(data->depsgraph);
+ const int orig_frame = CFRA;
+ const bool export_animation = (data->params.frame_start != data->params.frame_end);
- data->was_canceled = false;
- exporter(do_update, progress, &data->was_canceled);
+ // Create the Alembic archive.
+ ABCArchive abc_archive(data->bmain, scene, data->params, std::string(data->filename));
- if (CFRA != orig_frame) {
- CFRA = orig_frame;
+ ABCHierarchyIterator iter(data->depsgraph, &abc_archive, data->params);
- BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain);
- }
+ if (export_animation) {
+ CLOG_INFO(&LOG, 2, "Exporting animation");
+
+ // Writing the animated frames is not 100% of the work, but it's our best guess.
+ const float progress_per_frame = 1.0f / std::max(size_t(1), abc_archive.total_frame_count());
+ ABCArchive::Frames::const_iterator frame_it = abc_archive.frames_begin();
+ const ABCArchive::Frames::const_iterator frames_end = abc_archive.frames_end();
+
+ for (; frame_it != frames_end; frame_it++) {
+ double frame = *frame_it;
+
+ if (G.is_break || (stop != nullptr && *stop)) {
+ break;
+ }
+
+ // Update the scene for the next frame to render.
+ scene->r.cfra = static_cast<int>(frame);
+ scene->r.subframe = frame - scene->r.cfra;
+ BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain);
- data->export_ok = !data->was_canceled;
+ CLOG_INFO(&LOG, 2, "Exporting frame %.2f", frame);
+ ExportSubset export_subset = abc_archive.export_subset_for_frame(frame);
+ iter.set_export_subset(export_subset);
+ iter.iterate_and_write();
+
+ *progress += progress_per_frame;
+ *do_update = true;
+ }
}
- catch (const std::exception &e) {
- ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n';
+ else {
+ // If we're not animating, a single iteration over all objects is enough.
+ iter.iterate_and_write();
}
- catch (...) {
- ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n";
+
+ iter.release_writers();
+
+ // Finish up by going back to the keyframe that was current before we started.
+ if (CFRA != orig_frame) {
+ CFRA = orig_frame;
+ BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain);
}
+
+ data->export_ok = !data->was_canceled;
+
+ *progress = 1.0f;
+ *do_update = true;
}
static void export_endjob(void *customdata)
{
ExportJobData *data = static_cast<ExportJobData *>(customdata);
- DEG_graph_free(data->settings.depsgraph);
+ DEG_graph_free(data->depsgraph);
if (data->was_canceled && BLI_exists(data->filename)) {
BLI_delete(data->filename, false, false);
}
- std::string log = data->settings.logger.str();
- if (!log.empty()) {
- std::cerr << log;
- WM_report(RPT_ERROR, "Errors occurred during the export, look in the console to know more...");
- }
-
G.is_rendering = false;
WM_set_locked_interface(data->wm, false);
}
-bool ABC_export(struct Scene *scene,
- struct bContext *C,
+} // namespace alembic
+} // namespace io
+} // namespace blender
+
+bool ABC_export(Scene *scene,
+ bContext *C,
const char *filepath,
- const struct AlembicExportParams *params,
+ const AlembicExportParams *params,
bool as_background_job)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
ExportJobData *job = static_cast<ExportJobData *>(
MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
- job->view_layer = CTX_data_view_layer(C);
job->bmain = CTX_data_main(C);
job->wm = CTX_wm_manager(C);
job->export_ok = false;
- BLI_strncpy(job->filename, filepath, 1024);
-
- /* Alright, alright, alright....
- *
- * ExportJobData contains an ExportSettings containing a SimpleLogger.
- *
- * Since ExportJobData is a C-style struct dynamically allocated with
- * MEM_mallocN (see above), its constructor is never called, therefore the
- * ExportSettings constructor is not called which implies that the
- * SimpleLogger one is not called either. SimpleLogger in turn does not call
- * the constructor of its data members which ultimately means that its
- * std::ostringstream member has a NULL pointer. To be able to properly use
- * the stream's operator<<, the pointer needs to be set, therefore we have
- * to properly construct everything. And this is done using the placement
- * new operator as here below. It seems hackish, but I'm too lazy to
- * do bigger refactor and maybe there is a better way which does not involve
- * hardcore refactoring. */
- new (&job->settings) ExportSettings();
- job->settings.scene = scene;
- job->settings.depsgraph = DEG_graph_new(job->bmain, scene, job->view_layer, DAG_EVAL_RENDER);
-
- /* TODO(Sybren): for now we only export the active scene layer.
- * Later in the 2.8 development process this may be replaced by using
- * a specific collection for Alembic I/O, which can then be toggled
- * between "real" objects and cached Alembic files. */
- job->settings.view_layer = job->view_layer;
-
- job->settings.frame_start = params->frame_start;
- job->settings.frame_end = params->frame_end;
- job->settings.frame_samples_xform = params->frame_samples_xform;
- job->settings.frame_samples_shape = params->frame_samples_shape;
- job->settings.shutter_open = params->shutter_open;
- job->settings.shutter_close = params->shutter_close;
-
- /* TODO(Sybren): For now this is ignored, until we can get selection
- * detection working through Base pointers (instead of ob->flags). */
- job->settings.selected_only = params->selected_only;
-
- job->settings.export_face_sets = params->face_sets;
- job->settings.export_normals = params->normals;
- job->settings.export_uvs = params->uvs;
- job->settings.export_vcols = params->vcolors;
- job->settings.export_hair = params->export_hair;
- job->settings.export_particles = params->export_particles;
- job->settings.apply_subdiv = params->apply_subdiv;
- job->settings.curves_as_mesh = params->curves_as_mesh;
- job->settings.flatten_hierarchy = params->flatten_hierarchy;
-
- /* TODO(Sybren): visible_layer & renderable only is ignored for now,
- * to be replaced with collections later in the 2.8 dev process
- * (also see note above). */
- job->settings.visible_objects_only = params->visible_objects_only;
- job->settings.renderable_only = params->renderable_only;
-
- job->settings.use_subdiv_schema = params->use_subdiv_schema;
- job->settings.pack_uv = params->packuv;
- job->settings.global_scale = params->global_scale;
- job->settings.triangulate = params->triangulate;
- job->settings.quad_method = params->quad_method;
- job->settings.ngon_method = params->ngon_method;
-
- if (job->settings.frame_start > job->settings.frame_end) {
- std::swap(job->settings.frame_start, job->settings.frame_end);
- }
+ BLI_strncpy(job->filename, filepath, sizeof(job->filename));
+
+ job->depsgraph = DEG_graph_new(
+ job->bmain, scene, view_layer, DAG_EVAL_RENDER /* TODO(Sybren): params->evaluation_mode */);
+ job->params = *params;
bool export_ok = false;
if (as_background_job) {
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- job->settings.scene,
- "Alembic Export",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_ALEMBIC);
+ wmJob *wm_job = WM_jobs_get(
+ job->wm, CTX_wm_window(C), scene, "Alembic Export", WM_JOB_PROGRESS, WM_JOB_TYPE_ALEMBIC);
/* setup job */
WM_jobs_customdata_set(wm_job, job, MEM_freeN);
WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
+ WM_jobs_callbacks(wm_job,
+ blender::io::alembic::export_startjob,
+ NULL,
+ NULL,
+ blender::io::alembic::export_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -228,8 +209,8 @@ bool ABC_export(struct Scene *scene,
short stop = 0, do_update = 0;
float progress = 0.f;
- export_startjob(job, &stop, &do_update, &progress);
- export_endjob(job);
+ blender::io::alembic::export_startjob(job, &stop, &do_update, &progress);
+ blender::io::alembic::export_endjob(job);
export_ok = job->export_ok;
MEM_freeN(job);