221 lines
6.5 KiB
C++
221 lines
6.5 KiB
C++
/*
|
|
* 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) 2019 Blender Foundation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "usd.h"
|
|
#include "usd_hierarchy_iterator.h"
|
|
|
|
#include <pxr/pxr.h>
|
|
#include <pxr/usd/usd/stage.h>
|
|
#include <pxr/usd/usdGeom/tokens.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DEG_depsgraph.h"
|
|
#include "DEG_depsgraph_build.h"
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "BKE_blender_version.h"
|
|
#include "BKE_context.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_scene.h"
|
|
|
|
#include "BLI_fileops.h"
|
|
#include "BLI_path_util.h"
|
|
#include "BLI_string.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
namespace USD {
|
|
|
|
struct ExportJobData {
|
|
Main *bmain;
|
|
Depsgraph *depsgraph;
|
|
wmWindowManager *wm;
|
|
|
|
char filename[FILE_MAX];
|
|
USDExportParams params;
|
|
|
|
bool export_ok;
|
|
};
|
|
|
|
static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
|
|
{
|
|
ExportJobData *data = static_cast<ExportJobData *>(customdata);
|
|
data->export_ok = false;
|
|
|
|
G.is_rendering = true;
|
|
WM_set_locked_interface(data->wm, true);
|
|
G.is_break = false;
|
|
|
|
// Construct the depsgraph for exporting.
|
|
Scene *scene = DEG_get_input_scene(data->depsgraph);
|
|
ViewLayer *view_layer = DEG_get_input_view_layer(data->depsgraph);
|
|
DEG_graph_build_from_view_layer(data->depsgraph, data->bmain, scene, view_layer);
|
|
BKE_scene_graph_update_tagged(data->depsgraph, data->bmain);
|
|
|
|
*progress = 0.0f;
|
|
*do_update = true;
|
|
|
|
// For restoring the current frame after exporting animation is done.
|
|
const int orig_frame = CFRA;
|
|
|
|
pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->filename);
|
|
if (!usd_stage) {
|
|
/* This happens when the USD JSON files cannot be found. When that happens,
|
|
* the USD library doesn't know it has the functionality to write USDA and
|
|
* USDC files, and creating a new UsdStage fails. */
|
|
WM_reportf(
|
|
RPT_ERROR, "USD Export: unable to find suitable USD plugin to write %s", data->filename);
|
|
return;
|
|
}
|
|
|
|
usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z));
|
|
usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit,
|
|
pxr::VtValue(scene->unit.scale_length));
|
|
usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender v") +
|
|
BKE_blender_version_string());
|
|
|
|
// Set up the stage for animated data.
|
|
if (data->params.export_animation) {
|
|
usd_stage->SetTimeCodesPerSecond(FPS);
|
|
usd_stage->SetStartTimeCode(scene->r.sfra);
|
|
usd_stage->SetEndTimeCode(scene->r.efra);
|
|
}
|
|
|
|
USDHierarchyIterator iter(data->depsgraph, usd_stage, data->params);
|
|
|
|
if (data->params.export_animation) {
|
|
// Writing the animated frames is not 100% of the work, but it's our best guess.
|
|
float progress_per_frame = 1.0f / std::max(1, (scene->r.efra - scene->r.sfra + 1));
|
|
|
|
for (float frame = scene->r.sfra; frame <= scene->r.efra; frame++) {
|
|
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);
|
|
|
|
iter.set_export_frame(frame);
|
|
iter.iterate_and_write();
|
|
|
|
*progress += progress_per_frame;
|
|
*do_update = true;
|
|
}
|
|
}
|
|
else {
|
|
// If we're not animating, a single iteration over all objects is enough.
|
|
iter.iterate_and_write();
|
|
}
|
|
|
|
iter.release_writers();
|
|
usd_stage->GetRootLayer()->Save();
|
|
|
|
// 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 = true;
|
|
*progress = 1.0f;
|
|
*do_update = true;
|
|
}
|
|
|
|
static void export_endjob(void *customdata)
|
|
{
|
|
ExportJobData *data = static_cast<ExportJobData *>(customdata);
|
|
|
|
DEG_graph_free(data->depsgraph);
|
|
|
|
if (!data->export_ok && BLI_exists(data->filename)) {
|
|
BLI_delete(data->filename, false, false);
|
|
}
|
|
|
|
G.is_rendering = false;
|
|
WM_set_locked_interface(data->wm, false);
|
|
}
|
|
|
|
} // namespace USD
|
|
|
|
bool USD_export(bContext *C,
|
|
const char *filepath,
|
|
const USDExportParams *params,
|
|
bool as_background_job)
|
|
{
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
USD::ExportJobData *job = static_cast<USD::ExportJobData *>(
|
|
MEM_mallocN(sizeof(USD::ExportJobData), "ExportJobData"));
|
|
|
|
job->bmain = CTX_data_main(C);
|
|
job->wm = CTX_wm_manager(C);
|
|
job->export_ok = false;
|
|
BLI_strncpy(job->filename, filepath, sizeof(job->filename));
|
|
|
|
job->depsgraph = DEG_graph_new(job->bmain, scene, view_layer, params->evaluation_mode);
|
|
job->params = *params;
|
|
|
|
bool export_ok = false;
|
|
if (as_background_job) {
|
|
wmJob *wm_job = WM_jobs_get(
|
|
job->wm, CTX_wm_window(C), scene, "USD 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, USD::export_startjob, nullptr, nullptr, USD::export_endjob);
|
|
|
|
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
|
}
|
|
else {
|
|
/* Fake a job context, so that we don't need NULL pointer checks while exporting. */
|
|
short stop = 0, do_update = 0;
|
|
float progress = 0.f;
|
|
|
|
USD::export_startjob(job, &stop, &do_update, &progress);
|
|
USD::export_endjob(job);
|
|
export_ok = job->export_ok;
|
|
|
|
MEM_freeN(job);
|
|
}
|
|
|
|
return export_ok;
|
|
}
|
|
|
|
int USD_get_version(void)
|
|
{
|
|
/* USD 19.11 defines:
|
|
*
|
|
* #define PXR_MAJOR_VERSION 0
|
|
* #define PXR_MINOR_VERSION 19
|
|
* #define PXR_PATCH_VERSION 11
|
|
* #define PXR_VERSION 1911
|
|
*
|
|
* So the major version is implicit/invisible in the public version number.
|
|
*/
|
|
return PXR_VERSION;
|
|
}
|