15#include <pxr/base/tf/token.h>
17#include <pxr/usd/sdf/assetPath.h>
18#include <pxr/usd/sdf/path.h>
19#include <pxr/usd/usd/primRange.h>
20#include <pxr/usd/usd/stage.h>
21#include <pxr/usd/usdGeom/metrics.h>
22#include <pxr/usd/usdGeom/pointInstancer.h>
23#include <pxr/usd/usdGeom/tokens.h>
24#include <pxr/usd/usdGeom/xform.h>
25#include <pxr/usd/usdGeom/xformCommonAPI.h>
26#include <pxr/usd/usdUtils/usdzPackage.h>
102 if (path[0] ==
'\0') {
110 if (!pxr::SdfPath::IsValidPathString(path, &errMsg)) {
118 pxr::SdfPath sdf_path(path);
119 if (!sdf_path.IsAbsolutePath()) {
124 if (!sdf_path.IsPrimPath()) {
157 if (
params.root_prim_path[0] ==
'\0') {
161 pxr::UsdGeomXform root_xf = pxr::UsdGeomXform::Define(stage,
162 pxr::SdfPath(
params.root_prim_path));
168 pxr::UsdGeomXformCommonAPI xf_api(root_xf.GetPrim());
174 if (
params.convert_scene_units) {
178 if (
params.convert_orientation) {
189 xf_api.SetRotate(pxr::GfVec3f(eul[0], eul[1], eul[2]));
192 for (
const auto &path : pxr::SdfPath(
params.root_prim_path).GetPrefixes()) {
193 auto xform = pxr::UsdGeomXform::Define(stage, path);
195 xform.GetPrim().SetCustomDataByKey(pxr::TfToken(
"Blender:generated"), pxr::VtValue(
true));
202 const char *export_filepath =
data->export_filepath();
203 fmt::print(
"USD export of '{}' took ", export_filepath);
216 data->params.usdz_downscale_custom_size :
227 for (
int index = 0; index < num_files; index++) {
233 CLOG_WARN(&
LOG,
"Unable to open file for downscaling: %s", entries[index].path);
239 const int longest = width >= height ? width : height;
240 const float scale = 1.0 / (float(longest) / float(image_size));
242 if (longest > image_size) {
243 const int width_adjusted = float(width) * scale;
244 const int height_adjusted = float(height) * scale;
250 &opts,
data->bmain,
data->scene, im,
nullptr,
false,
false))
255 "Unable to resave '%s' (new size: %dx%d)",
263 "Downscaled '%s' to %dx%d",
295 sizeof(usdc_temp_dir),
302 char original_working_dir_buff[
FILE_MAX];
304 sizeof(original_working_dir_buff));
307 BLI_assert(original_working_dir == original_working_dir_buff);
313 pxr::UsdUtilsCreateNewUsdzPackage(pxr::SdfAssetPath(usdc_file), usdz_file);
325 "USD Export: Unable to delete existing usdz file %s",
326 data->usdz_filepath);
334 "USD Export: Couldn't move new usdz file from temporary location %s to %s",
336 data->usdz_filepath);
358 BLI_path_join(file_path,
sizeof(file_path), dir_path.c_str(), file_name.c_str());
366 "color_%02d%02d%02d.hdr",
369 int(
color[2] * 255));
392 pxr::UsdGeomPointInstancer instancer,
393 const pxr::UsdStageRefPtr &stage,
394 const pxr::SdfPath &wrapper_path,
395 std::vector<pxr::UsdPrim> &proto_list)
398 pxr::VtArray<pxr::GfVec3f> extent;
399 instancer.ComputeExtentAtTime(
400 &extent, pxr::UsdTimeCode().Default(), pxr::UsdTimeCode().Default());
401 instancer.CreateExtentAttr().Set(extent);
403 pxr::UsdPrim wrapper_prim = stage->GetPrimAtPath(wrapper_path);
404 if (!wrapper_prim || !wrapper_prim.IsValid()) {
408 std::string real_path_str;
410 for (
const pxr::SdfPrimSpecHandle &primSpec : wrapper_prim.GetPrimStack()) {
411 if (!primSpec || !primSpec->HasReferences()) {
415 for (
const pxr::SdfReference &ref : primSpec->GetReferenceList().GetPrependedItems()) {
416 if (ref.GetAssetPath().empty() && !ref.GetPrimPath().IsEmpty()) {
417 real_path_str = ref.GetPrimPath().GetString();
421 if (!real_path_str.empty()) {
426 if (real_path_str.empty()) {
427 CLOG_WARN(&
LOG,
"No prototype reference found for: %s", wrapper_path.GetText());
431 const pxr::SdfPath real_path(real_path_str);
432 pxr::UsdPrim proto_prim = stage->GetPrimAtPath(real_path);
434 if (!proto_prim || !proto_prim.IsValid()) {
435 CLOG_WARN(&
LOG,
"Referenced prototype not found at: %s", real_path.GetText());
439 proto_list.push_back(proto_prim);
440 proto_list.push_back(wrapper_prim.GetParent());
442 std::string doc_message = fmt::format(
443 "This prim is used as a prototype by the PointInstancer \"{}\" so we override the def "
444 "with an \"over\" so that it isn't imaged in the scene, but is available as a prototype "
445 "that can be referenced.",
446 wrapper_prim.GetName().GetString());
447 proto_prim.SetDocumentation(doc_message);
450 if (proto_prim.IsA<pxr::UsdGeomPointInstancer>()) {
451 pxr::UsdGeomPointInstancer nested_instancer(proto_prim);
452 pxr::SdfPathVector nested_targets;
453 if (nested_instancer.GetPrototypesRel().GetTargets(&nested_targets)) {
454 for (
const pxr::SdfPath &nested_wrapper_path : nested_targets) {
456 nested_instancer, stage, nested_wrapper_path, proto_list);
462 for (
const pxr::UsdPrim &child : proto_prim.GetAllChildren()) {
463 if (child.IsA<pxr::UsdGeomPointInstancer>()) {
464 pxr::UsdGeomPointInstancer nested_instancer(child);
465 pxr::SdfPathVector nested_targets;
466 if (nested_instancer.GetPrototypesRel().GetTargets(&nested_targets)) {
467 for (
const pxr::SdfPath &nested_wrapper_path : nested_targets) {
469 nested_instancer, stage, nested_wrapper_path, proto_list);
478 const char *filepath)
480 pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(filepath);
485 wmJobWorkerStatus *worker_status =
params.worker_status;
500 worker_status->progress = 0.10f;
501 worker_status->do_update =
true;
503 usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit,
double(scene->
unit.
scale_length));
504 usd_stage->GetRootLayer()->SetDocumentation(std::string(
"Blender v") +
508 if (
params.export_animation) {
509 usd_stage->SetTimeCodesPerSecond(
FPS);
510 usd_stage->SetStartTimeCode(scene->
r.
sfra);
511 usd_stage->SetEndTimeCode(scene->
r.
efra);
515 const int orig_frame = scene->
r.
cfra;
520 pxr::VtValue upAxis = pxr::VtValue(pxr::UsdGeomTokens->
z);
521 if (
params.convert_orientation) {
523 upAxis = pxr::VtValue(pxr::UsdGeomTokens->
x);
526 upAxis = pxr::VtValue(pxr::UsdGeomTokens->
y);
530 usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, upAxis);
533 pxr::UsdGeomSetStageMetersPerUnit(usd_stage, meters_per_unit);
539 worker_status->progress = 0.11f;
540 worker_status->do_update =
true;
542 if (
params.export_animation) {
544 float progress_per_frame = 0.75f / std::max(1, (scene->
r.
efra - scene->
r.
sfra + 1));
546 for (
float frame = scene->
r.
sfra; frame <= scene->r.efra; frame++) {
547 if (
G.is_break || worker_status->stop) {
552 scene->
r.
cfra = int(frame);
559 worker_status->progress += progress_per_frame;
560 worker_status->do_update =
true;
568 worker_status->progress = 0.86f;
569 worker_status->do_update =
true;
573 if (
params.export_shapekeys ||
params.export_armatures) {
580 if (
params.convert_world_material) {
585 if (!usd_stage->GetDefaultPrim()) {
588 for (
auto prim : usd_stage->TraverseAll()) {
589 usd_stage->SetDefaultPrim(prim);
594 if (
params.use_instancing) {
600 worker_status->progress = 0.88f;
601 worker_status->do_update =
true;
604 if (scene->
r.
cfra != orig_frame) {
605 scene->
r.
cfra = orig_frame;
609 worker_status->progress = 0.9f;
610 worker_status->do_update =
true;
618 data->export_ok =
false;
619 data->start_time = timeit::Clock::now();
621 G.is_rendering =
true;
627 worker_status->progress = 0.01f;
628 worker_status->do_update =
true;
639 worker_status->progress = 0.1f;
640 worker_status->do_update =
true;
641 data->params.worker_status = worker_status;
644 data->params,
data->depsgraph,
data->unarchived_filepath);
651 "USD Export: unable to find suitable USD plugin to write %s",
652 data->unarchived_filepath);
658 std::vector<pxr::UsdPrim> proto_list;
659 for (
const pxr::UsdPrim &prim : usd_stage->Traverse()) {
660 if (!prim.IsA<pxr::UsdGeomPointInstancer>()) {
663 pxr::UsdGeomPointInstancer instancer(prim);
664 pxr::SdfPathVector targets;
665 if (instancer.GetPrototypesRel().GetTargets(&targets)) {
666 for (
const pxr::SdfPath &wrapper_path : targets) {
668 instancer, usd_stage, wrapper_path, proto_list);
676 for (pxr::UsdPrim &proto : proto_list) {
677 proto.SetSpecifier(pxr::SdfSpecifierOver);
680 usd_stage->GetRootLayer()->Save();
682 data->export_ok =
true;
683 worker_status->progress = 1.0f;
684 worker_status->do_update =
true;
700 "USD Export: Attempting to delete directory that doesn't match the expected "
701 "temporary directory for usdz export.");
711 if (
data->targets_usdz()) {
718 if (!usd_conversion_success) {
719 data->export_ok =
false;
729 G.is_rendering =
false;
770 const char *filepath,
772 bool as_background_job,
803 "USD Export: Unable to find collection '%s'",
817 bool export_ok =
false;
818 if (as_background_job) {
836 wmJobWorkerStatus worker_status = {};
838 worker_status.reports =
reports;
867 switch (
params.convert_scene_units) {
const char * BKE_blender_version_string(void)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
Image * BKE_image_load(Main *bmain, const char *filepath)
bool BKE_image_scale(Image *image, int width, int height, ImageUser *iuser)
void BKE_image_get_size(Image *image, ImageUser *iuser, int *r_width, int *r_height)
bool BKE_image_save(ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
bool BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene, Image *ima, ImageUser *iuser, const bool guess_path, const bool save_as_render)
void BKE_image_save_options_free(ImageSaveOptions *opts)
ID * BKE_libblock_find_name(Main *bmain, short type, const char *name, const std::optional< Library * > lib=std::nullopt) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BKE_id_free(Main *bmain, void *idv)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
#define BLI_assert_msg(a, msg)
File and directory operations.
bool BLI_change_working_dir(const char *dir)
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
char * BLI_current_working_dir(char *dir, size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_path_move(const char *path_src, const char *path_dst) ATTR_NONNULL()
void transpose_m3(float R[3][3])
void mat3_to_eul(float eul[3], const float mat[3][3])
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
MINLINE void mul_v3_fl(float r[3], float f)
size_t BLI_path_append(char *__restrict dst, size_t dst_maxncpy, const char *__restrict file) ATTR_NONNULL(1
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_extension_replace(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
#define BLI_path_join(...)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_extension_check(const char *path, const char *ext) ATTR_NONNULL(1
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
bool BLI_path_extension_check_n(const char *path,...) ATTR_NONNULL(1) ATTR_SENTINEL(0)
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
#define SNPRINTF(dst, format,...)
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
#define CLOG_ERROR(clg_ref,...)
#define CLOG_WARN(clg_ref,...)
#define CLOG_INFO(clg_ref, level,...)
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
void DEG_graph_free(Depsgraph *graph)
void DEG_graph_build_from_collection(Depsgraph *graph, Collection *collection)
void DEG_graph_build_for_all_objects(Depsgraph *graph)
void DEG_graph_build_from_view_layer(Depsgraph *graph)
Main * DEG_get_bmain(const Depsgraph *graph)
Scene * DEG_get_input_scene(const Depsgraph *graph)
Object groups, one object can be in many groups at once.
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_rectfill(ImBuf *drect, const float col[4])
bool IMB_save_image(ImBuf *ibuf, const char *filepath, const int flags)
Read Guarded memory(de)allocation.
BMesh const char void * data
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
virtual void iterate_and_write()
void process_usd_skel() const
void set_export_frame(float frame_nr)
std::string image_cache_file_path()
void world_material_to_dome_light(const USDExportParams ¶ms, const Scene *scene, pxr::UsdStageRefPtr stage)
static void set_job_filepath(blender::io::usd::ExportJobData *job, const char *filepath)
static void collect_point_instancer_prototypes_and_set_extent(pxr::UsdGeomPointInstancer instancer, const pxr::UsdStageRefPtr &stage, const pxr::SdfPath &wrapper_path, std::vector< pxr::UsdPrim > &proto_list)
static bool perform_usdz_conversion(const ExportJobData *data)
@ USD_SCENE_UNITS_MILLIMETERS
@ USD_SCENE_UNITS_CENTIMETERS
@ USD_SCENE_UNITS_KILOMETERS
std::string cache_image_color(const float color[4])
static void report_job_duration(const ExportJobData *data)
static bool prim_path_valid(const char *path)
std::string get_image_cache_file(const std::string &file_name, bool mkdir)
static bool export_params_valid(const USDExportParams ¶ms)
static void export_endjob_usdz_cleanup(const ExportJobData *data)
void process_scene_graph_instances(const USDExportParams &export_params, pxr::UsdStageRefPtr stage)
bool USD_export(const bContext *C, const char *filepath, const USDExportParams *params, bool as_background_job, ReportList *reports)
static void ensure_root_prim(pxr::UsdStageRefPtr stage, const USDExportParams ¶ms)
pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms, Depsgraph *depsgraph, const char *filepath)
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports)
static void export_startjob(void *customdata, wmJobWorkerStatus *worker_status)
double get_meters_per_unit(const USDExportParams ¶ms)
static void create_temp_path_for_usdz_export(const char *filepath, blender::io::usd::ExportJobData *job)
eUSDZTextureDownscaleSize
@ USD_TEXTURE_SIZE_CUSTOM
static void process_usdz_textures(const ExportJobData *data, const char *path)
static void export_endjob(void *customdata)
void register_hook_converters()
std::chrono::nanoseconds Nanoseconds
Clock::time_point TimePoint
void print_duration(Nanoseconds duration)
bool targets_usdz() const
const char * export_filepath() const
char usdz_filepath[FILE_MAX]
char unarchived_filepath[FILE_MAX]
timeit::TimePoint start_time
char collection[MAX_IDPROP_NAME]
bool visible_objects_only
void * BKE_tempdir_session
void WM_global_reportf(eReportType type, const char *format,...)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))