Blender V4.5
io_usd.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#ifdef WITH_USD
10# include "DNA_modifier_types.h"
11# include "DNA_space_types.h"
12
13# include "BKE_context.hh"
14# include "BKE_file_handler.hh"
15# include "BKE_report.hh"
16
17# include "BLI_path_utils.hh"
18# include "BLI_string.h"
19
20# include "BLT_translation.hh"
21
22# include "ED_fileselect.hh"
23# include "ED_object.hh"
24
25# include "MEM_guardedalloc.h"
26
27# include "RNA_access.hh"
28# include "RNA_define.hh"
29# include "RNA_enum_types.hh"
30
31# include "UI_interface.hh"
32# include "UI_resources.hh"
33
34# include "WM_api.hh"
35# include "WM_types.hh"
36
37# include "DEG_depsgraph.hh"
38
39# include "IO_orientation.hh"
40# include "io_usd.hh"
41# include "io_utils.hh"
42# include "usd.hh"
43
44# include <pxr/pxr.h>
45
46# include <string>
47# include <utility>
48
49using namespace blender::io::usd;
50
51const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
53 "RENDER",
54 0,
55 "Render",
56 "Use Render settings for object visibility, modifier settings, etc"},
58 "VIEWPORT",
59 0,
60 "Viewport",
61 "Use Viewport settings for object visibility, modifier settings, etc"},
62 {0, nullptr, 0, nullptr, nullptr},
63};
64
65const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = {
67 "MAKE_UNIQUE",
68 0,
69 "Make Unique",
70 "Import each USD material as a unique Blender material"},
72 "REFERENCE_EXISTING",
73 0,
74 "Reference Existing",
75 "If a material with the same name already exists, reference that instead of importing"},
76 {0, nullptr, 0, nullptr, nullptr},
77};
78
79const EnumPropertyItem rna_enum_usd_attr_import_mode_items[] = {
80 {USD_ATTR_IMPORT_NONE, "NONE", 0, "None", "Do not import USD custom attributes"},
82 "USER",
83 0,
84 "User",
85 "Import USD attributes in the 'userProperties' namespace as Blender custom "
86 "properties. The namespace will be stripped from the property names"},
88 "ALL",
89 0,
90 "All Custom",
91 "Import all USD custom attributes as Blender custom properties. "
92 "Namespaces will be retained in the property names"},
93 {0, nullptr, 0, nullptr, nullptr},
94};
95
96const EnumPropertyItem rna_enum_usd_tex_import_mode_items[] = {
97 {USD_TEX_IMPORT_NONE, "IMPORT_NONE", 0, "None", "Don't import textures"},
98 {USD_TEX_IMPORT_PACK, "IMPORT_PACK", 0, "Packed", "Import textures as packed data"},
99 {USD_TEX_IMPORT_COPY, "IMPORT_COPY", 0, "Copy", "Copy files to textures directory"},
100 {0, nullptr, 0, nullptr, nullptr},
101};
102
103const EnumPropertyItem rna_enum_usd_tex_name_collision_mode_items[] = {
105 "USE_EXISTING",
106 0,
107 "Use Existing",
108 "If a file with the same name already exists, use that instead of copying"},
109 {USD_TEX_NAME_COLLISION_OVERWRITE, "OVERWRITE", 0, "Overwrite", "Overwrite existing files"},
110 {0, nullptr, 0, nullptr, nullptr},
111};
112
113const EnumPropertyItem rna_enum_usd_export_subdiv_mode_items[] = {
115 "IGNORE",
116 0,
117 "Ignore",
118 "Scheme = None. Export base mesh without subdivision"},
120 "TESSELLATE",
121 0,
122 "Tessellate",
123 "Scheme = None. Export subdivided mesh"},
125 "BEST_MATCH",
126 0,
127 "Best Match",
128 "Scheme = Catmull-Clark, when possible. "
129 "Reverts to exporting the subdivided mesh for the Simple subdivision type"},
130 {0, nullptr, 0, nullptr, nullptr},
131};
132
133const EnumPropertyItem rna_enum_usd_xform_op_mode_items[] = {
135 "TRS",
136 0,
137 "Translate, Rotate, Scale",
138 "Export with translate, rotate, and scale Xform operators"},
140 "TOS",
141 0,
142 "Translate, Orient, Scale",
143 "Export with translate, orient quaternion, and scale Xform operators"},
144 {USD_XFORM_OP_MAT, "MAT", 0, "Matrix", "Export matrix operator"},
145 {0, nullptr, 0, nullptr, nullptr},
146};
147
148const EnumPropertyItem rna_enum_usdz_downscale_size[] = {
149 {USD_TEXTURE_SIZE_KEEP, "KEEP", 0, "Keep", "Keep all current texture sizes"},
150 {USD_TEXTURE_SIZE_256, "256", 0, "256", "Resize to a maximum of 256 pixels"},
151 {USD_TEXTURE_SIZE_512, "512", 0, "512", "Resize to a maximum of 512 pixels"},
152 {USD_TEXTURE_SIZE_1024, "1024", 0, "1024", "Resize to a maximum of 1024 pixels"},
153 {USD_TEXTURE_SIZE_2048, "2048", 0, "2048", "Resize to a maximum of 2048 pixels"},
154 {USD_TEXTURE_SIZE_4096, "4096", 0, "4096", "Resize to a maximum of 4096 pixels"},
155 {USD_TEXTURE_SIZE_CUSTOM, "CUSTOM", 0, "Custom", "Specify a custom size"},
156 {0, nullptr, 0, nullptr, nullptr},
157};
158
159const EnumPropertyItem rna_enum_usd_tex_export_mode_items[] = {
160 {USD_TEX_EXPORT_KEEP, "KEEP", 0, "Keep", "Use original location of textures"},
162 "PRESERVE",
163 0,
164 "Preserve",
165 "Preserve file paths of textures from already imported USD files.\n"
166 "Export remaining textures to a 'textures' folder next to the USD file"},
168 "NEW",
169 0,
170 "New Path",
171 "Export textures to a 'textures' folder next to the USD file"},
172 {0, nullptr, 0, nullptr, nullptr}};
173
174const EnumPropertyItem rna_enum_usd_mtl_purpose_items[] = {
176 "MTL_ALL_PURPOSE",
177 0,
178 "All Purpose",
179 "Attempt to import 'allPurpose' materials."},
181 "MTL_PREVIEW",
182 0,
183 "Preview",
184 "Attempt to import 'preview' materials. "
185 "Load 'allPurpose' materials as a fallback"},
187 "MTL_FULL",
188 0,
189 "Full",
190 "Attempt to import 'full' materials. "
191 "Load 'allPurpose' or 'preview' materials, in that order, as a fallback"},
192 {0, nullptr, 0, nullptr, nullptr},
193};
194
195const EnumPropertyItem rna_enum_usd_convert_scene_units_items[] = {
196 {USD_SCENE_UNITS_METERS, "METERS", 0, "Meters", "Scene meters per unit to 1.0"},
197 {USD_SCENE_UNITS_KILOMETERS, "KILOMETERS", 0, "Kilometers", "Scene meters per unit to 1000.0"},
199 "CENTIMETERS",
200 0,
201 "Centimeters",
202 "Scene meters per unit to 0.01"},
204 "MILLIMETERS",
205 0,
206 "Millimeters",
207 "Scene meters per unit to 0.001"},
208 {USD_SCENE_UNITS_INCHES, "INCHES", 0, "Inches", "Scene meters per unit to 0.0254"},
209 {USD_SCENE_UNITS_FEET, "FEET", 0, "Feet", "Scene meters per unit to 0.3048"},
210 {USD_SCENE_UNITS_YARDS, "YARDS", 0, "Yards", "Scene meters per unit to 0.9144"},
212 "CUSTOM",
213 0,
214 "Custom",
215 "Specify a custom scene meters per unit value"},
216 {0, nullptr, 0, nullptr, nullptr},
217};
218
219/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
220 * This is set when the operator is invoked, and not set when it is only executed. */
221struct USDOperatorOptions {
222 bool as_background_job;
223};
224
225static void free_operator_customdata(wmOperator *op)
226{
227 if (op->customdata) {
228 USDOperatorOptions *options = static_cast<USDOperatorOptions *>(op->customdata);
230 op->customdata = nullptr;
231 }
232}
233
234/* Ensure that the prim_path is not set to
235 * the absolute root path '/'. */
236static void process_prim_path(char *prim_path)
237{
238 if (prim_path == nullptr || prim_path[0] == '\0') {
239 return;
240 }
241
242 /* The absolute root "/" path indicates a no-op,
243 * so clear the string. */
244 if (prim_path[0] == '/' && prim_path[1] == '\0') {
245 prim_path[0] = '\0';
246 }
247
248 /* If a prim path doesn't start with a "/" it
249 * is invalid when creating the prim. */
250 if (prim_path[0] != '/') {
251 const std::string prim_path_copy = std::string(prim_path);
252 BLI_snprintf(prim_path, FILE_MAX, "/%s", prim_path_copy.c_str());
253 }
254}
255
256static wmOperatorStatus wm_usd_export_invoke(bContext *C,
257 wmOperator *op,
258 const wmEvent * /*event*/)
259{
260 USDOperatorOptions *options = MEM_callocN<USDOperatorOptions>("USDOperatorOptions");
261 options->as_background_job = true;
262 op->customdata = options;
263
265
267
269}
270
271static wmOperatorStatus wm_usd_export_exec(bContext *C, wmOperator *op)
272{
273 if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
274 BKE_report(op->reports, RPT_ERROR, "No filepath given");
275 free_operator_customdata(op);
276 return OPERATOR_CANCELLED;
277 }
278
279 char filepath[FILE_MAX];
280 RNA_string_get(op->ptr, "filepath", filepath);
281
282 USDOperatorOptions *options = static_cast<USDOperatorOptions *>(op->customdata);
283 const bool as_background_job = (options != nullptr && options->as_background_job);
284 free_operator_customdata(op);
285
286 const bool selected_objects_only = RNA_boolean_get(op->ptr, "selected_objects_only");
287 const bool visible_objects_only = RNA_boolean_get(op->ptr, "visible_objects_only");
288 const bool export_animation = RNA_boolean_get(op->ptr, "export_animation");
289 const bool export_hair = RNA_boolean_get(op->ptr, "export_hair");
290 const bool export_uvmaps = RNA_boolean_get(op->ptr, "export_uvmaps");
291 const bool rename_uvmaps = RNA_boolean_get(op->ptr, "rename_uvmaps");
292 const bool export_mesh_colors = RNA_boolean_get(op->ptr, "export_mesh_colors");
293 const bool export_normals = RNA_boolean_get(op->ptr, "export_normals");
294 const bool export_materials = RNA_boolean_get(op->ptr, "export_materials");
295 const eSubdivExportMode export_subdiv = eSubdivExportMode(
296 RNA_enum_get(op->ptr, "export_subdivision"));
297
298 const bool export_meshes = RNA_boolean_get(op->ptr, "export_meshes");
299 const bool export_lights = RNA_boolean_get(op->ptr, "export_lights");
300 const bool export_cameras = RNA_boolean_get(op->ptr, "export_cameras");
301 const bool export_curves = RNA_boolean_get(op->ptr, "export_curves");
302 const bool export_points = RNA_boolean_get(op->ptr, "export_points");
303 const bool export_volumes = RNA_boolean_get(op->ptr, "export_volumes");
304
305 const bool use_instancing = RNA_boolean_get(op->ptr, "use_instancing");
306 const bool evaluation_mode = RNA_enum_get(op->ptr, "evaluation_mode");
307
308 const bool generate_preview_surface = RNA_boolean_get(op->ptr, "generate_preview_surface");
309 const bool generate_materialx_network = RNA_boolean_get(op->ptr, "generate_materialx_network");
310 const bool overwrite_textures = RNA_boolean_get(op->ptr, "overwrite_textures");
311 const bool relative_paths = RNA_boolean_get(op->ptr, "relative_paths");
312
313 const bool export_armatures = RNA_boolean_get(op->ptr, "export_armatures");
314 const bool export_shapekeys = RNA_boolean_get(op->ptr, "export_shapekeys");
315 const bool only_deform_bones = RNA_boolean_get(op->ptr, "only_deform_bones");
316
317 const bool export_custom_properties = RNA_boolean_get(op->ptr, "export_custom_properties");
318 const bool author_blender_name = RNA_boolean_get(op->ptr, "author_blender_name");
319
320 const bool triangulate_meshes = RNA_boolean_get(op->ptr, "triangulate_meshes");
321 const int quad_method = RNA_enum_get(op->ptr, "quad_method");
322 const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
323
324 const bool convert_orientation = RNA_boolean_get(op->ptr, "convert_orientation");
325
326 const int global_forward = RNA_enum_get(op->ptr, "export_global_forward_selection");
327 const int global_up = RNA_enum_get(op->ptr, "export_global_up_selection");
328
329 const bool convert_world_material = RNA_boolean_get(op->ptr, "convert_world_material") &&
330 export_lights;
331
332 const eUSDXformOpMode xform_op_mode = eUSDXformOpMode(RNA_enum_get(op->ptr, "xform_op_mode"));
333
334 const eUSDZTextureDownscaleSize usdz_downscale_size = eUSDZTextureDownscaleSize(
335 RNA_enum_get(op->ptr, "usdz_downscale_size"));
336
337 const int usdz_downscale_custom_size = RNA_int_get(op->ptr, "usdz_downscale_custom_size");
338
339 const bool merge_parent_xform = RNA_boolean_get(op->ptr, "merge_parent_xform");
340
341 const bool allow_unicode = RNA_boolean_get(op->ptr, "allow_unicode");
342
343 /* When the texture export settings were moved into an enum this bit
344 * became more involved, but it needs to stick around for API backwards
345 * compatibility until Blender 5.0. */
346
347 const eUSDTexExportMode textures_mode = eUSDTexExportMode(
348 RNA_enum_get(op->ptr, "export_textures_mode"));
349 bool export_textures = RNA_boolean_get(op->ptr, "export_textures");
350 bool use_original_paths = false;
351
352 if (!export_textures) {
353 switch (textures_mode) {
355 export_textures = false;
356 use_original_paths = true;
357 break;
359 export_textures = true;
360 use_original_paths = false;
361 break;
362 default:
363 use_original_paths = false;
364 }
365 }
366
367 const eUSDSceneUnits convert_scene_units = eUSDSceneUnits(
368 RNA_enum_get(op->ptr, "convert_scene_units"));
369 const float meters_per_unit = RNA_float_get(op->ptr, "meters_per_unit");
370
371 char root_prim_path[FILE_MAX];
372 RNA_string_get(op->ptr, "root_prim_path", root_prim_path);
373 process_prim_path(root_prim_path);
374
375 char custom_properties_namespace[MAX_IDPROP_NAME];
376 RNA_string_get(op->ptr, "custom_properties_namespace", custom_properties_namespace);
377
379 params.export_animation = export_animation;
380 params.selected_objects_only = selected_objects_only;
381 params.visible_objects_only = visible_objects_only;
382
383 params.export_meshes = export_meshes;
384 params.export_lights = export_lights;
385 params.export_cameras = export_cameras;
386 params.export_curves = export_curves;
387 params.export_points = export_points;
388 params.export_volumes = export_volumes;
389 params.export_hair = export_hair;
390 params.export_uvmaps = export_uvmaps;
391 params.rename_uvmaps = rename_uvmaps;
392 params.export_normals = export_normals;
393 params.export_mesh_colors = export_mesh_colors;
394 params.export_materials = export_materials;
395
396 params.export_armatures = export_armatures;
397 params.export_shapekeys = export_shapekeys;
398 params.only_deform_bones = only_deform_bones;
399
400 params.convert_world_material = convert_world_material;
401
402 params.use_instancing = use_instancing;
403 params.export_custom_properties = export_custom_properties;
404 params.author_blender_name = author_blender_name;
405 params.allow_unicode = allow_unicode;
406
407 params.export_subdiv = export_subdiv;
408 params.evaluation_mode = eEvaluationMode(evaluation_mode);
409
410 params.generate_preview_surface = generate_preview_surface;
411 params.generate_materialx_network = generate_materialx_network;
412 params.export_textures = export_textures;
413 params.overwrite_textures = overwrite_textures;
414 params.relative_paths = relative_paths;
415 params.use_original_paths = use_original_paths;
416
417 params.triangulate_meshes = triangulate_meshes;
418 params.quad_method = quad_method;
419 params.ngon_method = ngon_method;
420
421 params.convert_orientation = convert_orientation;
422 params.forward_axis = eIOAxis(global_forward);
423 params.up_axis = eIOAxis(global_up);
424 params.xform_op_mode = xform_op_mode;
425
426 params.usdz_downscale_size = usdz_downscale_size;
427 params.usdz_downscale_custom_size = usdz_downscale_custom_size;
428 params.convert_scene_units = convert_scene_units;
429 params.custom_meters_per_unit = meters_per_unit;
430
431 params.merge_parent_xform = merge_parent_xform;
432
433 STRNCPY(params.root_prim_path, root_prim_path);
434 STRNCPY(params.custom_properties_namespace, custom_properties_namespace);
435 RNA_string_get(op->ptr, "collection", params.collection);
436
437 bool ok = USD_export(C, filepath, &params, as_background_job, op->reports);
438
439 return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
440}
441
442static void wm_usd_export_draw(bContext *C, wmOperator *op)
443{
444 uiLayout *layout = op->layout;
445 PointerRNA *ptr = op->ptr;
446
447 uiLayoutSetPropSep(layout, true);
448 uiLayoutSetPropDecorate(layout, false);
449
450 if (uiLayout *panel = layout->panel(C, "USD_export_general", false, IFACE_("General"))) {
451 uiLayout *col = &panel->column(false);
452 col->prop(ptr, "root_prim_path", UI_ITEM_NONE, std::nullopt, ICON_NONE);
453
454 uiLayout *sub = &col->column(true, IFACE_("Include"));
455 if (CTX_wm_space_file(C)) {
456 sub->prop(ptr, "selected_objects_only", UI_ITEM_NONE, std::nullopt, ICON_NONE);
457 sub->prop(ptr, "visible_objects_only", UI_ITEM_NONE, std::nullopt, ICON_NONE);
458 }
459 sub->prop(ptr, "export_animation", UI_ITEM_NONE, std::nullopt, ICON_NONE);
460
461 sub = &col->column(true, IFACE_("Blender Data"));
462 sub->prop(ptr, "export_custom_properties", UI_ITEM_NONE, std::nullopt, ICON_NONE);
463 uiLayout *props_col = &sub->column(true);
464 props_col->prop(ptr, "custom_properties_namespace", UI_ITEM_NONE, std::nullopt, ICON_NONE);
465 props_col->prop(ptr, "author_blender_name", UI_ITEM_NONE, std::nullopt, ICON_NONE);
466 uiLayoutSetActive(props_col, RNA_boolean_get(op->ptr, "export_custom_properties"));
467 sub->prop(ptr, "allow_unicode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
468
469 sub = &col->column(true, IFACE_("File References"));
470 sub->prop(ptr, "relative_paths", UI_ITEM_NONE, std::nullopt, ICON_NONE);
471
472 col = &panel->column(false);
473 col->prop(ptr, "convert_orientation", UI_ITEM_NONE, std::nullopt, ICON_NONE);
474 if (RNA_boolean_get(ptr, "convert_orientation")) {
475 col->prop(ptr, "export_global_forward_selection", UI_ITEM_NONE, std::nullopt, ICON_NONE);
476 col->prop(ptr, "export_global_up_selection", UI_ITEM_NONE, std::nullopt, ICON_NONE);
477 }
478
479 col->prop(ptr, "convert_scene_units", UI_ITEM_NONE, std::nullopt, ICON_NONE);
480 if (eUSDSceneUnits(RNA_enum_get(ptr, "convert_scene_units")) == USD_SCENE_UNITS_CUSTOM) {
481 col->prop(ptr, "meters_per_unit", UI_ITEM_NONE, std::nullopt, ICON_NONE);
482 }
483
484 col->prop(ptr, "xform_op_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
485
486 col = &panel->column(false);
487 col->prop(ptr, "evaluation_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
488 }
489
490 if (uiLayout *panel = layout->panel(C, "USD_export_types", false, IFACE_("Object Types"))) {
491 uiLayout *col = &panel->column(false);
492 col->prop(ptr, "export_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
493 col->prop(ptr, "export_lights", UI_ITEM_NONE, std::nullopt, ICON_NONE);
494
495 uiLayout *row = &col->row(true);
496 row->prop(ptr, "convert_world_material", UI_ITEM_NONE, std::nullopt, ICON_NONE);
497 const bool export_lights = RNA_boolean_get(ptr, "export_lights");
498 uiLayoutSetActive(row, export_lights);
499
500 col->prop(ptr, "export_cameras", UI_ITEM_NONE, std::nullopt, ICON_NONE);
501 col->prop(ptr, "export_curves", UI_ITEM_NONE, std::nullopt, ICON_NONE);
502 col->prop(ptr, "export_points", UI_ITEM_NONE, std::nullopt, ICON_NONE);
503 col->prop(ptr, "export_volumes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
504 col->prop(ptr, "export_hair", UI_ITEM_NONE, std::nullopt, ICON_NONE);
505 }
506
507 if (uiLayout *panel = layout->panel(C, "USD_export_geometry", false, IFACE_("Geometry"))) {
508 uiLayout *col = &panel->column(false);
509 col->prop(ptr, "export_uvmaps", UI_ITEM_NONE, std::nullopt, ICON_NONE);
510 col->prop(ptr, "rename_uvmaps", UI_ITEM_NONE, std::nullopt, ICON_NONE);
511 col->prop(ptr, "export_normals", UI_ITEM_NONE, std::nullopt, ICON_NONE);
512
513 col->prop(ptr, "merge_parent_xform", UI_ITEM_NONE, std::nullopt, ICON_NONE);
514 col->prop(ptr, "triangulate_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
515 if (RNA_boolean_get(ptr, "triangulate_meshes")) {
516 col->prop(ptr, "quad_method", UI_ITEM_NONE, IFACE_("Method Quads"), ICON_NONE);
517 col->prop(ptr, "ngon_method", UI_ITEM_NONE, IFACE_("Polygons"), ICON_NONE);
518 }
519
520 col->prop(ptr, "export_subdivision", UI_ITEM_NONE, std::nullopt, ICON_NONE);
521 }
522
523 if (uiLayout *panel = layout->panel(C, "USD_export_rigging", true, IFACE_("Rigging"))) {
524 uiLayout *col = &panel->column(false);
525
526 col->prop(ptr, "export_shapekeys", UI_ITEM_NONE, std::nullopt, ICON_NONE);
527 col->prop(ptr, "export_armatures", UI_ITEM_NONE, std::nullopt, ICON_NONE);
528
529 uiLayout *row = &col->row(true);
530 row->prop(ptr, "only_deform_bones", UI_ITEM_NONE, std::nullopt, ICON_NONE);
531 uiLayoutSetActive(row, RNA_boolean_get(ptr, "export_armatures"));
532 }
533
534 {
535 PanelLayout panel = layout->panel(C, "USD_export_materials", true);
536 uiLayoutSetPropSep(panel.header, false);
537 panel.header->prop(ptr, "export_materials", UI_ITEM_NONE, "", ICON_NONE);
538 panel.header->label(IFACE_("Materials"), ICON_NONE);
539 if (panel.body) {
540 const bool export_materials = RNA_boolean_get(ptr, "export_materials");
541 uiLayoutSetActive(panel.body, export_materials);
542
543 uiLayout *col = &panel.body->column(false);
544 col->prop(ptr, "generate_preview_surface", UI_ITEM_NONE, std::nullopt, ICON_NONE);
545 col->prop(ptr, "generate_materialx_network", UI_ITEM_NONE, std::nullopt, ICON_NONE);
546 col = &panel.body->column(true);
547 uiLayoutSetPropSep(col, true);
548
549 col->prop(ptr, "export_textures_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
550
551 const eUSDTexExportMode textures_mode = eUSDTexExportMode(
552 RNA_enum_get(op->ptr, "export_textures_mode"));
553
554 uiLayout *col2 = &col->column(true);
555 uiLayoutSetPropSep(col2, true);
556 uiLayoutSetEnabled(col2, textures_mode == USD_TEX_EXPORT_NEW_PATH);
557 col2->prop(ptr, "overwrite_textures", UI_ITEM_NONE, std::nullopt, ICON_NONE);
558 col2->prop(ptr, "usdz_downscale_size", UI_ITEM_NONE, std::nullopt, ICON_NONE);
559 if (RNA_enum_get(ptr, "usdz_downscale_size") == USD_TEXTURE_SIZE_CUSTOM) {
560 col2->prop(ptr, "usdz_downscale_custom_size", UI_ITEM_NONE, std::nullopt, ICON_NONE);
561 }
562 }
563 }
564
565 if (uiLayout *panel = layout->panel(C, "USD_export_experimental", true, IFACE_("Experimental")))
566 {
567 uiLayout *col = &panel->column(false);
568 col->prop(ptr, "use_instancing", UI_ITEM_NONE, std::nullopt, ICON_NONE);
569 }
570}
571
572static void wm_usd_export_cancel(bContext * /*C*/, wmOperator *op)
573{
574 free_operator_customdata(op);
575}
576
577static bool wm_usd_export_check(bContext * /*C*/, wmOperator *op)
578{
579 char filepath[FILE_MAX];
580 RNA_string_get(op->ptr, "filepath", filepath);
581
582 if (!BLI_path_extension_check_n(filepath, ".usd", ".usda", ".usdc", ".usdz", nullptr)) {
583 BLI_path_extension_ensure(filepath, FILE_MAX, ".usdc");
584 RNA_string_set(op->ptr, "filepath", filepath);
585 return true;
586 }
587
588 return false;
589}
590
591static void forward_axis_update(Main * /*main*/, Scene * /*scene*/, PointerRNA *ptr)
592{
593 int forward = RNA_enum_get(ptr, "export_global_forward_selection");
594 int up = RNA_enum_get(ptr, "export_global_up_selection");
595 if ((forward % 3) == (up % 3)) {
596 RNA_enum_set(ptr, "export_global_up_selection", (up + 1) % 6);
597 }
598}
599
600static void up_axis_update(Main * /*main*/, Scene * /*scene*/, PointerRNA *ptr)
601{
602 int forward = RNA_enum_get(ptr, "export_global_forward_selection");
603 int up = RNA_enum_get(ptr, "export_global_up_selection");
604 if ((forward % 3) == (up % 3)) {
605 RNA_enum_set(ptr, "export_global_forward_selection", (forward + 1) % 6);
606 }
607}
608
610{
611 ot->name = "Export USD";
612 ot->description = "Export current scene in a USD archive";
613 ot->idname = "WM_OT_usd_export";
614
615 ot->invoke = wm_usd_export_invoke;
616 ot->exec = wm_usd_export_exec;
618 ot->ui = wm_usd_export_draw;
619 ot->cancel = wm_usd_export_cancel;
620 ot->check = wm_usd_export_check;
621
622 ot->flag = OPTYPE_REGISTER | OPTYPE_PRESET; /* No UNDO possible. */
623
627 FILE_SAVE,
631
632 PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.usd", 0, "", "");
634
635 RNA_def_boolean(ot->srna,
636 "selected_objects_only",
637 false,
638 "Selection Only",
639 "Only export selected objects. Unselected parents of selected objects are "
640 "exported as empty transform");
641
642 RNA_def_boolean(ot->srna,
643 "visible_objects_only",
644 true,
645 "Visible Only",
646 "Only export visible objects. Invisible parents of exported objects are "
647 "exported as empty transforms");
648
649 prop = RNA_def_string(ot->srna, "collection", nullptr, MAX_IDPROP_NAME, "Collection", nullptr);
651
653 ot->srna,
654 "export_animation",
655 false,
656 "Animation",
657 "Export all frames in the render frame range, rather than only the current frame");
659 ot->srna, "export_hair", false, "Hair", "Export hair particle systems as USD curves");
661 ot->srna, "export_uvmaps", true, "UV Maps", "Include all mesh UV maps in the export");
662 RNA_def_boolean(ot->srna,
663 "rename_uvmaps",
664 true,
665 "Rename UV Maps",
666 "Rename active render UV map to \"st\" to match USD conventions");
667 RNA_def_boolean(ot->srna,
668 "export_mesh_colors",
669 true,
670 "Color Attributes",
671 "Include mesh color attributes in the export");
672 RNA_def_boolean(ot->srna,
673 "export_normals",
674 true,
675 "Normals",
676 "Include normals of exported meshes in the export");
677 RNA_def_boolean(ot->srna,
678 "export_materials",
679 true,
680 "Materials",
681 "Export viewport settings of materials as USD preview materials, and export "
682 "material assignments as geometry subsets");
683
684 RNA_def_enum(ot->srna,
685 "export_subdivision",
686 rna_enum_usd_export_subdiv_mode_items,
688 "Subdivision",
689 "Choose how subdivision modifiers will be mapped to the USD subdivision scheme "
690 "during export");
691
692 RNA_def_boolean(ot->srna,
693 "export_armatures",
694 true,
695 "Armatures",
696 "Export armatures and meshes with armature modifiers as USD skeletons and "
697 "skinned meshes");
698
699 RNA_def_boolean(ot->srna,
700 "only_deform_bones",
701 false,
702 "Only Deform Bones",
703 "Only export deform bones and their parents");
704
706 ot->srna, "export_shapekeys", true, "Shape Keys", "Export shape keys as USD blend shapes");
707
708 RNA_def_boolean(ot->srna,
709 "use_instancing",
710 false,
711 "Instancing",
712 "Export instanced objects as references in USD rather than real objects");
713
714 RNA_def_enum(ot->srna,
715 "evaluation_mode",
716 rna_enum_usd_export_evaluation_mode_items,
718 "Use Settings for",
719 "Determines visibility of objects, modifier settings, and other areas where there "
720 "are different settings for viewport and rendering");
721
722 RNA_def_boolean(ot->srna,
723 "generate_preview_surface",
724 true,
725 "USD Preview Surface Network",
726 "Generate an approximate USD Preview Surface shader "
727 "representation of a Principled BSDF node network");
728
729 RNA_def_boolean(ot->srna,
730 "generate_materialx_network",
731 false,
732 "MaterialX Network",
733 "Generate a MaterialX network representation of the materials");
734
736 ot->srna,
737 "convert_orientation",
738 false,
739 "Convert Orientation",
740 "Convert orientation axis to a different convention to match other applications");
741
742 prop = RNA_def_enum(ot->srna,
743 "export_global_forward_selection",
746 "Forward Axis",
747 "");
748 RNA_def_property_update_runtime(prop, forward_axis_update);
749
750 prop = RNA_def_enum(
751 ot->srna, "export_global_up_selection", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
752 RNA_def_property_update_runtime(prop, up_axis_update);
753
754 RNA_def_boolean(ot->srna,
755 "export_textures",
756 false,
757 "Export Textures",
758 "If exporting materials, export textures referenced by material nodes "
759 "to a 'textures' directory in the same directory as the USD file");
760
761 RNA_def_enum(ot->srna,
762 "export_textures_mode",
763 rna_enum_usd_tex_export_mode_items,
765 "Export Textures",
766 "Texture export method");
767
768 RNA_def_boolean(ot->srna,
769 "overwrite_textures",
770 false,
771 "Overwrite Textures",
772 "Overwrite existing files when exporting textures");
773
774 RNA_def_boolean(ot->srna,
775 "relative_paths",
776 true,
777 "Relative Paths",
778 "Use relative paths to reference external files (i.e. textures, volumes) in "
779 "USD, otherwise use absolute paths");
780
781 RNA_def_enum(ot->srna,
782 "xform_op_mode",
783 rna_enum_usd_xform_op_mode_items,
785 "Xform Ops",
786 "The type of transform operators to write");
787
788 RNA_def_string(ot->srna,
789 "root_prim_path",
790 "/root",
791 FILE_MAX,
792 "Root Prim",
793 "If set, add a transform primitive with the given path to the stage "
794 "as the parent of all exported data");
795
796 RNA_def_boolean(ot->srna,
797 "export_custom_properties",
798 true,
799 "Custom Properties",
800 "Export custom properties as USD attributes");
801
802 RNA_def_string(ot->srna,
803 "custom_properties_namespace",
804 "userProperties",
806 "Namespace",
807 "If set, add the given namespace as a prefix to exported custom property names. "
808 "This only applies to property names that do not already have a prefix "
809 "(e.g., it would apply to name 'bar' but not 'foo:bar') and does not apply "
810 "to blender object and data names which are always exported in the "
811 "'userProperties:blender' namespace");
812
813 RNA_def_boolean(ot->srna,
814 "author_blender_name",
815 true,
816 "Blender Names",
817 "Author USD custom attributes containing the original Blender object and "
818 "object data names");
819
821 ot->srna,
822 "convert_world_material",
823 true,
824 "World Dome Light",
825 "Convert the world material to a USD dome light. "
826 "Currently works for simple materials, consisting of an environment texture "
827 "connected to a background shader, with an optional vector multiply of the texture color");
828
830 ot->srna,
831 "allow_unicode",
832 false,
833 "Allow Unicode",
834 "Preserve UTF-8 encoded characters when writing USD prim and property names "
835 "(requires software utilizing USD 24.03 or greater when opening the resulting files)");
836
837 RNA_def_boolean(ot->srna, "export_meshes", true, "Meshes", "Export all meshes");
838
839 RNA_def_boolean(ot->srna, "export_lights", true, "Lights", "Export all lights");
840
841 RNA_def_boolean(ot->srna, "export_cameras", true, "Cameras", "Export all cameras");
842
843 RNA_def_boolean(ot->srna, "export_curves", true, "Curves", "Export all curves");
844
845 RNA_def_boolean(ot->srna, "export_points", true, "Point Clouds", "Export all point clouds");
846
847 RNA_def_boolean(ot->srna, "export_volumes", true, "Volumes", "Export all volumes");
848
849 RNA_def_boolean(ot->srna,
850 "triangulate_meshes",
851 false,
852 "Triangulate Meshes",
853 "Triangulate meshes during export");
854
855 RNA_def_enum(ot->srna,
856 "quad_method",
859 "Quad Method",
860 "Method for splitting the quads into triangles");
861
862 RNA_def_enum(ot->srna,
863 "ngon_method",
866 "N-gon Method",
867 "Method for splitting the n-gons into triangles");
868
869 RNA_def_enum(ot->srna,
870 "usdz_downscale_size",
871 rna_enum_usdz_downscale_size,
873 "USDZ Texture Downsampling",
874 "Choose a maximum size for all exported textures");
875
876 RNA_def_int(ot->srna,
877 "usdz_downscale_custom_size",
878 128,
879 64,
880 16384,
881 "USDZ Custom Downscale Size",
882 "Custom size for downscaling exported textures",
883 128,
884 8192);
885
886 RNA_def_boolean(ot->srna,
887 "merge_parent_xform",
888 false,
889 "Merge parent Xform",
890 "Merge USD primitives with their Xform parent if possible. USD does not allow "
891 "nested UsdGeomGprims, intermediary Xform prims will be defined to keep the USD "
892 "file valid when encountering object hierarchies.");
893
894 RNA_def_enum(ot->srna,
895 "convert_scene_units",
896 rna_enum_usd_convert_scene_units_items,
898 "Units",
899 "Set the USD Stage meters per unit to the chosen measurement, or a custom value");
900
901 RNA_def_float(ot->srna,
902 "meters_per_unit",
903 1.0f,
904 0.0001f,
905 1000.0f,
906 "Meters Per Unit",
907 "Custom value for meters per unit in the USD Stage",
908 0.0001f,
909 1000.0f);
910}
911
912/* ====== USD Import ====== */
913
914static wmOperatorStatus wm_usd_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
915{
916 USDOperatorOptions *options = MEM_callocN<USDOperatorOptions>("USDOperatorOptions");
917 options->as_background_job = true;
918 op->customdata = options;
919
921}
922
923static wmOperatorStatus wm_usd_import_exec(bContext *C, wmOperator *op)
924{
925 if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
926 BKE_report(op->reports, RPT_ERROR, "No filepath given");
927 free_operator_customdata(op);
928 return OPERATOR_CANCELLED;
929 }
930
931 char filepath[FILE_MAX];
932 RNA_string_get(op->ptr, "filepath", filepath);
933
934 USDOperatorOptions *options = static_cast<USDOperatorOptions *>(op->customdata);
935 const bool as_background_job = (options != nullptr && options->as_background_job);
936 free_operator_customdata(op);
937
938 const float scale = RNA_float_get(op->ptr, "scale");
939 const float light_intensity_scale = RNA_float_get(op->ptr, "light_intensity_scale");
940 const bool apply_unit_conversion_scale = RNA_boolean_get(op->ptr, "apply_unit_conversion_scale");
941
942 const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
943
944 const bool read_mesh_uvs = RNA_boolean_get(op->ptr, "read_mesh_uvs");
945 const bool read_mesh_colors = RNA_boolean_get(op->ptr, "read_mesh_colors");
946 const bool read_mesh_attributes = RNA_boolean_get(op->ptr, "read_mesh_attributes");
947
948 char mesh_read_flag = MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY;
949 if (read_mesh_uvs) {
950 mesh_read_flag |= MOD_MESHSEQ_READ_UV;
951 }
952 if (read_mesh_colors) {
953 mesh_read_flag |= MOD_MESHSEQ_READ_COLOR;
954 }
955 if (read_mesh_attributes) {
956 mesh_read_flag |= MOD_MESHSEQ_READ_ATTRIBUTES;
957 }
958
959 const bool import_cameras = RNA_boolean_get(op->ptr, "import_cameras");
960 const bool import_curves = RNA_boolean_get(op->ptr, "import_curves");
961 const bool import_lights = RNA_boolean_get(op->ptr, "import_lights");
962 const bool import_materials = RNA_boolean_get(op->ptr, "import_materials");
963 const bool import_meshes = RNA_boolean_get(op->ptr, "import_meshes");
964 const bool import_volumes = RNA_boolean_get(op->ptr, "import_volumes");
965 const bool import_shapes = RNA_boolean_get(op->ptr, "import_shapes");
966 const bool import_skeletons = RNA_boolean_get(op->ptr, "import_skeletons");
967 const bool import_blendshapes = RNA_boolean_get(op->ptr, "import_blendshapes");
968 const bool import_points = RNA_boolean_get(op->ptr, "import_points");
969
970 const bool import_subdiv = RNA_boolean_get(op->ptr, "import_subdiv");
971
972 const bool support_scene_instancing = RNA_boolean_get(op->ptr, "support_scene_instancing");
973
974 const bool import_visible_only = RNA_boolean_get(op->ptr, "import_visible_only");
975
976 const bool import_defined_only = RNA_boolean_get(op->ptr, "import_defined_only");
977
978 const bool create_collection = RNA_boolean_get(op->ptr, "create_collection");
979
980 char *prim_path_mask = RNA_string_get_alloc(op->ptr, "prim_path_mask", nullptr, 0, nullptr);
981
982 const bool import_guide = RNA_boolean_get(op->ptr, "import_guide");
983 const bool import_proxy = RNA_boolean_get(op->ptr, "import_proxy");
984 const bool import_render = RNA_boolean_get(op->ptr, "import_render");
985
986 const bool import_all_materials = RNA_boolean_get(op->ptr, "import_all_materials");
987
988 const bool import_usd_preview = RNA_boolean_get(op->ptr, "import_usd_preview");
989 const bool set_material_blend = RNA_boolean_get(op->ptr, "set_material_blend");
990
991 const eUSDMtlPurpose mtl_purpose = eUSDMtlPurpose(RNA_enum_get(op->ptr, "mtl_purpose"));
992 const eUSDMtlNameCollisionMode mtl_name_collision_mode = eUSDMtlNameCollisionMode(
993 RNA_enum_get(op->ptr, "mtl_name_collision_mode"));
994
995 const eUSDAttrImportMode attr_import_mode = eUSDAttrImportMode(
996 RNA_enum_get(op->ptr, "attr_import_mode"));
997
998 const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
999
1000 const bool create_world_material = RNA_boolean_get(op->ptr, "create_world_material") &&
1001 import_lights;
1002
1003 const bool merge_parent_xform = RNA_boolean_get(op->ptr, "merge_parent_xform");
1004
1005 /* TODO(makowalski): Add support for sequences. */
1006 const bool is_sequence = false;
1007 int offset = 0;
1008 int sequence_len = 1;
1009
1010 const eUSDTexImportMode import_textures_mode = eUSDTexImportMode(
1011 RNA_enum_get(op->ptr, "import_textures_mode"));
1012
1013 char import_textures_dir[FILE_MAXDIR];
1014 RNA_string_get(op->ptr, "import_textures_dir", import_textures_dir);
1015
1016 const eUSDTexNameCollisionMode tex_name_collision_mode = eUSDTexNameCollisionMode(
1017 RNA_enum_get(op->ptr, "tex_name_collision_mode"));
1018
1020 params.prim_path_mask = prim_path_mask;
1021 params.scale = scale;
1022 params.light_intensity_scale = light_intensity_scale;
1023 params.apply_unit_conversion_scale = apply_unit_conversion_scale;
1024
1025 params.mesh_read_flag = mesh_read_flag;
1026 params.set_frame_range = set_frame_range;
1027 params.is_sequence = is_sequence;
1028 params.sequence_len = sequence_len;
1029 params.offset = offset;
1030 params.relative_path = RNA_boolean_get(op->ptr, "relative_path");
1031
1032 params.import_visible_only = import_visible_only;
1033 params.import_defined_only = import_defined_only;
1034
1035 params.import_cameras = import_cameras;
1036 params.import_curves = import_curves;
1037 params.import_lights = import_lights;
1038 params.import_materials = import_materials;
1039 params.import_all_materials = import_all_materials;
1040 params.import_meshes = import_meshes;
1041 params.import_points = import_points;
1042 params.import_subdiv = import_subdiv;
1043 params.import_volumes = import_volumes;
1044
1045 params.create_collection = create_collection;
1046 params.create_world_material = create_world_material;
1047 params.support_scene_instancing = support_scene_instancing;
1048
1049 params.import_shapes = import_shapes;
1050 params.import_skeletons = import_skeletons;
1051 params.import_blendshapes = import_blendshapes;
1052
1053 params.validate_meshes = validate_meshes;
1054 params.merge_parent_xform = merge_parent_xform;
1055
1056 params.import_guide = import_guide;
1057 params.import_proxy = import_proxy;
1058 params.import_render = import_render;
1059
1060 params.import_usd_preview = import_usd_preview;
1061 params.set_material_blend = set_material_blend;
1062 params.mtl_purpose = mtl_purpose;
1063 params.mtl_name_collision_mode = mtl_name_collision_mode;
1064 params.import_textures_mode = import_textures_mode;
1065 params.tex_name_collision_mode = tex_name_collision_mode;
1066
1067 params.attr_import_mode = attr_import_mode;
1068
1069 STRNCPY(params.import_textures_dir, import_textures_dir);
1070
1071 /* Switch out of edit mode to avoid being stuck in it (#54326). */
1072 Object *obedit = CTX_data_edit_object(C);
1073 if (obedit) {
1075 }
1076
1077 const bool ok = USD_import(C, filepath, &params, as_background_job, op->reports);
1078
1079 return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1080}
1081
1082static void wm_usd_import_cancel(bContext * /*C*/, wmOperator *op)
1083{
1084 free_operator_customdata(op);
1085}
1086
1087static void wm_usd_import_draw(bContext *C, wmOperator *op)
1088{
1089 uiLayout *layout = op->layout;
1090 PointerRNA *ptr = op->ptr;
1091
1092 uiLayoutSetPropSep(layout, true);
1093 uiLayoutSetPropDecorate(layout, false);
1094
1095 if (uiLayout *panel = layout->panel(C, "USD_import_general", false, IFACE_("General"))) {
1096 uiLayout *col = &panel->column(false);
1097
1098 col->prop(ptr, "prim_path_mask", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1099
1100 uiLayout *sub = &col->column(true, IFACE_("Include"));
1101 sub->prop(ptr, "import_visible_only", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1102 sub->prop(ptr, "import_defined_only", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1103
1104 col = &panel->column(false);
1105 col->prop(ptr, "set_frame_range", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1106 col->prop(ptr, "create_collection", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1107 col->prop(ptr, "relative_path", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1108
1109 col->prop(ptr, "apply_unit_conversion_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1110 col->prop(ptr, "scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1111 col->prop(ptr, "light_intensity_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1112 col->prop(ptr, "attr_import_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1113 }
1114
1115 if (uiLayout *panel = layout->panel(C, "USD_import_types", false, IFACE_("Object Types"))) {
1116 uiLayout *col = &panel->column(false);
1117 col->prop(ptr, "import_cameras", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1118 col->prop(ptr, "import_curves", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1119 col->prop(ptr, "import_lights", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1120
1121 uiLayout *row = &col->row(true);
1122 row->prop(ptr, "create_world_material", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1123 const bool import_lights = RNA_boolean_get(ptr, "import_lights");
1124 uiLayoutSetActive(row, import_lights);
1125
1126 col->prop(ptr, "import_materials", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1127 col->prop(ptr, "import_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1128 col->prop(ptr, "import_volumes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1129 col->prop(ptr, "import_points", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1130 col->prop(ptr, "import_shapes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1131
1132 col = &panel->column(true, IFACE_("Display Purpose"));
1133 col->prop(ptr, "import_render", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1134 col->prop(ptr, "import_proxy", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1135 col->prop(ptr, "import_guide", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1136
1137 col = &panel->column(true, IFACE_("Material Purpose"));
1138 col->prop(ptr, "mtl_purpose", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1139 }
1140
1141 if (uiLayout *panel = layout->panel(C, "USD_import_geometry", true, IFACE_("Geometry"))) {
1142 uiLayout *col = &panel->column(false);
1143 col->prop(ptr, "read_mesh_uvs", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1144 col->prop(ptr, "read_mesh_colors", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1145 col->prop(ptr, "read_mesh_attributes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1146 col->prop(ptr, "import_subdiv", UI_ITEM_NONE, IFACE_("Subdivision"), ICON_NONE);
1147
1148 col = &panel->column(false);
1149 col->prop(ptr, "validate_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1150 col->prop(ptr, "merge_parent_xform", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1151 }
1152
1153 if (uiLayout *panel = layout->panel(C, "USD_import_rigging", true, IFACE_("Rigging"))) {
1154 uiLayout *col = &panel->column(false);
1155 col->prop(ptr, "import_blendshapes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1156 col->prop(ptr, "import_skeletons", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1157 }
1158
1159 if (uiLayout *panel = layout->panel(C, "USD_import_material", true, IFACE_("Materials"))) {
1160 uiLayout *col = &panel->column(false);
1161
1162 col->prop(ptr, "import_all_materials", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1163 col->prop(ptr, "import_usd_preview", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1164 uiLayoutSetEnabled(col, RNA_boolean_get(ptr, "import_materials"));
1165
1166 uiLayout *row = &col->row(true);
1167 row->prop(ptr, "set_material_blend", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1168 uiLayoutSetEnabled(row, RNA_boolean_get(ptr, "import_usd_preview"));
1169 col->prop(ptr, "mtl_name_collision_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1170 }
1171
1172 if (uiLayout *panel = layout->panel(C, "USD_import_texture", true, IFACE_("Textures"))) {
1173 uiLayout *col = &panel->column(false);
1174
1175 col->prop(ptr, "import_textures_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1176 bool copy_textures = RNA_enum_get(op->ptr, "import_textures_mode") == USD_TEX_IMPORT_COPY;
1177
1178 uiLayout *row = &col->row(true);
1179 row->prop(ptr, "import_textures_dir", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1180 uiLayoutSetEnabled(row, copy_textures);
1181 row = &col->row(true);
1182 row->prop(ptr, "tex_name_collision_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1183 uiLayoutSetEnabled(row, copy_textures);
1184 uiLayoutSetEnabled(col, RNA_boolean_get(ptr, "import_materials"));
1185 }
1186
1187 if (uiLayout *panel = layout->panel(
1188 C, "USD_import_instancing", true, IFACE_("Particles and Instancing")))
1189 {
1190 uiLayout *col = &panel->column(false);
1191 col->prop(ptr, "support_scene_instancing", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1192 }
1193}
1194
1196{
1197 ot->name = "Import USD";
1198 ot->description = "Import USD stage into current scene";
1199 ot->idname = "WM_OT_usd_import";
1200
1201 ot->invoke = wm_usd_import_invoke;
1202 ot->exec = wm_usd_import_exec;
1203 ot->cancel = wm_usd_import_cancel;
1204 ot->poll = WM_operator_winactive;
1205 ot->ui = wm_usd_import_draw;
1206
1207 ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
1208
1216
1217 PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.usd", 0, "", "");
1219
1221 ot->srna,
1222 "scale",
1223 1.0f,
1224 0.0001f,
1225 1000.0f,
1226 "Scale",
1227 "Value by which to enlarge or shrink the objects with respect to the world's origin",
1228 0.0001f,
1229 1000.0f);
1230
1231 RNA_def_boolean(ot->srna,
1232 "set_frame_range",
1233 true,
1234 "Set Frame Range",
1235 "Update the scene's start and end frame to match those of the USD archive");
1236
1237 RNA_def_boolean(ot->srna, "import_cameras", true, "Cameras", "");
1238 RNA_def_boolean(ot->srna, "import_curves", true, "Curves", "");
1239 RNA_def_boolean(ot->srna, "import_lights", true, "Lights", "");
1240 RNA_def_boolean(ot->srna, "import_materials", true, "Materials", "");
1241 RNA_def_boolean(ot->srna, "import_meshes", true, "Meshes", "");
1242 RNA_def_boolean(ot->srna, "import_volumes", true, "Volumes", "");
1243 RNA_def_boolean(ot->srna, "import_shapes", true, "USD Shapes", "");
1244 RNA_def_boolean(ot->srna, "import_skeletons", true, "Armatures", "");
1245 RNA_def_boolean(ot->srna, "import_blendshapes", true, "Shape Keys", "");
1246 RNA_def_boolean(ot->srna, "import_points", true, "Point Clouds", "");
1247
1248 RNA_def_boolean(ot->srna,
1249 "import_subdiv",
1250 false,
1251 "Import Subdivision Scheme",
1252 "Create subdivision surface modifiers based on the USD "
1253 "SubdivisionScheme attribute");
1254
1255 RNA_def_boolean(ot->srna,
1256 "support_scene_instancing",
1257 true,
1258 "Scene Instancing",
1259 "Import USD scene graph instances as collection instances");
1260
1261 RNA_def_boolean(ot->srna,
1262 "import_visible_only",
1263 true,
1264 "Visible Primitives Only",
1265 "Do not import invisible USD primitives. "
1266 "Only applies to primitives with a non-animated visibility attribute. "
1267 "Primitives with animated visibility will always be imported");
1268
1269 RNA_def_boolean(ot->srna,
1270 "create_collection",
1271 false,
1272 "Create Collection",
1273 "Add all imported objects to a new collection");
1274
1275 RNA_def_boolean(ot->srna, "read_mesh_uvs", true, "UV Coordinates", "Read mesh UV coordinates");
1276
1278 ot->srna, "read_mesh_colors", true, "Color Attributes", "Read mesh color attributes");
1279
1280 RNA_def_boolean(ot->srna,
1281 "read_mesh_attributes",
1282 true,
1283 "Mesh Attributes",
1284 "Read USD Primvars as mesh attributes");
1285
1286 RNA_def_string(ot->srna,
1287 "prim_path_mask",
1288 nullptr,
1289 0,
1290 "Path Mask",
1291 "Import only the primitive at the given path and its descendants. "
1292 "Multiple paths may be specified in a list delimited by commas or semicolons");
1293
1294 RNA_def_boolean(ot->srna, "import_guide", false, "Guide", "Import guide geometry");
1295
1296 RNA_def_boolean(ot->srna, "import_proxy", false, "Proxy", "Import proxy geometry");
1297
1298 RNA_def_boolean(ot->srna, "import_render", true, "Render", "Import final render geometry");
1299
1300 RNA_def_boolean(ot->srna,
1301 "import_all_materials",
1302 false,
1303 "Import All Materials",
1304 "Also import materials that are not used by any geometry. "
1305 "Note that when this option is false, materials referenced "
1306 "by geometry will still be imported");
1307
1308 RNA_def_boolean(ot->srna,
1309 "import_usd_preview",
1310 true,
1311 "Import USD Preview",
1312 "Convert UsdPreviewSurface shaders to Principled BSDF shader networks");
1313
1314 RNA_def_boolean(ot->srna,
1315 "set_material_blend",
1316 true,
1317 "Set Material Blend",
1318 "If the Import USD Preview option is enabled, "
1319 "the material blend method will automatically be set based on the "
1320 "shader's opacity and opacityThreshold inputs");
1321
1322 RNA_def_float(ot->srna,
1323 "light_intensity_scale",
1324 1.0f,
1325 0.0001f,
1326 10000.0f,
1327 "Light Intensity Scale",
1328 "Scale for the intensity of imported lights",
1329 0.0001f,
1330 1000.0f);
1331
1332 RNA_def_enum(ot->srna,
1333 "mtl_purpose",
1334 rna_enum_usd_mtl_purpose_items,
1336 "Material Purpose",
1337 "Attempt to import materials with the given purpose. "
1338 "If no material with this purpose is bound to the primitive, "
1339 "fall back on loading any other bound material");
1340
1342 ot->srna,
1343 "mtl_name_collision_mode",
1344 rna_enum_usd_mtl_name_collision_mode_items,
1346 "Material Name Collision",
1347 "Behavior when the name of an imported material conflicts with an existing material");
1348
1349 RNA_def_enum(ot->srna,
1350 "import_textures_mode",
1351 rna_enum_usd_tex_import_mode_items,
1353 "Import Textures",
1354 "Behavior when importing textures from a USDZ archive");
1355
1356 RNA_def_string(ot->srna,
1357 "import_textures_dir",
1358 "//textures/",
1360 "Textures Directory",
1361 "Path to the directory where imported textures will be copied");
1362
1364 ot->srna,
1365 "tex_name_collision_mode",
1366 rna_enum_usd_tex_name_collision_mode_items,
1368 "File Name Collision",
1369 "Behavior when the name of an imported texture file conflicts with an existing file");
1370
1371 RNA_def_enum(ot->srna,
1372 "attr_import_mode",
1373 rna_enum_usd_attr_import_mode_items,
1375 "Custom Properties",
1376 "Behavior when importing USD attributes as Blender custom properties");
1377
1379 ot->srna,
1380 "validate_meshes",
1381 false,
1382 "Validate Meshes",
1383 "Ensure the data is valid "
1384 "(when disabled, data may be imported which causes crashes displaying or editing)");
1385
1386 RNA_def_boolean(ot->srna,
1387 "create_world_material",
1388 true,
1389 "World Dome Light",
1390 "Convert the first discovered USD dome light to a world background shader");
1391
1392 RNA_def_boolean(ot->srna,
1393 "import_defined_only",
1394 true,
1395 "Defined Primitives Only",
1396 "Import only defined USD primitives. When disabled this allows importing USD "
1397 "primitives which are not defined, such as those with an override specifier");
1398
1399 RNA_def_boolean(ot->srna,
1400 "merge_parent_xform",
1401 true,
1402 "Merge parent Xform",
1403 "Allow USD primitives to merge with their Xform parent "
1404 "if they are the only child in the hierarchy");
1405
1407 ot->srna,
1408 "apply_unit_conversion_scale",
1409 true,
1410 "Apply Unit Conversion Scale",
1411 "Scale the scene objects by the USD stage's meters per unit value. "
1412 "This scaling is applied in addition to the value specified in the Scale option");
1413}
1414
1415namespace blender::ed::io {
1417{
1418 auto fh = std::make_unique<blender::bke::FileHandlerType>();
1419 STRNCPY(fh->idname, "IO_FH_usd");
1420 STRNCPY(fh->import_operator, "WM_OT_usd_import");
1421 STRNCPY(fh->export_operator, "WM_OT_usd_export");
1422 STRNCPY(fh->label, "Universal Scene Description");
1423 STRNCPY(fh->file_extensions_str, ".usd;.usda;.usdc;.usdz");
1424 fh->poll_drop = poll_file_object_drop;
1425 bke::file_handler_add(std::move(fh));
1426}
1427} // namespace blender::ed::io
1428
1429#endif /* WITH_USD */
SpaceFile * CTX_wm_space_file(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define FILE_MAX
bool BLI_path_extension_ensure(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
bool BLI_path_extension_check_n(const char *path,...) ATTR_NONNULL(1) ATTR_SENTINEL(0)
#define FILE_MAXDIR
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define IFACE_(msgid)
eEvaluationMode
@ DAG_EVAL_RENDER
@ DAG_EVAL_VIEWPORT
@ MOD_TRIANGULATE_NGON_BEAUTY
@ MOD_MESHSEQ_READ_COLOR
@ MOD_MESHSEQ_READ_VERT
@ MOD_MESHSEQ_READ_ATTRIBUTES
@ MOD_MESHSEQ_READ_UV
@ MOD_MESHSEQ_READ_POLY
@ MOD_TRIANGULATE_QUAD_SHORTEDGE
@ OB_MODE_EDIT
@ FILE_SORT_DEFAULT
@ FILE_BLENDER
@ FILE_TYPE_FOLDER
@ FILE_TYPE_USD
@ FILE_DEFAULTDISPLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void ED_fileselect_ensure_default_filepath(bContext *C, wmOperator *op, const char *extension)
Definition filesel.cc:1490
eIOAxis
@ IO_AXIS_Y
@ IO_AXIS_NEGATIVE_Z
Read Guarded memory(de)allocation.
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1072
@ WM_FILESEL_SHOW_PROPS
Definition WM_api.hh:1078
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1075
@ FILE_OPENFILE
Definition WM_api.hh:1084
@ FILE_SAVE
Definition WM_api.hh:1085
@ OPTYPE_PRESET
Definition WM_types.hh:195
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
static void set_frame_range(ImportJobData *data)
CCL_NAMESPACE_BEGIN struct Options options
uint col
#define MAX_IDPROP_NAME
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void WM_OT_usd_import(wmOperatorType *ot)
void WM_OT_usd_export(wmOperatorType *ot)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void file_handler_add(std::unique_ptr< FileHandlerType > file_handler)
bool poll_file_object_drop(const bContext *C, blender::bke::FileHandlerType *)
Definition io_utils.cc:58
wmOperatorStatus filesel_drop_import_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition io_utils.cc:26
void usd_file_handler_add()
bool mode_set(bContext *C, eObjectMode mode)
void import_meshes(Main &bmain, const ufbx_scene &fbx, FbxElementMapping &mapping, const FBXImportParams &params)
@ USD_TEX_IMPORT_NONE
Definition usd.hh:65
@ USD_TEX_IMPORT_PACK
Definition usd.hh:66
@ USD_TEX_IMPORT_COPY
Definition usd.hh:67
@ USD_XFORM_OP_TRS
Definition usd.hh:92
@ USD_XFORM_OP_TOS
Definition usd.hh:93
@ USD_XFORM_OP_MAT
Definition usd.hh:94
@ USD_SCENE_UNITS_CUSTOM
Definition usd.hh:117
@ USD_SCENE_UNITS_MILLIMETERS
Definition usd.hh:121
@ USD_SCENE_UNITS_METERS
Definition usd.hh:118
@ USD_SCENE_UNITS_CENTIMETERS
Definition usd.hh:120
@ USD_SCENE_UNITS_KILOMETERS
Definition usd.hh:119
@ USD_SCENE_UNITS_FEET
Definition usd.hh:123
@ USD_SCENE_UNITS_YARDS
Definition usd.hh:124
@ USD_SCENE_UNITS_INCHES
Definition usd.hh:122
@ USD_ATTR_IMPORT_USER
Definition usd.hh:56
@ USD_ATTR_IMPORT_ALL
Definition usd.hh:57
@ USD_ATTR_IMPORT_NONE
Definition usd.hh:55
static Collection * create_collection(Main *bmain, Collection *parent, const char *name)
@ USD_MTL_PURPOSE_FULL
Definition usd.hh:46
@ USD_MTL_PURPOSE_ALL
Definition usd.hh:44
@ USD_MTL_PURPOSE_PREVIEW
Definition usd.hh:45
bool USD_import(const bContext *C, const char *filepath, const USDImportParams *params, bool as_background_job, ReportList *reports)
eUSDTexNameCollisionMode
Definition usd.hh:74
@ USD_TEX_NAME_COLLISION_USE_EXISTING
Definition usd.hh:75
@ USD_TEX_NAME_COLLISION_OVERWRITE
Definition usd.hh:76
@ USD_SUBDIV_TESSELLATE
Definition usd.hh:83
@ USD_SUBDIV_BEST_MATCH
Definition usd.hh:88
@ USD_SUBDIV_IGNORE
Definition usd.hh:81
void import_blendshapes(Main *bmain, Object *mesh_obj, const pxr::UsdPrim &prim, ReportList *reports, const bool import_anim)
bool USD_export(const bContext *C, const char *filepath, const USDExportParams *params, bool as_background_job, ReportList *reports)
@ USD_TEX_EXPORT_KEEP
Definition usd.hh:111
@ USD_TEX_EXPORT_PRESERVE
Definition usd.hh:112
@ USD_TEX_EXPORT_NEW_PATH
Definition usd.hh:113
eUSDMtlNameCollisionMode
Definition usd.hh:35
@ USD_MTL_NAME_COLLISION_MAKE_UNIQUE
Definition usd.hh:36
@ USD_MTL_NAME_COLLISION_REFERENCE_EXISTING
Definition usd.hh:37
eUSDZTextureDownscaleSize
Definition usd.hh:97
@ USD_TEXTURE_SIZE_256
Definition usd.hh:100
@ USD_TEXTURE_SIZE_CUSTOM
Definition usd.hh:98
@ USD_TEXTURE_SIZE_2048
Definition usd.hh:103
@ USD_TEXTURE_SIZE_4096
Definition usd.hh:104
@ USD_TEXTURE_SIZE_KEEP
Definition usd.hh:99
@ USD_TEXTURE_SIZE_1024
Definition usd.hh:102
@ USD_TEXTURE_SIZE_512
Definition usd.hh:101
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
const EnumPropertyItem io_transform_axis[]
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[]
const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
struct ReportList * reports
struct uiLayout * layout
struct PointerRNA * ptr
void WM_event_add_fileselect(bContext *C, wmOperator *op)
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
bool WM_operator_winactive(bContext *C)