diff options
author | Benjamin Skinner <benjamin.skinner96@gmail.com> | 2020-11-17 18:43:35 +0300 |
---|---|---|
committer | makowalski <makowalski@nvidia.com> | 2021-01-16 06:19:32 +0300 |
commit | 1e5e81a873874ac23ed390292221c9745c0bfc2b (patch) | |
tree | 9c8885c32cea0ddf7e5269f23c4147056d451e63 /source | |
parent | 3cc1bcce4ff7417bd0659e1171fd370e29385fc2 (diff) |
Initial USD Import open sourcing.
Cherry-picked commit of Tangent Animation's
USD importer from branch ta-usd-import in
https://github.com/tangent-opensource/blender.git.
Diffstat (limited to 'source')
41 files changed, 4422 insertions, 101 deletions
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 82f985a3227..3a7715a1d33 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -668,6 +668,13 @@ if(WITH_ALEMBIC) add_definitions(-DWITH_ALEMBIC) endif() +if(WITH_USD) + list(APPEND INC + ../io/usd + ) + add_definitions(-DWITH_USD) +endif() + if(WITH_OPENSUBDIV) list(APPEND INC_SYS ${OPENSUBDIV_INCLUDE_DIRS} diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index d6c31809a2e..fa11c43769c 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -55,6 +55,10 @@ # include "ABC_alembic.h" #endif +#ifdef WITH_USD +# include "usd.h" +#endif + static void cachefile_handle_free(CacheFile *cache_file); static void cache_file_init_data(ID *id) @@ -162,89 +166,178 @@ void BKE_cachefile_reader_open(CacheFile *cache_file, Object *object, const char *object_path) { + switch (cache_file->type) { #ifdef WITH_ALEMBIC - BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); + case CACHEFILE_TYPE_ALEMBIC: + BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); - if (cache_file->handle == NULL) { - return; - } + if (cache_file->handle == NULL) { + return; + } - /* Open Alembic cache reader. */ - *reader = CacheReader_open_alembic_object(cache_file->handle, *reader, object, object_path); + /* Open Alembic cache reader. */ + *reader = CacheReader_open_alembic_object( + (CacheArchiveHandle *)cache_file->handle, *reader, object, object_path); + + /* Multiple modifiers and constraints can call this function concurrently. */ + BLI_spin_lock(&spin); + if (*reader) { + /* Register in set so we can free it when the cache file changes. */ + if (cache_file->handle_readers == NULL) { + cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers"); + } + BLI_gset_reinsert(cache_file->handle_readers, reader, NULL); + } + else if (cache_file->handle_readers) { + /* Remove in case CacheReader_open_alembic_object free the existing reader. */ + BLI_gset_remove(cache_file->handle_readers, reader, NULL); + } + BLI_spin_unlock(&spin); + break; +#endif +#ifdef WITH_USD + case CACHEFILE_TYPE_USD: + BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); + if (cache_file->handle == NULL) { + return; + } - /* Multiple modifiers and constraints can call this function concurrently. */ - BLI_spin_lock(&spin); - if (*reader) { - /* Register in set so we can free it when the cache file changes. */ - if (cache_file->handle_readers == NULL) { - cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers"); - } - BLI_gset_reinsert(cache_file->handle_readers, reader, NULL); - } - else if (cache_file->handle_readers) { - /* Remove in case CacheReader_open_alembic_object free the existing reader. */ - BLI_gset_remove(cache_file->handle_readers, reader, NULL); - } - BLI_spin_unlock(&spin); -#else - UNUSED_VARS(cache_file, reader, object, object_path); + /* Open USD cache reader. */ + *reader = CacheReader_open_usd_object( + (USDStageHandle *)cache_file->handle, *reader, object, object_path); + /* Multiple modifiers and constraints can call this function concurrently. */ + BLI_spin_lock(&spin); + if (*reader) { + /* Register in set so we can free it when the cache file changes. */ + if (cache_file->handle_readers == NULL) { + cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers"); + } + BLI_gset_reinsert(cache_file->handle_readers, reader, NULL); + } + else if (cache_file->handle_readers) { + /* Remove in case CacheReader_open_usd_object free the existing reader. */ + BLI_gset_remove(cache_file->handle_readers, reader, NULL); + } + BLI_spin_unlock(&spin); + break; #endif + default: + UNUSED_VARS(cache_file, reader, object, object_path); + break; + } } void BKE_cachefile_reader_free(CacheFile *cache_file, struct CacheReader **reader) { + switch (cache_file->type) { #ifdef WITH_ALEMBIC - if (*reader != NULL) { - if (cache_file) { - BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); - } + case CACHEFILE_TYPE_ALEMBIC: + if (*reader != NULL) { + if (cache_file) { + BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); + } - CacheReader_free(*reader); - *reader = NULL; + CacheReader_free(*reader); + *reader = NULL; - /* Multiple modifiers and constraints can call this function concurrently. */ - BLI_spin_lock(&spin); - if (cache_file && cache_file->handle_readers) { - BLI_gset_remove(cache_file->handle_readers, reader, NULL); - } - BLI_spin_unlock(&spin); - } -#else - UNUSED_VARS(cache_file, reader); + /* Multiple modifiers and constraints can call this function concurrently. */ + BLI_spin_lock(&spin); + if (cache_file && cache_file->handle_readers) { + BLI_gset_remove(cache_file->handle_readers, reader, NULL); + } + BLI_spin_unlock(&spin); + } #endif +#ifdef WITH_USD + case CACHEFILE_TYPE_USD: + if (*reader != NULL) { + if (cache_file) { + BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE); + } + + USDCacheReader_free(*reader); + *reader = NULL; + + /* Multiple modifiers and constraints can call this function concurrently. */ + BLI_spin_lock(&spin); + if (cache_file && cache_file->handle_readers) { + BLI_gset_remove(cache_file->handle_readers, reader, NULL); + } + BLI_spin_unlock(&spin); + } + break; +#endif + default: + UNUSED_VARS(cache_file, reader); + break; + } } static void cachefile_handle_free(CacheFile *cache_file) { + switch (cache_file->type) { #ifdef WITH_ALEMBIC - /* Free readers in all modifiers and constraints that use the handle, before - * we free the handle itself. */ - BLI_spin_lock(&spin); - if (cache_file->handle_readers) { - GSetIterator gs_iter; - GSET_ITER (gs_iter, cache_file->handle_readers) { - struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter); - if (*reader != NULL) { - CacheReader_free(*reader); - *reader = NULL; + case CACHEFILE_TYPE_ALEMBIC: + /* Free readers in all modifiers and constraints that use the handle, before + * we free the handle itself. */ + BLI_spin_lock(&spin); + if (cache_file->handle_readers) { + GSetIterator gs_iter; + GSET_ITER (gs_iter, cache_file->handle_readers) { + struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter); + if (*reader != NULL) { + CacheReader_free(*reader); + *reader = NULL; + } + } + + BLI_gset_free(cache_file->handle_readers, NULL); + cache_file->handle_readers = NULL; } - } + BLI_spin_unlock(&spin); - BLI_gset_free(cache_file->handle_readers, NULL); - cache_file->handle_readers = NULL; - } - BLI_spin_unlock(&spin); + /* Free handle. */ + if (cache_file->handle) { + ABC_free_handle((CacheArchiveHandle *)cache_file->handle); + cache_file->handle = NULL; + } - /* Free handle. */ - if (cache_file->handle) { - ABC_free_handle(cache_file->handle); - cache_file->handle = NULL; - } + cache_file->handle_filepath[0] = '\0'; + break; +#endif +#ifdef WITH_USD + case CACHEFILE_TYPE_USD: + /* Free readers in all modifiers and constraints that use the handle, before + * we free the handle itself. */ + BLI_spin_lock(&spin); + if (cache_file->handle_readers) { + GSetIterator gs_iter; + GSET_ITER (gs_iter, cache_file->handle_readers) { + struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter); + if (*reader != NULL) { + USDCacheReader_free(*reader); + *reader = NULL; + } + } + + BLI_gset_free(cache_file->handle_readers, NULL); + cache_file->handle_readers = NULL; + } + BLI_spin_unlock(&spin); - cache_file->handle_filepath[0] = '\0'; -#else - UNUSED_VARS(cache_file); + /* Free handle. */ + if (cache_file->handle) { + USD_free_handle((USDStageHandle *)cache_file->handle); + cache_file->handle = NULL; + } + + cache_file->handle_filepath[0] = '\0'; + break; #endif + default: + UNUSED_VARS(cache_file); + break; + } } void *BKE_cachefile_add(Main *bmain, const char *name) @@ -284,8 +377,20 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file BLI_freelistN(&cache_file->object_paths); #ifdef WITH_ALEMBIC - cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths); - BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); + if (BLI_path_extension_check_glob(filepath, "*abc")) { + cache_file->type = CACHEFILE_TYPE_ALEMBIC; + cache_file->handle = (CacheArchiveHandle *)ABC_create_handle( + bmain, filepath, &cache_file->object_paths); + BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); + } +#endif +#ifdef WITH_USD + if (BLI_path_extension_check_glob(filepath, "*.usd;*.usda;*.usdc;*.usdz")) { + cache_file->type = CACHEFILE_TYPE_USD; + cache_file->handle = (CacheArchiveHandle *)USD_create_handle( + bmain, filepath, &cache_file->object_paths); + BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); + } #endif if (DEG_is_active(depsgraph)) { @@ -330,4 +435,4 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c const float time_offset = cache_file->frame_offset / fps; const float frame = (cache_file->override_frame ? cache_file->frame : time); return cache_file->is_sequence ? frame : frame / fps - time_offset; -} +}
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b6f84dfc42f..7b5ac10f86e 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -95,6 +95,10 @@ # include "ABC_alembic.h" #endif +#ifdef WITH_USD +# include "usd.h" +#endif + /* ---------------------------------------------------------------------------- */ /* Useful macros for testing various common flag combinations */ @@ -5290,7 +5294,7 @@ static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, vo static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { -#ifdef WITH_ALEMBIC +#if defined(WITH_ALEMBIC) || defined(WITH_USD) bTransformCacheConstraint *data = con->data; Scene *scene = cob->scene; @@ -5308,7 +5312,20 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa BKE_cachefile_reader_open(cache_file, &data->reader, cob->ob, data->object_path); } - ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale); + switch (cache_file->type) { +# ifdef WITH_ALEMBIC + case CACHEFILE_TYPE_ALEMBIC: + ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale); + break; +# endif +# ifdef WITH_USD + case CACHEFILE_TYPE_USD: + USD_get_transform(data->reader, cob->matrix, time * FPS, cache_file->scale); + break; +# endif + default: + break; + } #else UNUSED_VARS(con, cob); #endif diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index acb511a414d..b4985f7fccf 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -51,6 +51,7 @@ void ED_operatortypes_io(void) WM_operatortype_append(WM_OT_alembic_export); #endif #ifdef WITH_USD + WM_operatortype_append(WM_OT_usd_import); WM_operatortype_append(WM_OT_usd_export); #endif diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index 0eadb38abb5..cb75e0d524b 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -22,23 +22,30 @@ */ #ifdef WITH_USD +# include <string.h> # include "DNA_space_types.h" +# include "DNA_modifier_types.h" # include "BKE_context.h" # include "BKE_main.h" # include "BKE_report.h" +# include "BLI_blenlib.h" # include "BLI_path_util.h" # include "BLI_string.h" # include "BLI_utildefines.h" # include "BLT_translation.h" +# include "ED_object.h" + # include "MEM_guardedalloc.h" # include "RNA_access.h" # include "RNA_define.h" +# include "RNA_enum_types.h" + # include "UI_interface.h" # include "UI_resources.h" @@ -50,6 +57,8 @@ # include "io_usd.h" # include "usd.h" +# include "stdio.h" + const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = { {DAG_EVAL_RENDER, "RENDER", @@ -64,6 +73,16 @@ const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_usd_import_read_flags[] = { + {MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""}, + {MOD_MESHSEQ_READ_POLY, "POLY", 0, "Faces", ""}, + {MOD_MESHSEQ_READ_UV, "UV", 0, "UV", ""}, + {MOD_MESHSEQ_READ_COLOR, "COLOR", 0, "Color", ""}, + {MOD_MESHSEQ_READ_ATTR, "ATTR", 0, "Attributes", ""}, + {MOD_MESHSEQ_READ_VELS, "VELS", 0, "Velocities", ""}, + {0, NULL, 0, NULL, NULL}, +}; + /* Stored in the wmOperator's customdata field to indicate it should run as a background job. * This is set when the operator is invoked, and not set when it is only executed. */ enum { AS_BACKGROUND_JOB = 1 }; @@ -242,4 +261,275 @@ void WM_OT_usd_export(struct wmOperatorType *ot) "are different settings for viewport and rendering"); } +/* ====== USD Import ====== */ + +static int wm_usd_import_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!RNA_struct_property_is_set(op->ptr, "as_background_job")) { + RNA_boolean_set(op->ptr, "as_background_job", true); + } + return WM_operator_filesel(C, op, event); +} + +static int wm_usd_import_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + const float scale = RNA_float_get(op->ptr, "scale"); + const float vel_scale = RNA_float_get(op->ptr, "vel_scale"); + const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence"); + const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range"); + const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes"); + const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job"); + const char global_read_flag = RNA_enum_get(op->ptr, "global_read_flag"); + + const bool import_cameras = RNA_boolean_get(op->ptr, "import_cameras"); + const bool import_curves = RNA_boolean_get(op->ptr, "import_curves"); + const bool import_lights = RNA_boolean_get(op->ptr, "import_lights"); + const bool import_materials = RNA_boolean_get(op->ptr, "import_materials"); + const bool import_meshes = RNA_boolean_get(op->ptr, "import_meshes"); + const bool import_volumes = RNA_boolean_get(op->ptr, "import_volumes"); + + const bool import_subdiv = RNA_boolean_get(op->ptr, "import_subdiv"); + + const bool create_collection = RNA_boolean_get(op->ptr, "create_collection"); + + char *prim_path_mask = malloc(1024); + RNA_string_get(op->ptr, "prim_path_mask", prim_path_mask); + + int offset = 0; + int sequence_len = 1; + + if (is_sequence) { + // @TODO: Not Implemented + /*sequence_len = get_sequence_len(filename, &offset); + if (sequence_len < 0) { + BKE_report(op->reports, RPT_ERROR, "Unable to determine ABC sequence length"); + return OPERATOR_CANCELLED; + }*/ + } + + /* Switch out of edit mode to avoid being stuck in it (T54326). */ + Object *obedit = CTX_data_edit_object(C); + if (obedit) { + ED_object_mode_toggle(C, OB_MODE_EDIT); + } + + struct USDImportParams params = { + scale, + vel_scale, + is_sequence, + set_frame_range, + sequence_len, + offset, + validate_meshes, + global_read_flag, + import_cameras, + import_curves, + import_lights, + import_materials, + import_meshes, + import_volumes, + prim_path_mask, + import_subdiv, + create_collection, + }; + + bool ok = USD_import(C, filename, ¶ms, as_background_job); + + return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout; + struct PointerRNA *ptr = op->ptr; + + uiLayoutSetPropSep(layout, false); + + uiLayout *box = uiLayoutBox(layout); + uiLayout *row = uiLayoutRow(box, false); + + uiItemL(box, IFACE_("USD Import"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Global Read Flag:"), ICON_NONE); + row = uiLayoutRow(box, false); + uiItemR(row, ptr, "global_read_flag", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE); + row = uiLayoutRow(box, false); + uiItemR(row, ptr, "scale", 0, NULL, ICON_NONE); + row = uiLayoutRow(box, false); + uiItemR(row, ptr, "vel_scale", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Options:"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, ptr, "relative_path", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, ptr, "set_frame_range", 0, NULL, ICON_NONE); + + // TODO: Not supported + // row = uiLayoutRow(box, false); + // uiItemR(row, ptr, "is_sequence", 0, NULL, ICON_NONE); + + // row = uiLayoutRow(box, false); + // uiItemR(row, ptr, "validate_meshes", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, ptr, "import_subdiv", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, ptr, "create_collection", 0, NULL, ICON_NONE); + + // row = uiLayoutRow(box, false); + // uiItemR(row, ptr, "prim_path_mask", 0, NULL, ICON_NONE); + + uiLayout *prim_path_mask_box = uiLayoutBox(box); + row = uiLayoutRow(prim_path_mask_box, false); + uiItemL(row, IFACE_("Prim Path Mask:"), ICON_NONE); + + row = uiLayoutRow(prim_path_mask_box, false); + uiItemR(row, ptr, "prim_path_mask", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Primitive Types:"), ICON_OBJECT_DATA); + uiItemR(box, ptr, "import_cameras", 0, NULL, ICON_NONE); + uiItemR(box, ptr, "import_curves", 0, NULL, ICON_NONE); + uiItemR(box, ptr, "import_lights", 0, NULL, ICON_NONE); + uiItemR(box, ptr, "import_materials", 0, NULL, ICON_NONE); + uiItemR(box, ptr, "import_meshes", 0, NULL, ICON_NONE); + uiItemR(box, ptr, "import_volumes", 0, NULL, ICON_NONE); +} + +void WM_OT_usd_import(struct wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Import USD"; + ot->description = "Import USD stage into current scene"; + ot->idname = "WM_OT_usd_import"; + + ot->invoke = wm_usd_import_invoke; + ot->exec = wm_usd_import_exec; + ot->poll = WM_operator_winactive; + ot->ui = wm_usd_import_draw; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_USD, + FILE_BLENDER, + FILE_SAVE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + RNA_def_float( + ot->srna, + "scale", + 1.0f, + 0.0001f, + 1000.0f, + "Scale", + "Value by which to enlarge or shrink the objects with respect to the world's origin", + 0.0001f, + 1000.0f); + RNA_def_float(ot->srna, + "vel_scale", + 1.0f, + 0.0001f, + 1000.0f, + "Velocity Scale", + "Amount to scale velocity", + 0.0001f, + 1000.0f); + + RNA_def_boolean( + ot->srna, + "set_frame_range", + true, + "Set Frame Range", + "If checked, update scene's start and end frame to match those of the USD archive"); + + RNA_def_boolean(ot->srna, + "validate_meshes", + 0, + "Validate Meshes", + "Check imported mesh objects for invalid data (slow)"); + + RNA_def_boolean(ot->srna, + "is_sequence", + false, + "Is Sequence", + "Only set to true if the cache is split into separate files. (UNSUPPORTED)"); + + RNA_def_boolean( + ot->srna, + "as_background_job", + false, + "Run as Background Job", + "Enable this to run the export in the background, disable to block Blender while exporting. " + "This option is deprecated; EXECUTE this operator to run in the foreground, and INVOKE it " + "to run as a background job"); + + RNA_def_boolean( + ot->srna, "import_cameras", true, "Cameras", "When checked, all cameras will be imported"); + RNA_def_boolean( + ot->srna, "import_curves", true, "Curves", "When checked, all curves will be imported"); + RNA_def_boolean( + ot->srna, "import_lights", true, "Lights", "When checked, all lights will be imported"); + RNA_def_boolean(ot->srna, + "import_materials", + true, + "Materials", + "When checked, all materials will be imported"); + RNA_def_boolean( + ot->srna, "import_meshes", true, "Meshes", "When checked, all meshes will be imported"); + RNA_def_boolean(ot->srna, + "import_volumes", + true, + "Volumes", + "(Tangent Specific) When checked, all volumes will be imported"); + + RNA_def_boolean(ot->srna, + "import_subdiv", + true, + "Import Subdiv Scheme", + "If enabled, subdiv surface modifiers will be created based on USD " + "SubdivisionScheme attribute"); + + RNA_def_boolean(ot->srna, + "create_collection", + false, + "Create Collection", + "If enabled, all import objects will be added to a new collection"); + + prop = RNA_def_enum(ot->srna, + "global_read_flag", + rna_enum_usd_import_read_flags, + 0, + "Flags", + "Set read flag for all usd import mesh sequence cache modifiers"); + + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_enum_default(prop, MOD_MESHSEQ_READ_ALL); + + RNA_def_string(ot->srna, + "prim_path_mask", + NULL, + 1024, + "", + "If set, this will specify a specific primitive from the usd stage"); +} + #endif /* WITH_USD */ diff --git a/source/blender/editors/io/io_usd.h b/source/blender/editors/io/io_usd.h index 671984b6f34..24de748285c 100644 --- a/source/blender/editors/io/io_usd.h +++ b/source/blender/editors/io/io_usd.h @@ -26,3 +26,6 @@ struct wmOperatorType; void WM_OT_usd_export(struct wmOperatorType *ot); + +void WM_OT_usd_import(struct wmOperatorType *ot); + diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index 9785f6d68ab..9432e54346f 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -31,7 +31,7 @@ struct Object; struct Scene; struct bContext; -typedef struct AbcArchiveHandle AbcArchiveHandle; +typedef struct CacheArchiveHandle CacheArchiveHandle; int ABC_get_version(void); @@ -97,11 +97,11 @@ bool ABC_import(struct bContext *C, bool validate_meshes, bool as_background_job); -AbcArchiveHandle *ABC_create_handle(struct Main *bmain, +CacheArchiveHandle *ABC_create_handle(struct Main *bmain, const char *filename, struct ListBase *object_paths); -void ABC_free_handle(AbcArchiveHandle *handle); +void ABC_free_handle(CacheArchiveHandle *handle); void ABC_get_transform(struct CacheReader *reader, float r_mat_world[4][4], @@ -125,7 +125,7 @@ bool ABC_mesh_topology_changed(struct CacheReader *reader, void CacheReader_incref(struct CacheReader *reader); void CacheReader_free(struct CacheReader *reader); -struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle, +struct CacheReader *CacheReader_open_alembic_object(struct CacheArchiveHandle *handle, struct CacheReader *reader, struct Object *object, const char *object_path); diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index ad5a258f80c..45ea4d2ed60 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -89,18 +89,14 @@ using Alembic::AbcMaterial::IMaterial; using namespace blender::io::alembic; -struct AbcArchiveHandle { - int unused; -}; - -BLI_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle) +BLI_INLINE ArchiveReader *archive_from_handle(CacheArchiveHandle *handle) { return reinterpret_cast<ArchiveReader *>(handle); } -BLI_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) +BLI_INLINE CacheArchiveHandle *handle_from_archive(ArchiveReader *archive) { - return reinterpret_cast<AbcArchiveHandle *>(archive); + return reinterpret_cast<CacheArchiveHandle *>(archive); } //#define USE_NURBS @@ -150,8 +146,8 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths) } if (get_path) { - void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"); - AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void); + void *abc_path_void = MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath"); + CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(abc_path_void); BLI_strncpy(abc_path->path, object.getFullName().c_str(), sizeof(abc_path->path)); BLI_addtail(object_paths, abc_path); @@ -160,9 +156,9 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths) return parent_is_part_of_this_object; } -AbcArchiveHandle *ABC_create_handle(struct Main *bmain, - const char *filename, - ListBase *object_paths) +CacheArchiveHandle *ABC_create_handle(struct Main *bmain, + const char *filename, + ListBase *object_paths) { ArchiveReader *archive = new ArchiveReader(bmain, filename); @@ -178,7 +174,7 @@ AbcArchiveHandle *ABC_create_handle(struct Main *bmain, return handle_from_archive(archive); } -void ABC_free_handle(AbcArchiveHandle *handle) +void ABC_free_handle(CacheArchiveHandle *handle) { delete archive_from_handle(handle); } @@ -359,8 +355,8 @@ static std::pair<bool, AbcObjectReader *> visit_object( readers.push_back(reader); reader->incref(); - AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>( - MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); + CacheObjectPath *abc_path = static_cast<CacheObjectPath *>( + MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath")); BLI_strncpy(abc_path->path, full_name.c_str(), sizeof(abc_path->path)); BLI_addtail(&settings.cache_file->object_paths, abc_path); @@ -828,7 +824,7 @@ void CacheReader_incref(CacheReader *reader) abc_reader->incref(); } -CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, +CacheReader *CacheReader_open_alembic_object(CacheArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path) diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 79b15c60b94..46c2ac26e94 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -63,6 +63,19 @@ set(SRC intern/usd_writer_metaball.cc intern/usd_writer_transform.cc + intern/usd_util.cc + + intern/usd_reader_camera.cc + intern/usd_reader_curve.cc + intern/usd_reader_geom.cc + intern/usd_reader_light.cc + intern/usd_reader_mesh.cc + intern/usd_reader_nurbs.cc + intern/usd_reader_prim.cc + intern/usd_reader_stage.cc + intern/usd_reader_xform.cc + intern/usd_reader_volume.cc + usd.h intern/usd_exporter_context.h intern/usd_hierarchy_iterator.h @@ -73,6 +86,19 @@ set(SRC intern/usd_writer_mesh.h intern/usd_writer_metaball.h intern/usd_writer_transform.h + + intern/usd_util.h + + intern/usd_reader_camera.h + intern/usd_reader_curve.h + intern/usd_reader_geom.h + intern/usd_reader_light.h + intern/usd_reader_mesh.h + intern/usd_reader_nurbs.h + intern/usd_reader_prim.h + intern/usd_reader_stage.h + intern/usd_reader_xform.h + intern/usd_reader_volume.h ) set(LIB diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc index dc2b46e5cea..a91c41f7bac 100644 --- a/source/blender/io/usd/intern/usd_capi.cc +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -19,11 +19,19 @@ #include "usd.h" #include "usd_hierarchy_iterator.h" +#include "usd_reader_mesh.h" +#include "usd_reader_prim.h" +#include "usd_reader_stage.h" #include <pxr/base/plug/registry.h> #include <pxr/pxr.h> #include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/metrics.h> +#include <pxr/usd/usdGeom/scope.h> #include <pxr/usd/usdGeom/tokens.h> +#include <pxr/usd/usdGeom/xformCommonAPI.h> +#include <pxr/usd/usdLux/domeLight.h> +#include <pxr/usd/usdShade/materialBindingAPI.h> #include "MEM_guardedalloc.h" @@ -31,23 +39,80 @@ #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" +#include "DNA_cachefile_types.h" +#include "DNA_node_types.h" #include "DNA_scene_types.h" +#include "DNA_world_types.h" #include "BKE_appdir.h" #include "BKE_blender_version.h" +#include "BKE_cachefile.h" +#include "BKE_cdderivedmesh.h" #include "BKE_context.h" +#include "BKE_curve.h" #include "BKE_global.h" +#include "BKE_layer.h" +#include "BKE_lib_id.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_node.h" #include "BKE_scene.h" +#include "BKE_world.h" #include "BLI_fileops.h" +#include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" #include "WM_api.h" #include "WM_types.h" +#include "usd_reader_geom.h" +#include "usd_reader_prim.h" +#include "usd_util.h" + +struct USDStageHandle { + CacheArchiveHandle base; +}; + namespace blender::io::usd { +USDStageReader *archive_from_handle(USDStageHandle *handle) +{ + return reinterpret_cast<USDStageReader *>(handle); +} + +USDStageReader *archive_from_handle(CacheArchiveHandle *handle) +{ + return reinterpret_cast<USDStageReader *>(handle); +} + +USDStageHandle *handle_from_archive(USDStageReader *archive) +{ + return reinterpret_cast<USDStageHandle *>(archive); +} + +static bool gather_objects_paths(const pxr::UsdPrim &object, ListBase *object_paths) +{ + if (!object.IsValid()) { + return false; + } + + for (const pxr::UsdPrim &childPrim : object.GetChildren()) { + gather_objects_paths(childPrim, object_paths); + } + + void *usd_path_void = MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath"); + CacheObjectPath *usd_path = static_cast<CacheObjectPath *>(usd_path_void); + + BLI_strncpy(usd_path->path, object.GetPrimPath().GetString().c_str(), sizeof(usd_path->path)); + BLI_addtail(object_paths, usd_path); + + return true; +} + +/* ********************** Export file ********************** */ + struct ExportJobData { Main *bmain; Depsgraph *depsgraph; @@ -210,6 +275,7 @@ bool USD_export(bContext *C, 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); + // TODO: Should create WM_JOB_TYPE_USD... /* setup job */ WM_jobs_customdata_set(wm_job, job, MEM_freeN); @@ -250,3 +316,439 @@ int USD_get_version(void) */ return PXR_VERSION; } + +/* ********************** Import file ********************** */ + +namespace USD { +enum { + USD_NO_ERROR = 0, + USD_ARCHIVE_FAIL, +}; + +struct ImportJobData { + Main *bmain; + Scene *scene; + ViewLayer *view_layer; + wmWindowManager *wm; + + char filename[1024]; + USDImportParams params; + ImportSettings settings; + + USDStageReader *archive; + std::vector<USDPrimReader *> readers; + + short *stop; + short *do_update; + float *progress; + + char error_code; + bool was_canceled; + bool import_ok; +}; + +static void import_startjob(void *customdata, short *stop, short *do_update, float *progress) +{ + WM_reportf(RPT_WARNING, "Import start job: %s", 0); + ImportJobData *data = static_cast<ImportJobData *>(customdata); + + data->stop = stop; + data->do_update = do_update; + data->progress = progress; + data->was_canceled = false; + + // G.is_rendering = true; + WM_set_locked_interface(data->wm, true); + G.is_break = false; + + if (data->params.create_collection) { + char display_name[1024]; + BLI_path_to_display_name( + display_name, strlen(data->filename), BLI_path_basename(data->filename)); + Collection *import_collection = BKE_collection_add( + data->bmain, data->scene->master_collection, display_name); + id_fake_user_set(&import_collection->id); + + DEG_id_tag_update(&import_collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(data->bmain); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + + data->view_layer->active_collection = BKE_layer_collection_first_from_scene_collection( + data->view_layer, import_collection); + } + + BLI_path_abs(data->filename, BKE_main_blendfile_path_from_global()); + USDStageReader *archive = new USDStageReader(data->bmain, data->filename); + + archive->params(data->params); + archive->settings(data->settings); + + CacheFile *cache_file = static_cast<CacheFile *>( + BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename))); + + /* Decrement the ID ref-count because it is going to be incremented for each + * modifier and constraint that it will be attached to, so since currently + * it is not used by anyone, its use count will off by one. */ + id_us_min(&cache_file->id); + + cache_file->is_sequence = data->params.is_sequence; + cache_file->scale = data->params.scale; + STRNCPY(cache_file->filepath, data->filename); + + data->archive = archive; + data->settings.cache_file = cache_file; + data->settings.vel_scale = data->params.vel_scale; + + *data->do_update = true; + *data->progress = 0.05f; + + if (G.is_break) { + data->was_canceled = true; + return; + } + + *data->do_update = true; + *data->progress = 0.1f; + + Scene *scene = data->scene; + + if (!archive->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 Import: unable to find suitable USD plugin to read %s", data->filename); + data->import_ok = false; + return; + } + + // Set up the stage for animated data. + if (data->params.set_frame_range) { + // archive->stage()->SetTimeCodesPerSecond(FPS); + scene->r.sfra = archive->stage()->GetStartTimeCode(); + scene->r.efra = archive->stage()->GetEndTimeCode(); + // archive->usd_stage->SetStartTimeCode(scene->r.sfra); + // usd_stage->SetEndTimeCode(scene->r.efra); + } + + *data->progress = 0.15f; + + data->readers = archive->collect_readers(data->bmain, data->params, data->settings); + + *data->progress = 0.2f; + + const float size = static_cast<float>(data->readers.size()); + size_t i = 0; + + std::vector<USDPrimReader *>::iterator iter; + + /* Setup parenthood */ + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + Object *ob = (*iter)->object(); + + USDPrimReader *reader = (*iter); + reader->readObjectData(data->bmain, 0.0); + + USDPrimReader *parent = (*iter)->parent(); + + if (parent == NULL /*|| !reader->inherits_xform()*/) { + ob->parent = NULL; + } + else { + ob->parent = parent->object(); + } + + *data->progress = 0.2f + 0.8f * (++i / size); + *data->do_update = true; + + if (G.is_break) { + data->was_canceled = true; + return; + } + } + + data->import_ok = !data->was_canceled; + + *progress = 1.0f; + *do_update = true; +} + +static void import_endjob(void *customdata) +{ + WM_reportf(RPT_WARNING, "Import end job: %s", 0); + + ImportJobData *data = static_cast<ImportJobData *>(customdata); + + std::vector<USDPrimReader *>::iterator iter; + + /* Delete objects on cancellation. */ + if (data->was_canceled) { + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + Object *ob = (*iter)->object(); + + /* It's possible that cancellation occurred between the creation of + * the reader and the creation of the Blender object. */ + if (ob == NULL) { + continue; + } + + BKE_id_free_us(data->bmain, ob); + } + } + else { + /* Add object to scene. */ + Base *base; + LayerCollection *lc; + ViewLayer *view_layer = data->view_layer; + + BKE_view_layer_base_deselect_all(view_layer); + + lc = BKE_layer_collection_get_active(view_layer); + + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + Object *ob = (*iter)->object(); + + BKE_collection_object_add(data->bmain, lc->collection, ob); + + base = BKE_view_layer_base_find(view_layer, ob); + /* TODO: is setting active needed? */ + BKE_view_layer_base_select_and_set_active(view_layer, base); + + DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update_ex(data->bmain, + &ob->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION | + ID_RECALC_BASE_FLAGS); + } + + DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS); + DEG_relations_tag_update(data->bmain); + } + + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + USDPrimReader *reader = *iter; + reader->decref(); + + if (reader->refcount() == 0) { + delete reader; + } + } + + WM_set_locked_interface(data->wm, false); + + switch (data->error_code) { + default: + case USD_NO_ERROR: + data->import_ok = !data->was_canceled; + break; + case USD_ARCHIVE_FAIL: + WM_report(RPT_ERROR, "Could not open USD archive for reading! See console for detail."); + break; + } + + WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene); +} + +static void import_freejob(void *user_data) +{ + ImportJobData *data = static_cast<ImportJobData *>(user_data); + + // delete data->archive; + delete data; +} + +} // namespace USD + +bool USD_import(struct bContext *C, + const char *filepath, + const USDImportParams *params, + bool as_background_job) +{ + /* Using new here since MEM_* funcs do not call ctor to properly initialize + * data. */ + USD::ImportJobData *job = new USD::ImportJobData(); + // USD::ImportJobData *job = static_cast<USD::ImportJobData + // *>(MEM_mallocN(sizeof(USD::ImportJobData), "ImportJobData")); + job->bmain = CTX_data_main(C); + job->scene = CTX_data_scene(C); + job->view_layer = CTX_data_view_layer(C); + job->wm = CTX_wm_manager(C); + job->import_ok = false; + BLI_strncpy(job->filename, filepath, 1024); + + job->settings.scale = params->scale; + job->settings.sequence_offset = params->offset; + job->settings.is_sequence = params->is_sequence; + job->settings.sequence_len = params->sequence_len; + job->settings.validate_meshes = params->validate_meshes; + job->settings.sequence_len = params->sequence_len; + job->error_code = USD::USD_NO_ERROR; + job->was_canceled = false; + job->archive = NULL; + + job->params = *params; + + G.is_break = false; + + bool import_ok = false; + if (as_background_job) { + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + job->scene, + "USD Import", + WM_JOB_PROGRESS, + WM_JOB_TYPE_ALEMBIC); + + /* setup job */ + WM_jobs_customdata_set(wm_job, job, USD::import_freejob); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, USD::import_startjob, NULL, NULL, USD::import_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 importing. */ + short stop = 0, do_update = 0; + float progress = 0.f; + + USD::import_startjob(job, &stop, &do_update, &progress); + USD::import_endjob(job); + import_ok = job->import_ok; + + USD::import_freejob(job); + } + + return import_ok; +} + +static USDPrimReader *get_usd_reader(CacheReader *reader, Object *ob, const char **err_str) +{ + USDPrimReader *usd_reader = reinterpret_cast<USDPrimReader *>(reader); + pxr::UsdPrim iobject = usd_reader->prim(); + + if (!iobject.IsValid()) { + *err_str = "Invalid object: verify object path"; + return NULL; + } + + /*const ObjectHeader &header = iobject.getHeader(); + if (!usd_reader->accepts_object_type(header, ob, err_str)) {*/ + /* err_str is set by acceptsObjectType() */ + /*return NULL; +}*/ + + return usd_reader; +} + +Mesh *USD_read_mesh(CacheReader *reader, + Object *ob, + Mesh *existing_mesh, + const float time, + const char **err_str, + int read_flag, + float vel_fac) +{ + USDGeomReader *usd_reader = reinterpret_cast<USDGeomReader *>( + get_usd_reader(reader, ob, err_str)); + if (usd_reader == NULL) { + return NULL; + } + + return usd_reader->read_mesh(existing_mesh, time, read_flag, vel_fac, err_str); +} + +bool USD_mesh_topology_changed( + CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str) +{ + USDMeshReader *usd_reader = (USDMeshReader *)get_usd_reader(reader, ob, err_str); + + if (usd_reader == NULL) { + return false; + } + + return usd_reader->topology_changed(existing_mesh, time); +} + +void USDCacheReader_incref(CacheReader *reader) +{ + USDPrimReader *usd_reader = reinterpret_cast<USDPrimReader *>(reader); + usd_reader->incref(); +} + +CacheReader *CacheReader_open_usd_object(USDStageHandle *handle, + CacheReader *reader, + Object *object, + const char *object_path) +{ + if (object_path[0] == '\0') { + return reader; + } + + USD::USDStageReader *archive = USD::archive_from_handle(handle); + + if (!archive || !archive->valid()) { + return reader; + } + + pxr::UsdPrim prim = archive->stage()->GetPrimAtPath(pxr::SdfPath(object_path)); + + if (reader) { + USDCacheReader_free(reader); + } + + // TODO: The handle does not have the proper import params or settings + USDPrimReader *usd_reader = USD::create_fake_reader(archive, prim); + + if (usd_reader == NULL) { + /* This object is not supported */ + return NULL; + } + usd_reader->object(object); + usd_reader->incref(); + + return reinterpret_cast<CacheReader *>(usd_reader); +} + +void USDCacheReader_free(CacheReader *reader) +{ + USDPrimReader *usd_reader = reinterpret_cast<USDPrimReader *>(reader); + usd_reader->decref(); + + if (usd_reader->refcount() == 0) { + delete usd_reader; + } +} + +USDStageHandle *USD_create_handle(struct Main *bmain, const char *filename, ListBase *object_paths) +{ + USD::USDStageReader *archive = new USD::USDStageReader(bmain, filename); + + if (!archive->valid()) { + delete archive; + return NULL; + } + + if (object_paths) { + USD::gather_objects_paths(archive->stage()->GetPseudoRoot(), object_paths); + } + + return USD::handle_from_archive(archive); +} + +void USD_free_handle(USDStageHandle *handle) +{ + USD::USDStageReader *archive = USD::archive_from_handle(handle); + delete archive; +} + +void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale) +{ + if (!reader) { + return; + } + USDXformReader *usd_reader = reinterpret_cast<USDXformReader *>(reader); + + bool is_constant = false; + usd_reader->read_matrix(r_mat, time, scale, is_constant); +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_camera.cc b/source/blender/io/usd/intern/usd_reader_camera.cc new file mode 100644 index 00000000000..d76c2828d3a --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_camera.cc @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#include "usd_reader_camera.h" +#include "usd_reader_prim.h" + +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_camera.h" +#include "BKE_constraint.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/pxr.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/primRange.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/camera.h> + +void USDCameraReader::createObject(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Creating blender camera for prim: %s", m_prim.GetPath().GetText()); + Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_name.c_str())); + + m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_name.c_str()); + m_object->data = bcam; +} + +void USDCameraReader::readObjectData(Main *bmain, double motionSampleTime) +{ + Camera *bcam = (Camera *)m_object->data; + + pxr::UsdGeomCamera cam_prim = pxr::UsdGeomCamera::Get(m_stage, m_prim.GetPath()); + + pxr::VtValue val; + cam_prim.GetFocalLengthAttr().Get(&val, motionSampleTime); + pxr::VtValue verApOffset; + cam_prim.GetVerticalApertureOffsetAttr().Get(&verApOffset, motionSampleTime); + pxr::VtValue horApOffset; + cam_prim.GetHorizontalApertureOffsetAttr().Get(&horApOffset, motionSampleTime); + pxr::VtValue clippingRangeVal; + cam_prim.GetClippingRangeAttr().Get(&clippingRangeVal, motionSampleTime); + pxr::VtValue focalDistanceVal; + cam_prim.GetFocusDistanceAttr().Get(&focalDistanceVal, motionSampleTime); + pxr::VtValue fstopVal; + cam_prim.GetFStopAttr().Get(&fstopVal, motionSampleTime); + pxr::VtValue projectionVal; + cam_prim.GetProjectionAttr().Get(&projectionVal, motionSampleTime); + pxr::VtValue verAp; + cam_prim.GetVerticalApertureAttr().Get(&verAp, motionSampleTime); + pxr::VtValue horAp; + cam_prim.GetHorizontalApertureAttr().Get(&horAp, motionSampleTime); + + bcam->lens = val.Get<float>(); + // bcam->sensor_x = 0.0f; + // bcam->sensor_y = 0.0f; + bcam->shiftx = verApOffset.Get<float>(); + bcam->shifty = horApOffset.Get<float>(); + + bcam->type = (projectionVal.Get<pxr::TfToken>().GetString() == "perspective") ? CAM_PERSP : + CAM_ORTHO; + + bcam->clip_start = max_ff(0.1f, clippingRangeVal.Get<pxr::GfVec2f>()[0]); + bcam->clip_end = clippingRangeVal.Get<pxr::GfVec2f>()[1]; + + bcam->dof.focus_distance = focalDistanceVal.Get<float>(); + bcam->dof.aperture_fstop = static_cast<float>(fstopVal.Get<float>()); + + if (bcam->type == CAM_ORTHO) { + bcam->ortho_scale = max_ff(verAp.Get<float>(), horAp.Get<float>()); + } + + USDXformReader::readObjectData(bmain, motionSampleTime); +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_camera.h b/source/blender/io/usd/intern/usd_reader_camera.h new file mode 100644 index 00000000000..ac749ca2a4c --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_camera.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_CAMERA_H__ +#define __USD_READER_CAMERA_H__ + +#include "usd.h" +#include "usd_reader_xform.h" + +class USDCameraReader : public USDXformReader { + + public: + USDCameraReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDXformReader(stage, object, import_params, settings) + { + } + + void createObject(Main *bmain, double motionSampleTime) override; + void readObjectData(Main *bmain, double motionSampleTime) override; +}; + +#endif /* __USD_READER_CAMERA_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_curve.cc b/source/blender/io/usd/intern/usd_reader_curve.cc new file mode 100644 index 00000000000..97acf29181d --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_curve.cc @@ -0,0 +1,268 @@ +/* + * 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. + */ + +#include "usd_reader_curve.h" +#include "usd_reader_prim.h" + +#include "MEM_guardedalloc.h" +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_camera.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/base/vt/array.h> +#include <pxr/base/vt/types.h> +#include <pxr/base/vt/value.h> +#include <pxr/pxr.h> +#include <pxr/usd/sdf/assetPath.h> +#include <pxr/usd/sdf/types.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/primRange.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/basisCurves.h> +#include <pxr/usd/usdGeom/curves.h> + +void USDCurvesReader::createObject(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Creating blender curve for prim: %s", m_prim.GetPath().GetText()); + m_curve = BKE_curve_add(bmain, m_name.c_str(), OB_CURVE); + + m_curve->flag |= CU_DEFORM_FILL | CU_3D; + m_curve->actvert = CU_ACT_NONE; + m_curve->resolu = 2; + + m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_name.c_str()); + m_object->data = m_curve; +} + +void USDCurvesReader::readObjectData(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Reading specific camera data: %s", m_prim.GetPath().GetText()); + + Curve *cu = (Curve *)m_object->data; + read_curve_sample(cu, motionSampleTime); + + if (curve_prim.GetPointsAttr().ValueMightBeTimeVarying()) { + addCacheModifier(); + } + + USDXformReader::readObjectData(bmain, motionSampleTime); +} + +void USDCurvesReader::read_curve_sample(Curve *cu, double motionSampleTime) +{ + curve_prim = pxr::UsdGeomBasisCurves::Get(m_stage, m_prim.GetPath()); + + pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr(); + pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr(); + pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr(); + + pxr::VtIntArray usdCounts; + + vertexAttr.Get(&usdCounts, motionSampleTime); + int num_subcurves = usdCounts.size(); + + pxr::VtVec3fArray usdPoints; + pointsAttr.Get(&usdPoints, motionSampleTime); + + pxr::VtFloatArray usdWidths; + widthsAttr.Get(&usdWidths, motionSampleTime); + + pxr::UsdAttribute basisAttr = curve_prim.GetBasisAttr(); + pxr::TfToken basis; + basisAttr.Get(&basis, motionSampleTime); + + pxr::UsdAttribute typeAttr = curve_prim.GetTypeAttr(); + pxr::TfToken type; + typeAttr.Get(&type, motionSampleTime); + + pxr::UsdAttribute wrapAttr = curve_prim.GetWrapAttr(); + pxr::TfToken wrap; + wrapAttr.Get(&wrap, motionSampleTime); + + pxr::VtVec3fArray usdNormals; + curve_prim.GetNormalsAttr().Get(&usdNormals, motionSampleTime); + + // If normals, extrude, else bevel + // Perhaps to be replaced by Blender/USD Schema + if (usdNormals.size() > 0) { + // Set extrusion to 1.0f; + m_curve->ext1 = 1.0f; + } + else { + // Set bevel depth to 1.0f; + m_curve->ext2 = 1.0f; + } + + size_t idx = 0; + for (size_t i = 0; i < num_subcurves; i++) { + const int num_verts = usdCounts[i]; + Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "usd_getnurb")); + + if (basis == pxr::UsdGeomTokens->bspline) { + nu->flag = CU_SMOOTH; + nu->type = CU_NURBS; + } + else if (basis == pxr::UsdGeomTokens->bezier) { + // TODO: Beziers are not properly imported as beziers... + nu->type = CU_NURBS; + nu->flag |= CU_SMOOTH; + nu->flagu |= CU_NURB_ENDPOINT; + } + else if (basis.IsEmpty()) { + nu->type = CU_POLY; + } + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + + nu->pntsu = num_verts; + nu->pntsv = 1; + + if (type == pxr::UsdGeomTokens->cubic) { + nu->orderu = 4; + } + else if (type == pxr::UsdGeomTokens->linear) { + nu->orderu = 2; + } + + if (wrap == pxr::UsdGeomTokens->periodic) { + nu->flagu |= CU_NURB_CYCLIC; + } + else if (wrap == pxr::UsdGeomTokens->pinned) { + nu->flagu |= CU_NURB_ENDPOINT; + } + + float weight = 1.0f; + + nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "usd_getnurb")); + BPoint *bp = nu->bp; + + for (int j = 0; j < nu->pntsu; j++, bp++, idx++) { + bp->vec[0] = (float)usdPoints[idx][0]; + bp->vec[1] = (float)usdPoints[idx][1]; + bp->vec[2] = (float)usdPoints[idx][2]; + bp->vec[3] = weight; + bp->f1 = SELECT; + bp->weight = weight; + + float radius = m_curve->width; + if (idx < usdWidths.size()) + radius = usdWidths[idx]; + + bp->radius = radius; + } + + BKE_nurb_knot_calc_u(nu); + BKE_nurb_knot_calc_v(nu); + + BLI_addtail(BKE_curve_nurbs_get(cu), nu); + } +} + +Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str) +{ + pxr::UsdGeomCurves curve_prim = pxr::UsdGeomCurves::Get(m_stage, m_prim.GetPath()); + + pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr(); + pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr(); + pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr(); + + pxr::VtIntArray usdCounts; + + vertexAttr.Get(&usdCounts, motionSampleTime); + int num_subcurves = usdCounts.size(); + + pxr::VtVec3fArray usdPoints; + pointsAttr.Get(&usdPoints, motionSampleTime); + + int vertex_idx = 0; + int curve_idx; + Curve *curve = static_cast<Curve *>(m_object->data); + + const int curve_count = BLI_listbase_count(&curve->nurb); + bool same_topology = curve_count == num_subcurves; + + if (same_topology) { + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) { + const int num_in_usd = usdCounts[curve_idx]; + const int num_in_blender = nurbs->pntsu; + + if (num_in_usd != num_in_blender) { + same_topology = false; + break; + } + } + } + + if (!same_topology) { + BKE_nurbList_free(&curve->nurb); + read_curve_sample(curve, motionSampleTime); + } + else { + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) { + const int totpoint = usdCounts[curve_idx]; + + if (nurbs->bp) { + BPoint *point = nurbs->bp; + + for (int i = 0; i < totpoint; i++, point++, vertex_idx++) { + point->vec[0] = usdPoints[vertex_idx][0]; + point->vec[1] = usdPoints[vertex_idx][1]; + point->vec[2] = usdPoints[vertex_idx][2]; + } + } + else if (nurbs->bezt) { + BezTriple *bezier = nurbs->bezt; + + for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) { + bezier->vec[1][0] = usdPoints[vertex_idx][0]; + bezier->vec[1][1] = usdPoints[vertex_idx][1]; + bezier->vec[1][2] = usdPoints[vertex_idx][2]; + } + } + } + } + + return BKE_mesh_new_nomain_from_curve(m_object); +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_curve.h b/source/blender/io/usd/intern/usd_reader_curve.h new file mode 100644 index 00000000000..1db69f91976 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_curve.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_CURVES_H__ +#define __USD_READER_CURVES_H__ + +#include "usd.h" +#include "usd_reader_geom.h" + +#include "pxr/usd/usdGeom/basisCurves.h" + +struct Curve; + +class USDCurvesReader : public USDGeomReader { + + public: + USDCurvesReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDGeomReader(stage, object, import_params, settings) + { + } + + void createObject(Main *bmain, double motionSampleTime) override; + void readObjectData(Main *bmain, double motionSampleTime) override; + + void read_curve_sample(Curve *cu, double motionSampleTime); + + Mesh *read_mesh(struct Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str) override; + + protected: + pxr::UsdGeomBasisCurves curve_prim; + Curve *m_curve; +}; + +#endif /* __USD_READER_CURVES_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_geom.cc b/source/blender/io/usd/intern/usd_reader_geom.cc new file mode 100644 index 00000000000..1e1acc9a773 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_geom.cc @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#include "usd_reader_geom.h" +#include "usd_reader_prim.h" + +#include "MEM_guardedalloc.h" +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_camera.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_lib_id.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/base/vt/array.h> +#include <pxr/base/vt/types.h> +#include <pxr/base/vt/value.h> +#include <pxr/pxr.h> +#include <pxr/usd/sdf/assetPath.h> +#include <pxr/usd/sdf/types.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/primRange.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/mesh.h> + +void USDGeomReader::createObject(Main *bmain, double motionSampleTime) +{ +} + +bool USDGeomReader::valid() const +{ + return true; + // return m_schema.valid(); +} + +bool USDGeomReader::topology_changed(Mesh *existing_mesh, double motionSampleTime) +{ + return true; +} + +void USDGeomReader::readObjectData(Main *bmain, double motionSampleTime) +{ +} + +Mesh *USDGeomReader::read_mesh(struct Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str) +{ + return nullptr; +} + +void USDGeomReader::addCacheModifier() +{ + ModifierData *md = modifier_new(eModifierType_MeshSequenceCache); + BLI_addtail(&m_object->modifiers, md); + + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); + + mcmd->cache_file = m_settings->cache_file; + id_us_plus(&mcmd->cache_file->id); + mcmd->read_flag = m_import_params.global_read_flag; + // mcmd->vel_fac = m_settings->vel_scale; + + BLI_strncpy(mcmd->object_path, m_prim.GetPath().GetString().c_str(), FILE_MAX); +} + +void USDGeomReader::addSubdivModifier() +{ + ModifierData *md = modifier_new(eModifierType_Subsurf); + BLI_addtail(&m_object->modifiers, md); + + //SubsurfModifierData *subd = reinterpret_cast<SubsurfModifierData *>(md); +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_geom.h b/source/blender/io/usd/intern/usd_reader_geom.h new file mode 100644 index 00000000000..4370b24f311 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_geom.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_GEOM_H__ +#define __USD_READER_GEOM_H__ + +#include "usd.h" +#include "usd_reader_xform.h" + +struct Mesh; + +class USDGeomReader : public USDXformReader { + + public: + USDGeomReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDXformReader(stage, object, import_params, settings) + { + } + + bool valid() const override; + + virtual void createObject(Main *bmain, double motionSampleTime) override; + virtual void readObjectData(Main *bmain, double motionSampleTime) override; + + virtual Mesh *read_mesh(struct Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str); + + void addCacheModifier() override; + void addSubdivModifier(); + + bool topology_changed(Mesh *existing_mesh, double motionSampleTime); +}; + +#endif /* __USD_READER_GEOM_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_light.cc b/source/blender/io/usd/intern/usd_reader_light.cc new file mode 100644 index 00000000000..1d947416242 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_light.cc @@ -0,0 +1,198 @@ +/* + * 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. + */ + +#include "usd_reader_light.h" +#include "usd_reader_prim.h" +#include "usd_util.h" + +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_constraint_types.h" +#include "DNA_light_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_constraint.h" +#include "BKE_light.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/pxr.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/primRange.h> +#include <pxr/usd/usd/stage.h> + +#include <pxr/usd/usdLux/light.h> + +#include <pxr/usd/usdLux/diskLight.h> +#include <pxr/usd/usdLux/distantLight.h> +#include <pxr/usd/usdLux/rectLight.h> +#include <pxr/usd/usdLux/shapingAPI.h> +#include <pxr/usd/usdLux/sphereLight.h> + +#include <iostream> + +void USDLightReader::createObject(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Creating blender light for prim: %s", m_prim.GetPath().GetText()); + Light *blight = static_cast<Light *>(BKE_light_add(bmain, m_name.c_str())); + + m_object = BKE_object_add_only_object(bmain, OB_LAMP, m_name.c_str()); + m_object->data = blight; +} + +void USDLightReader::readObjectData(Main *bmain, double motionSampleTime) +{ + Light *blight = (Light *)m_object->data; + + pxr::UsdLuxLight light_prim = pxr::UsdLuxLight::Get(m_stage, m_prim.GetPath()); + pxr::UsdLuxShapingAPI shapingAPI(light_prim); + + // Set light type + + if (m_prim.IsA<pxr::UsdLuxDiskLight>()) { + blight->type = LA_AREA; + blight->area_shape = LA_AREA_DISK; + // Ellipse lights are not currently supported + } + else if (m_prim.IsA<pxr::UsdLuxRectLight>()) { + blight->type = LA_AREA; + blight->area_shape = LA_AREA_RECT; + } + else if (m_prim.IsA<pxr::UsdLuxSphereLight>()) { + blight->type = LA_LOCAL; + + if (shapingAPI.GetShapingConeAngleAttr().IsAuthored()) { + blight->type = LA_SPOT; + } + } + else if (m_prim.IsA<pxr::UsdLuxDistantLight>()) { + blight->type = LA_SUN; + } + + // Set light values + + pxr::VtValue intensity; + light_prim.GetIntensityAttr().Get(&intensity, motionSampleTime); + + blight->energy = intensity.Get<float>(); + + // TODO: Not currently supported + // pxr::VtValue exposure; + // light_prim.GetExposureAttr().Get(&exposure, motionSampleTime); + + // TODO: Not currently supported + // pxr::VtValue diffuse; + // light_prim.GetDiffuseAttr().Get(&diffuse, motionSampleTime); + + pxr::VtValue specular; + light_prim.GetSpecularAttr().Get(&specular, motionSampleTime); + blight->spec_fac = specular.Get<float>(); + + pxr::VtValue color; + light_prim.GetColorAttr().Get(&color, motionSampleTime); + pxr::GfVec3f color_vec = color.Get<pxr::GfVec3f>(); + blight->r = color_vec[0]; + blight->g = color_vec[1]; + blight->b = color_vec[2]; + + // TODO: Not currently supported + // pxr::VtValue use_color_temp; + // light_prim.GetEnableColorTemperatureAttr().Get(&use_color_temp, motionSampleTime); + + // TODO: Not currently supported + // pxr::VtValue color_temp; + // light_prim.GetColorTemperatureAttr().Get(&color_temp, motionSampleTime); + + switch (blight->type) { + case LA_AREA: + if (blight->area_shape == LA_AREA_RECT && m_prim.IsA<pxr::UsdLuxRectLight>()) { + pxr::UsdLuxRectLight rect_light = pxr::UsdLuxRectLight::Get(m_stage, m_prim.GetPath()); + + pxr::VtValue width; + rect_light.GetWidthAttr().Get(&width, motionSampleTime); + + pxr::VtValue height; + rect_light.GetHeightAttr().Get(&height, motionSampleTime); + + blight->area_size = width.Get<float>(); + blight->area_sizey = height.Get<float>(); + } + + if (blight->area_shape == LA_AREA_DISK && m_prim.IsA<pxr::UsdLuxDiskLight>()) { + pxr::UsdLuxDiskLight disk_light = pxr::UsdLuxDiskLight::Get(m_stage, m_prim.GetPath()); + + pxr::VtValue radius; + disk_light.GetRadiusAttr().Get(&radius, motionSampleTime); + + blight->area_size = radius.Get<float>() * 2.0f; + } + break; + case LA_LOCAL: + if (m_prim.IsA<pxr::UsdLuxSphereLight>()) { + pxr::UsdLuxSphereLight sphere_light = pxr::UsdLuxSphereLight::Get(m_stage, + m_prim.GetPath()); + + pxr::VtValue radius; + sphere_light.GetRadiusAttr().Get(&radius, motionSampleTime); + + blight->area_size = radius.Get<float>(); + } + break; + case LA_SPOT: + if (m_prim.IsA<pxr::UsdLuxSphereLight>()) { + pxr::UsdLuxSphereLight sphere_light = pxr::UsdLuxSphereLight::Get(m_stage, + m_prim.GetPath()); + + pxr::VtValue radius; + sphere_light.GetRadiusAttr().Get(&radius, motionSampleTime); + + blight->area_size = radius.Get<float>(); + + pxr::VtValue coneAngle; + shapingAPI.GetShapingConeAngleAttr().Get(&coneAngle, motionSampleTime); + blight->spotsize = coneAngle.Get<float>() * ((float)M_PI / 180.0f) * 2.0f; + + pxr::VtValue spotBlend; + shapingAPI.GetShapingConeSoftnessAttr().Get(&spotBlend, motionSampleTime); + blight->spotblend = spotBlend.Get<float>(); + } + break; + case LA_SUN: + if (m_prim.IsA<pxr::UsdLuxDistantLight>()) { + pxr::UsdLuxDistantLight distant_light = pxr::UsdLuxDistantLight::Get(m_stage, + m_prim.GetPath()); + + pxr::VtValue angle; + distant_light.GetAngleAttr().Get(&angle, motionSampleTime); + blight->sun_angle = angle.Get<float>(); + } + break; + } + + USDXformReader::readObjectData(bmain, motionSampleTime); +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_light.h b/source/blender/io/usd/intern/usd_reader_light.h new file mode 100644 index 00000000000..bc8b4301ead --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_light.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_LIGHT_H__ +#define __USD_READER_LIGHT_H__ + +#include "usd.h" +#include "usd_reader_xform.h" + +class USDLightReader : public USDXformReader { + + public: + USDLightReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDXformReader(stage, object, import_params, settings) + { + } + + void createObject(Main *bmain, double motionSampleTime) override; + void readObjectData(Main *bmain, double motionSampleTime) override; +}; + +#endif /* __USD_READER_LIGHT_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc new file mode 100644 index 00000000000..a4a2c474a99 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -0,0 +1,740 @@ +/* + * 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. + */ + +#include "usd_reader_mesh.h" +#include "usd_reader_prim.h" + +#include "MEM_guardedalloc.h" +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_customdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_camera.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_customdata.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/base/vt/array.h> +#include <pxr/base/vt/types.h> +#include <pxr/base/vt/value.h> +#include <pxr/pxr.h> +#include <pxr/usd/sdf/assetPath.h> +#include <pxr/usd/sdf/types.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/primRange.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/mesh.h> +#include <pxr/usd/usdGeom/subset.h> +#include <pxr/usd/usdShade/materialBindingAPI.h> + +#include <iostream> + +namespace usdtokens { +// Materials +static const pxr::TfToken st("st", pxr::TfToken::Immortal); +static const pxr::TfToken UVMap("UVMap", pxr::TfToken::Immortal); +static const pxr::TfToken Cd("Cd", pxr::TfToken::Immortal); +static const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal); +} // namespace usdtokens + +namespace utils { +// Very similar to abc mesh utils +static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map) +{ + Material *material = static_cast<Material *>(bmain->materials.first); + + for (; material; material = static_cast<Material *>(material->id.next)) { + // We have to do this because the stored material name is coming directly from usd + mat_map[pxr::TfMakeValidIdentifier(material->id.name + 2).c_str()] = material; + } +} + +static void assign_materials(Main *bmain, + Object *ob, + const std::map<std::string, int> &mat_index_map) +{ + bool can_assign = true; + std::map<std::string, int>::const_iterator it = mat_index_map.begin(); + + int matcount = 0; + for (; it != mat_index_map.end(); ++it, matcount++) { + if (!BKE_object_material_slot_add(bmain, ob)) { + can_assign = false; + break; + } + } + + /* TODO(kevin): use global map? */ + std::map<std::string, Material *> mat_map; + build_mat_map(bmain, mat_map); + + std::map<std::string, Material *>::iterator mat_iter; + + if (can_assign) { + it = mat_index_map.begin(); + + for (; it != mat_index_map.end(); ++it) { + std::string mat_name = it->first; + mat_iter = mat_map.find(mat_name.c_str()); + + Material *assigned_mat; + + if (mat_iter == mat_map.end()) { + assigned_mat = BKE_material_add(bmain, mat_name.c_str()); + mat_map[mat_name] = assigned_mat; + } + else { + assigned_mat = mat_iter->second; + } + + BKE_object_material_assign(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA); + } + } +} + +} // namespace utils + +static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) +{ + CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); + void *cd_ptr; + CustomData *loopdata; + int numloops; + + /* unsupported custom data type -- don't do anything. */ + if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { + return NULL; + } + + loopdata = &mesh->ldata; + cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name); + if (cd_ptr != NULL) { + /* layer already exists, so just return it. */ + return cd_ptr; + } + + /* Create a new layer. */ + numloops = mesh->totloop; + cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, NULL, numloops, name); + return cd_ptr; +} + +USDMeshReader::USDMeshReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDGeomReader(stage, object, import_params, settings), + m_lastNumPositions(-1), + m_hasUVs(false), + m_isTimeVarying(false), + m_isInitialLoad(false) +{ +} + +void USDMeshReader::createObject(Main *bmain, double motionSampleTime) +{ + Mesh *mesh = BKE_mesh_add(bmain, m_name.c_str()); + + m_object = BKE_object_add_only_object(bmain, OB_MESH, m_name.c_str()); + m_object->data = mesh; + + /* + if (m_settings->validate_meshes) { + BKE_mesh_validate(mesh, false, false); + } + + readFaceSetsSample(bmain, mesh, sample_sel); + */ +} + +void USDMeshReader::readObjectData(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Reading specific mesh data: %s", m_prim.GetPath().GetText()); + + Mesh *mesh = (Mesh *)m_object->data; + + m_isInitialLoad = true; + Mesh *read_mesh = this->read_mesh( + mesh, motionSampleTime, m_import_params.global_read_flag, 1.0f, NULL); + m_isInitialLoad = false; + if (read_mesh != mesh) { + /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_nomain_to_mesh() */ + /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */ + short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH); + BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); + mesh->flag |= autosmooth; + } + + readFaceSetsSample(bmain, mesh, motionSampleTime); + + if (mesh_prim.GetPointsAttr().ValueMightBeTimeVarying()) + m_isTimeVarying = true; + + if (m_isTimeVarying) { + addCacheModifier(); + } + + if (m_import_params.import_subdiv) { + pxr::TfToken subdivScheme; + mesh_prim.GetSubdivisionSchemeAttr().Get(&subdivScheme, motionSampleTime); + + if (subdivScheme == pxr::UsdGeomTokens->catmullClark) { + addSubdivModifier(); + } + } + + USDXformReader::readObjectData(bmain, motionSampleTime); +} + +bool USDMeshReader::valid() const +{ + return mesh_prim.GetPrim().IsValid(); +} + +bool USDMeshReader::topology_changed(Mesh *existing_mesh, double motionSampleTime) +{ + pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr(); + pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr(); + pxr::UsdAttribute pointsAttr = mesh_prim.GetPointsAttr(); + pxr::UsdAttribute normalsAttr = mesh_prim.GetNormalsAttr(); + + faceVertIndicesAttr.Get(&m_face_indices, motionSampleTime); + faceVertCountsAttr.Get(&m_face_counts, motionSampleTime); + pointsAttr.Get(&m_positions, motionSampleTime); + + normalsAttr.Get(&m_normals, motionSampleTime); + + if (m_lastNumPositions != m_positions.size()) { + m_lastNumPositions = m_positions.size(); + return true; + } + + return false; +} + +void USDMeshReader::read_mpolys(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, double motionSampleTime) +{ + MPoly *mpolys = mesh->mpoly; + MLoop *mloops = mesh->mloop; + + pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr(); + pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr(); + + pxr::VtIntArray face_counts; + faceVertCountsAttr.Get(&face_counts, motionSampleTime); + pxr::VtIntArray face_indices; + faceVertIndicesAttr.Get(&face_indices, motionSampleTime); + + unsigned int loop_index = 0; + unsigned int rev_loop_index = 0; + + for (int i = 0; i < face_counts.size(); i++) { + const int face_size = face_counts[i]; + + MPoly &poly = mpolys[i]; + poly.loopstart = loop_index; + poly.totloop = face_size; + poly.mat_nr = 0; + + /* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded, + * this is encoded in custom loop normals. See T71246. */ + poly.flag |= ME_SMOOTH; + + rev_loop_index = loop_index + (face_size - 1); + + for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) { + MLoop &loop = mloops[loop_index]; + if (m_isLeftHanded) + loop.v = face_indices[rev_loop_index]; + else + loop.v = face_indices[loop_index]; + } + } + + BKE_mesh_calc_edges(mesh, false, false); +} + +void USDMeshReader::read_uvs(Mesh *mesh, + pxr::UsdGeomMesh mesh_prim, + double motionSampleTime, + bool load_uvs) +{ + unsigned int loop_index = 0; + unsigned int rev_loop_index = 0; + unsigned int uv_index = 0; + + const CustomData *ldata = &mesh->ldata; + std::vector<pxr::VtVec2fArray> uv_primvars; + uv_primvars.resize(ldata->totlayer); + + if (m_hasUVs) { + for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) { + const CustomDataLayer *layer = &ldata->layers[layer_idx]; + std::string layer_name = std::string(layer->name); + if (layer->type != CD_MLOOPUV) { + continue; + } + pxr::VtVec2fArray uvs; + + pxr::TfToken uv_token; + + // If first time seeing uv token, store in map of <layer->uid, TfToken> + if (uv_token_map.find(layer_name) == uv_token_map.end()) { + uv_token = pxr::TfToken(layer_name); + uv_token_map.insert(std::make_pair(layer_name, uv_token)); + } + else + uv_token = uv_token_map.at(layer_name); + + // Early out if no token found, this should never happen + if (uv_token.IsEmpty()) { + continue; + } + // Early out if not first load and uvs arent animated + if (!load_uvs && primvar_varying_map.find(uv_token) != primvar_varying_map.end() && + !primvar_varying_map.at(uv_token)) { + continue; + } + + // Early out if mesh doesn't have primvar + if (!mesh_prim.HasPrimvar(uv_token)) { + continue; + } + + mesh_prim.GetPrimvar(uv_token).Get<pxr::VtVec2fArray>(&uvs, motionSampleTime); + + uv_primvars[layer_idx] = uvs; + } + } + + for (int i = 0; i < m_face_counts.size(); i++) { + const int face_size = m_face_counts[i]; + + rev_loop_index = loop_index + (face_size - 1); + + for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) { + + for (int layer_idx = 0; layer_idx < ldata->totlayer; layer_idx++) { + const CustomDataLayer *layer = &ldata->layers[layer_idx]; + if (layer->type != CD_MLOOPUV) { + continue; + } + + // Early out if mismatched layer sizes + if (layer_idx > uv_primvars.size()) { + continue; + } + + // Early out if no uvs loaded + if (uv_primvars[layer_idx].empty()) { + continue; + } + + pxr::VtVec2fArray &uvs = uv_primvars[layer_idx]; + + MLoopUV *mloopuv = static_cast<MLoopUV *>(layer->data); + if (m_isLeftHanded) + uv_index = loop_index; + else + uv_index = rev_loop_index; + + if (uv_index >= uvs.size()) { + continue; + } + mloopuv[uv_index].uv[0] = uvs[uv_index][0]; + mloopuv[uv_index].uv[1] = uvs[uv_index][1]; + } + } + } + BKE_mesh_calc_edges(mesh, false, false); +} + +void USDMeshReader::read_attributes(Mesh *mesh, + pxr::UsdGeomMesh mesh_prim, + double motionSampleTime) +{ + CustomData *cd = &mesh->vdata; + std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim.GetPrimvars(); + + for (pxr::UsdGeomPrimvar p : primvars) { + int cd_type = 0; + size_t num = 0; + size_t type_size = 0; + void *data; + + if (!p.HasAuthoredValue()) + continue; + + if (!m_isInitialLoad && + primvar_varying_map.find(p.GetPrimvarName()) == primvar_varying_map.end()) + continue; + + const char *name = p.GetPrimvarName().GetString().c_str(); + if (p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2hArray || + p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2fArray || + p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2dArray) { + continue; + } + else if (p.GetTypeName() == pxr::SdfValueTypeNames->Color3fArray || + p.GetTypeName() == pxr::SdfValueTypeNames->Double3Array || + p.GetTypeName() == pxr::SdfValueTypeNames->Float3Array) { + cd_type = CD_VALUE_F3; + pxr::VtVec3fArray idata; + p.Get<pxr::VtVec3fArray>(&idata, motionSampleTime); + num = idata.size(); + type_size = sizeof(pxr::GfVec3f); + data = (void *)idata.cdata(); + } + else if (p.GetTypeName() == pxr::SdfValueTypeNames->FloatArray || + p.GetTypeName() == pxr::SdfValueTypeNames->DoubleArray) { + cd_type = CD_VALUE_FLOAT; + pxr::VtFloatArray idata; + p.Get<pxr::VtFloatArray>(&idata, motionSampleTime); + num = idata.size(); + type_size = sizeof(float); + data = (void *)idata.cdata(); + } + else if (p.GetTypeName() == pxr::SdfValueTypeNames->IntArray) { + cd_type = CD_VALUE_INT; + pxr::VtIntArray idata; + p.Get<pxr::VtIntArray>(&idata, motionSampleTime); + num = idata.size(); + type_size = sizeof(int); + data = (void *)idata.cdata(); + } + else if (p.GetTypeName() == pxr::SdfValueTypeNames->Int3Array) { + cd_type = CD_VALUE_I3; + pxr::VtVec3iArray idata; + p.Get<pxr::VtVec3iArray>(&idata, motionSampleTime); + num = idata.size(); + type_size = sizeof(pxr::GfVec3i); + data = (void *)idata.cdata(); + } + + void *cdata = CustomData_get_layer_named(cd, cd_type, name); + + if (!cdata) { + cdata = CustomData_add_layer_named(cd, cd_type, CD_DEFAULT, NULL, num, name); + } + memcpy(cdata, data, num * type_size); + } +} + +void USDMeshReader::read_vels(Mesh *mesh, + pxr::UsdGeomMesh mesh_prim, + float vel_scale, + double motionSampleTime) +{ + pxr::VtVec3fArray velocities; + pxr::UsdAttribute vel_attr = mesh_prim.GetVelocitiesAttr(); + + if (!m_isInitialLoad && !vel_attr.ValueMightBeTimeVarying()) + return; + + vel_attr.Get<pxr::VtVec3fArray>(&velocities, motionSampleTime); + + if (velocities.size() <= 0) + return; + + float(*vdata)[3] = (float(*)[3])CustomData_add_layer( + &mesh->vdata, CD_VELOCITY, CD_DEFAULT, NULL, mesh->totvert); + + if (vdata) { + for (int i = 0; i < mesh->totvert; i++) { + vdata[i][0] = velocities[i][0] * vel_scale; + vdata[i][1] = velocities[i][1] * vel_scale; + vdata[i][2] = velocities[i][2] * vel_scale; + } + } +} + +void USDMeshReader::process_normals_vertex_varying(Mesh *mesh) +{ + for (int i = 0; i < m_normals.size(); i++) { + MVert &mvert = mesh->mvert[i]; + mvert.no[0] = m_normals[i][0]; + mvert.no[1] = m_normals[i][1]; + mvert.no[2] = m_normals[i][2]; + } +} + +void USDMeshReader::process_normals_face_varying(Mesh *mesh) +{ + if (m_normals.size() <= 0) { + BKE_mesh_calc_normals(mesh); + return; + } + + // mesh->flag |= ME_AUTOSMOOTH; + + long int loop_count = m_normals.size(); + + float(*lnors)[3] = static_cast<float(*)[3]>( + MEM_malloc_arrayN(loop_count, sizeof(float[3]), "USD::FaceNormals")); + + MPoly *mpoly = mesh->mpoly; + int usd_index = 0; + + for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mpoly) { + for (int j = 0; j < mpoly->totloop; j++, usd_index++) { + int blender_index = mpoly->loopstart + j; + + lnors[blender_index][0] = m_normals[usd_index][0]; + lnors[blender_index][1] = m_normals[usd_index][1]; + lnors[blender_index][2] = m_normals[usd_index][2]; + } + } + BKE_mesh_set_custom_normals(mesh, lnors); + + MEM_freeN(lnors); +} + +void USDMeshReader::read_mesh_sample(const std::string &iobject_full_name, + ImportSettings *settings, + Mesh *mesh, + const pxr::UsdGeomMesh &mesh_prim, + double motionSampleTime, + bool new_mesh) +{ + + pxr::UsdAttribute normalsAttr = mesh_prim.GetNormalsAttr(); + /*pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr(); + pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr();*/ + + std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim.GetPrimvars(); + /*pxr::UsdAttribute pointsAttr = mesh_prim.GetPointsAttr();*/ + pxr::UsdAttribute subdivSchemeAttr = mesh_prim.GetSubdivisionSchemeAttr(); + + /*pxr::VtIntArray face_indices; + faceVertIndicesAttr.Get(&face_indices, motionSampleTime); + pxr::VtIntArray face_counts; + faceVertIndicesAttr.Get(&face_counts, motionSampleTime); + pxr::VtVec3fArray positions; + pointsAttr.Get(&positions, motionSampleTime);*/ + + /*get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); + + if (config.weight != 0.0f) { + Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; + schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); + abc_mesh_data.ceil_positions = ceil_sample.getPositions(); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { + read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); + }*/ + + if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { + for (int i = 0; i < m_positions.size(); i++) { + MVert &mvert = mesh->mvert[i]; + mvert.co[0] = m_positions[i][0]; + mvert.co[1] = m_positions[i][1]; + mvert.co[2] = m_positions[i][2]; + } + + if (m_normalInterpolation == pxr::UsdGeomTokens->vertex) + process_normals_vertex_varying(mesh); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { + read_mpolys(mesh, mesh_prim, motionSampleTime); + if (m_normalInterpolation == pxr::UsdGeomTokens->faceVarying) + process_normals_face_varying(mesh); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { + read_uvs(mesh, mesh_prim, motionSampleTime, new_mesh); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_ATTR) != 0) { + read_attributes(mesh, mesh_prim, motionSampleTime); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_VELS) != 0) { + read_vels(mesh, mesh_prim, settings->vel_scale, motionSampleTime); + } +} + +void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime, + MPoly *mpoly, + int totpoly, + std::map<std::string, int> &r_mat_map) +{ + pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(m_prim); + std::vector<pxr::UsdGeomSubset> subsets = api.GetMaterialBindSubsets(); + + int current_mat = 0; + if (subsets.size() > 0) { + for (pxr::UsdGeomSubset &subset : subsets) { + pxr::UsdShadeMaterialBindingAPI subsetAPI = pxr::UsdShadeMaterialBindingAPI( + subset.GetPrim()); + std::string materialName = subsetAPI.GetDirectBinding().GetMaterialPath().GetName(); + + if (r_mat_map.find(materialName) == r_mat_map.end()) { + r_mat_map[materialName] = 1 + current_mat++; + } + + const int mat_idx = r_mat_map[materialName] - 1; + + pxr::UsdAttribute indicesAttribute = subset.GetIndicesAttr(); + pxr::VtIntArray indices; + indicesAttribute.Get(&indices, motionSampleTime); + + for (int i = 0; i < indices.size(); i++) { + MPoly &poly = mpoly[indices[i]]; + poly.mat_nr = mat_idx; + } + } + } + else { + r_mat_map[api.GetDirectBinding().GetMaterialPath().GetName()] = 1; + } +} + +void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double motionSampleTime) +{ + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, mat_map); + utils::assign_materials(bmain, m_object, mat_map); +} + +Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str) +{ + mesh_prim = pxr::UsdGeomMesh::Get(m_stage, m_prim.GetPath()); + + // pxr::UsdAttribute normalsAttr = mesh_prim.GetNormalsAttr(); + // pxr::UsdAttribute faceVertCountsAttr = mesh_prim.GetFaceVertexCountsAttr(); + // pxr::UsdAttribute faceVertIndicesAttr = mesh_prim.GetFaceVertexIndicesAttr(); + + m_normalInterpolation = mesh_prim.GetNormalsInterpolation(); + + mesh_prim.GetOrientationAttr().Get(&m_orientation); + if (m_orientation == pxr::UsdGeomTokens->leftHanded) + m_isLeftHanded = true; + + std::vector<pxr::TfToken> uv_tokens; + + std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim.GetPrimvars(); + + for (pxr::UsdGeomPrimvar p : primvars) { + if (primvar_varying_map.find(p.GetPrimvarName()) == primvar_varying_map.end()) { + primvar_varying_map.insert(std::make_pair(p.GetPrimvarName(), p.ValueMightBeTimeVarying())); + if (p.ValueMightBeTimeVarying()) + m_isTimeVarying = true; + } + + // Assume all uvs are stored in one of these primvar types... + if (p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2hArray || + p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2fArray || + p.GetTypeName() == pxr::SdfValueTypeNames->TexCoord2dArray) { + uv_tokens.push_back(p.GetBaseName()); + m_hasUVs = true; + } + } + + // pxr::UsdAttribute pointsAttr = mesh_prim.GetPointsAttr(); + // pxr::UsdAttribute subdivSchemeAttr = mesh_prim.GetSubdivisionSchemeAttr(); + + // pxr::VtIntArray face_indices; + // faceVertIndicesAttr.Get(&face_indices, motionSampleTime); + // pxr::VtIntArray face_counts; + // faceVertCountsAttr.Get(&face_counts, motionSampleTime); + // pxr::VtVec3fArray positions; + // pointsAttr.Get(&positions, motionSampleTime); + + Mesh *active_mesh = existing_mesh; + bool new_mesh = false; + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + ImportSettings settings; + settings.read_flag |= read_flag; + settings.vel_scale = vel_scale; + + if (topology_changed(existing_mesh, motionSampleTime)) { + new_mesh = true; + active_mesh = BKE_mesh_new_nomain_from_template( + existing_mesh, m_positions.size(), 0, 0, m_face_indices.size(), m_face_counts.size()); + + for (pxr::TfToken token : uv_tokens) { + void *cd_ptr = add_customdata_cb(active_mesh, token.GetText(), CD_MLOOPUV); + active_mesh->mloopuv = static_cast<MLoopUV *>(cd_ptr); + } + + // settings.read_flag |= MOD_MESHSEQ_READ_ALL; + } + // else { + /* If the face count changed (e.g. by triangulation), only read points. + * This prevents crash from T49813. + * TODO(kevin): perhaps find a better way to do this? */ + /*if (face_counts.size() != existing_mesh->totpoly || + face_indices.size() != existing_mesh->totloop) { + //settings.read_flag = MOD_MESHSEQ_READ_VERT; + std::cout << "Mismatch vert counts\n"; + if (err_str) { + *err_str = + "Topology has changed, perhaps by triangulating the" + " mesh. Only vertices will be read!"; + } + } +}*/ + + read_mesh_sample(m_prim.GetPath().GetString().c_str(), + &settings, + active_mesh, + mesh_prim, + motionSampleTime, + new_mesh || m_isInitialLoad); + + if (new_mesh) { + /* Here we assume that the number of materials doesn't change, i.e. that + * the material slots that were created when the object was loaded from + * USD are still valid now. */ + size_t num_polys = active_mesh->totpoly; + if (num_polys > 0) { + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(motionSampleTime, active_mesh->mpoly, num_polys, mat_map); + } + } + + return active_mesh; +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h new file mode 100644 index 00000000000..e4933c018ad --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_mesh.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_MESH_H__ +#define __USD_READER_MESH_H__ + +#include "pxr/usd/usdGeom/mesh.h" +#include "usd.h" +#include "usd_reader_geom.h" + +typedef float f3Data[3]; + +class USDMeshReader : public USDGeomReader { + + public: + USDMeshReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings); + + bool valid() const override; + + void createObject(Main *bmain, double motionSampleTime) override; + void readObjectData(Main *bmain, double motionSampleTime) override; + + struct Mesh *read_mesh(struct Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str); + bool topology_changed(Mesh *existing_mesh, double motionSampleTime); + + private: + void process_normals_vertex_varying(Mesh *mesh); + void process_normals_face_varying(Mesh *mesh); + void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime); + void assign_facesets_to_mpoly(double motionSampleTime, + struct MPoly *mpoly, + int totpoly, + std::map<std::string, int> &r_mat_map); + + void read_mpolys(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, double motionSampleTime); + void read_uvs(Mesh *mesh, + pxr::UsdGeomMesh mesh_prim, + double motionSampleTime, + bool load_uvs = false); + void read_attributes(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, double motionSampleTime); + void read_vels(Mesh *mesh, pxr::UsdGeomMesh mesh_prim, float vel_scale, double motionSampleTime); + + void read_mesh_sample(const std::string &iobject_full_name, + ImportSettings *settings, + Mesh *mesh, + const pxr::UsdGeomMesh &mesh_prim, + double motionSampleTime, + bool new_mesh); + + pxr::UsdGeomMesh mesh_prim; + + std::unordered_map<std::string, pxr::TfToken> uv_token_map; + std::map<const pxr::TfToken, bool> primvar_varying_map; + + pxr::VtIntArray m_face_indices; + pxr::VtIntArray m_face_counts; + pxr::VtVec3fArray m_positions; + pxr::VtVec3fArray m_normals; + pxr::TfToken m_normalInterpolation; + pxr::TfToken m_orientation; + bool m_isLeftHanded; + + int m_lastNumPositions; + + bool m_hasUVs; + bool m_isTimeVarying; + + // This is to ensure we load all data once because we reuse the read_mesh function + // in the mesh seq modifier, and in initial load. Ideally a better fix would be + // implemented. Note this will break if face or positions vary... + bool m_isInitialLoad; +}; + +#endif /* __USD_READER_MESH_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.cc b/source/blender/io/usd/intern/usd_reader_nurbs.cc new file mode 100644 index 00000000000..7d6693b78a4 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_nurbs.cc @@ -0,0 +1,273 @@ +/* + * 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. + */ + +#include "usd_reader_nurbs.h" +#include "usd_reader_prim.h" + +#include "MEM_guardedalloc.h" +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_camera.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/base/vt/array.h> +#include <pxr/base/vt/types.h> +#include <pxr/base/vt/value.h> +#include <pxr/pxr.h> +#include <pxr/usd/sdf/assetPath.h> +#include <pxr/usd/sdf/types.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/primRange.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/basisCurves.h> +#include <pxr/usd/usdGeom/curves.h> + +static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots) +{ + if (knots.size() == 0) { + return false; + } + + /* Skip first and last knots, as they are used for padding. */ + const size_t num_knots = knots.size(); + nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "usd_setsplineknotsu")); + + for (size_t i = 0; i < num_knots; i++) { + nu_knots[i] = (float)knots[i]; + } + + return true; +} + +void USDNurbsReader::createObject(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Creating blender curve for prim: %s", m_prim.GetPath().GetText()); + m_curve = BKE_curve_add(bmain, m_name.c_str(), OB_CURVE); + + m_curve->flag |= CU_DEFORM_FILL | CU_3D; + m_curve->actvert = CU_ACT_NONE; + m_curve->resolu = 2; + + m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_name.c_str()); + m_object->data = m_curve; +} + +void USDNurbsReader::readObjectData(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Reading specific camera data: %s", m_prim.GetPath().GetText()); + + Curve *cu = (Curve *)m_object->data; + read_curve_sample(cu, motionSampleTime); + + if (curve_prim.GetPointsAttr().ValueMightBeTimeVarying()) { + addCacheModifier(); + } + + USDXformReader::readObjectData(bmain, motionSampleTime); +} + +void USDNurbsReader::read_curve_sample(Curve *cu, double motionSampleTime) +{ + curve_prim = pxr::UsdGeomNurbsCurves::Get(m_stage, m_prim.GetPath()); + + pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr(); + pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr(); + pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr(); + + pxr::VtIntArray usdCounts; + + vertexAttr.Get(&usdCounts, motionSampleTime); + int num_subcurves = usdCounts.size(); + + pxr::VtVec3fArray usdPoints; + pointsAttr.Get(&usdPoints, motionSampleTime); + + pxr::VtFloatArray usdWidths; + widthsAttr.Get(&usdWidths, motionSampleTime); + + pxr::VtIntArray orders; + curve_prim.GetOrderAttr().Get(&orders, motionSampleTime); + + pxr::VtDoubleArray knots; + curve_prim.GetKnotsAttr().Get(&knots, motionSampleTime); + + pxr::VtVec3fArray usdNormals; + curve_prim.GetNormalsAttr().Get(&usdNormals, motionSampleTime); + + // If normals, extrude, else bevel + // Perhaps to be replaced by Blender/USD Schema + if (usdNormals.size() > 0) { + // Set extrusion to 1.0f; + m_curve->ext1 = 1.0f; + } + else { + // Set bevel depth to 1.0f; + m_curve->ext2 = 1.0f; + } + + size_t idx = 0; + for (size_t i = 0; i < num_subcurves; i++) { + const int num_verts = usdCounts[i]; + + Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "usd_getnurb")); + nu->flag = CU_SMOOTH; + nu->type = CU_NURBS; + + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + + nu->pntsu = num_verts; + nu->pntsv = 1; + + if (i < orders.size()) { + nu->orderu = static_cast<short>(orders[i]); + } + else { + nu->orderu = 4; + nu->orderv = 4; + } + + // TODO: Not needed at present, left for future dev + // if (knots.size() > 3) { + // if ((knots[0] == knots[1]) && (knots[knots.size()] == knots[knots.size() - 1])) { + // nu->flagu |= CU_NURB_ENDPOINT; + // } else { + // nu->flagu |= CU_NURB_CYCLIC; + // } + // } + + float weight = 1.0f; + + nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "usd_getnurb")); + BPoint *bp = nu->bp; + + for (int j = 0; j < nu->pntsu; j++, bp++, idx++) { + bp->vec[0] = (float)usdPoints[idx][0]; + bp->vec[1] = (float)usdPoints[idx][1]; + bp->vec[2] = (float)usdPoints[idx][2]; + bp->vec[3] = weight; + bp->f1 = SELECT; + bp->weight = weight; + + float radius = 0.1f; + if (idx < usdWidths.size()) + radius = usdWidths[idx]; + + bp->radius = radius; + } + + if (!set_knots(knots, nu->knotsu)) { + BKE_nurb_knot_calc_u(nu); + } + + BLI_addtail(BKE_curve_nurbs_get(cu), nu); + } +} + +Mesh *USDNurbsReader::read_mesh(struct Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str) +{ + pxr::UsdGeomCurves curve_prim = pxr::UsdGeomCurves::Get(m_stage, m_prim.GetPath()); + + pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr(); + pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr(); + pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr(); + + pxr::VtIntArray usdCounts; + + vertexAttr.Get(&usdCounts, motionSampleTime); + int num_subcurves = usdCounts.size(); + + pxr::VtVec3fArray usdPoints; + pointsAttr.Get(&usdPoints, motionSampleTime); + + int vertex_idx = 0; + int curve_idx; + Curve *curve = static_cast<Curve *>(m_object->data); + + const int curve_count = BLI_listbase_count(&curve->nurb); + bool same_topology = curve_count == num_subcurves; + + if (same_topology) { + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) { + const int num_in_usd = usdCounts[curve_idx]; + const int num_in_blender = nurbs->pntsu; + + if (num_in_usd != num_in_blender) { + same_topology = false; + break; + } + } + } + + if (!same_topology) { + BKE_nurbList_free(&curve->nurb); + read_curve_sample(curve, motionSampleTime); + } + else { + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) { + const int totpoint = usdCounts[curve_idx]; + + if (nurbs->bp) { + BPoint *point = nurbs->bp; + + for (int i = 0; i < totpoint; i++, point++, vertex_idx++) { + point->vec[0] = usdPoints[vertex_idx][0]; + point->vec[1] = usdPoints[vertex_idx][1]; + point->vec[2] = usdPoints[vertex_idx][2]; + } + } + else if (nurbs->bezt) { + BezTriple *bezier = nurbs->bezt; + + for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) { + bezier->vec[1][0] = usdPoints[vertex_idx][0]; + bezier->vec[1][1] = usdPoints[vertex_idx][1]; + bezier->vec[1][2] = usdPoints[vertex_idx][2]; + } + } + } + } + + return BKE_mesh_new_nomain_from_curve(m_object); +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.h b/source/blender/io/usd/intern/usd_reader_nurbs.h new file mode 100644 index 00000000000..4849c02c38c --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_nurbs.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_NURBS_H__ +#define __USD_READER_NURBS_H__ + +#include "usd.h" +#include "usd_reader_geom.h" + +#include "pxr/usd/usdGeom/nurbsCurves.h" + +struct Curve; + +class USDNurbsReader : public USDGeomReader { + + public: + USDNurbsReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDGeomReader(stage, object, import_params, settings) + { + } + + void createObject(Main *bmain, double motionSampleTime) override; + void readObjectData(Main *bmain, double motionSampleTime) override; + + void read_curve_sample(Curve *cu, double motionSampleTime); + + Mesh *read_mesh(struct Mesh *existing_mesh, + double motionSampleTime, + int read_flag, + float vel_scale, + const char **err_str) override; + + protected: + pxr::UsdGeomNurbsCurves curve_prim; + Curve *m_curve; +}; + +#endif /* __USD_READER_NURBS_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_prim.cc b/source/blender/io/usd/intern/usd_reader_prim.cc new file mode 100644 index 00000000000..bdf96be1d31 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_prim.cc @@ -0,0 +1,112 @@ +/* + * 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. + */ + +#include "usd_reader_prim.h" + +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_constraint_types.h" +#include "DNA_modifier_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_constraint.h" +#include "BKE_library.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +USDPrimReader::USDPrimReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : m_name(object.GetName().GetString()), + m_prim_path(object.GetPrimPath().GetString()), + m_prim(object), + m_stage(stage), + m_import_params(import_params), + m_settings(&settings) +{ + //@TODO(bjs): This should be handled better + if (m_name == "/") + m_name = "root"; +} + +USDPrimReader::~USDPrimReader() +{ +} + +const pxr::UsdPrim &USDPrimReader::prim() const +{ + return m_prim; +} + +Object *USDPrimReader::object() const +{ + return m_object; +} + +void USDPrimReader::object(Object *ob) +{ + m_object = ob; +} + +bool USDPrimReader::valid() const +{ + return m_prim.IsValid(); +} + +void USDPrimReader::createObject(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Creating blender object for prim: %s", m_prim.GetPath().GetText()); + m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_name.c_str()); + m_object->empty_drawsize = 0.1f; + m_object->data = NULL; +} + +void USDPrimReader::readObjectData(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Reading prim data: %s", m_prim.GetPath().GetText()); + // m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_prim_path.c_str()); + // m_object->data = NULL; +} + +void USDPrimReader::addCacheModifier() +{ +} + +int USDPrimReader::refcount() const +{ + return m_refcount; +} + +void USDPrimReader::incref() +{ + m_refcount++; +} + +void USDPrimReader::decref() +{ + m_refcount--; + BLI_assert(m_refcount >= 0); +} diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h new file mode 100644 index 00000000000..e44fdc87c52 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_prim.h @@ -0,0 +1,239 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_OBJECT_H__ +#define __USD_READER_OBJECT_H__ + +#include "usd.h" + +#include <pxr/usd/sdf/path.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdShade/material.h> +#include <pxr/usd/usdUtils/sparseValueWriter.h> + +#include <vector> + +extern "C" { +#include "DNA_ID.h" +} + +struct CacheFile; +struct Main; +struct Mesh; +struct Object; + +struct ImportSettings { + bool do_convert_mat; + float conversion_mat[4][4]; + + int from_up; + int from_forward; + float scale; + bool is_sequence; + bool set_frame_range; + + /* Length and frame offset of file sequences. */ + int sequence_len; + int sequence_offset; + + /* From MeshSeqCacheModifierData.read_flag */ + int read_flag; + + bool validate_meshes; + + CacheFile *cache_file; + + float vel_scale; + + ImportSettings() + : do_convert_mat(false), + from_up(0), + from_forward(0), + scale(1.0f), + is_sequence(false), + set_frame_range(false), + sequence_len(1), + sequence_offset(0), + read_flag(0), + validate_meshes(false), + cache_file(NULL), + vel_scale(1.0f) + { + } +}; + +// Most generic USD Reader + +class USDPrimReader { + + protected: + std::string m_name; + std::string m_prim_path; + Object *m_object; + pxr::UsdPrim m_prim; + pxr::UsdStageRefPtr m_stage; + const USDImportParams &m_import_params; + USDPrimReader *m_parent_reader; + + ImportSettings *m_settings; + + int m_refcount; + + public: + // USDPrimReader(pxr::UsdPrim* prim, ImportSettings &settings); + USDPrimReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings); + ~USDPrimReader(); + + const pxr::UsdPrim &prim() const; + + virtual bool valid() const; + + virtual void createObject(Main *bmain, double motionSampleTime); + virtual void readObjectData(Main *bmain, double motionSampleTime); + + Object *object() const; + void object(Object *ob); + + USDPrimReader *parent() const + { + return m_parent_reader; + } + void parent(USDPrimReader *parent) + { + m_parent_reader = parent; + } + + int refcount() const; + void incref(); + void decref(); + + virtual void addCacheModifier(); + + const std::string &name() const + { + return m_name; + } + const std::string &prim_path() const + { + return m_prim_path; + } +}; + +// template<typename Schema> static bool has_animations(Schema &schema, ImportSettings *settings) +// { +// return settings->is_sequence || !schema.isConstant(); +// } + +// class USDObjectReader { +// protected: +// std::string m_name; +// std::string m_object_name; +// std::string m_data_name; +// Object *m_object; +// pxr::UsdPrim m_iobject; + +// ImportSettings *m_settings; + +// chrono_t m_min_time; +// chrono_t m_max_time; + +// /* Use reference counting since the same reader may be used by multiple +// * modifiers and/or constraints. */ +// int m_refcount; + +// bool m_inherits_xform; + +// public: +// USDObjectReader *parent_reader; + +// public: +// explicit USDObjectReader(const pxr::UsdPrim &object, ImportSettings &settings); + +// virtual ~USDObjectReader(); + +// const Alembic::USD::IObject &iobject() const; + +// typedef std::vector<USDObjectReader *> ptr_vector; + +// /** +// * Returns the transform of this object. This can be the Alembic object +// * itself (in case of an Empty) or it can be the parent Alembic object. +// */ +// virtual Alembic::USDGeom::IXform xform(); + +// Object *object() const; +// void object(Object *ob); + +// const std::string &name() const +// { +// return m_name; +// } +// const std::string &object_name() const +// { +// return m_object_name; +// } +// const std::string &data_name() const +// { +// return m_data_name; +// } +// bool inherits_xform() const +// { +// return m_inherits_xform; +// } + +// virtual bool valid() const = 0; +// virtual bool accepts_object_type(const Alembic::USDCoreAbstract::ObjectHeader &alembic_header, +// const Object *const ob, +// const char **err_str) const = 0; + +// virtual void readObjectData(Main *bmain, const Alembic::USD::ISampleSelector &sample_sel) = 0; + +// virtual struct Mesh *read_mesh(struct Mesh *mesh, +// const Alembic::USD::ISampleSelector &sample_sel, +// int read_flag, +// const char **err_str); +// virtual bool topology_changed(Mesh *existing_mesh, +// const Alembic::USD::ISampleSelector &sample_sel); + +// /** Reads the object matrix and sets up an object transform if animated. */ +// void setupObjectTransform(const float time); + +// void addCacheModifier(); + +// chrono_t minTime() const; +// chrono_t maxTime() const; + +// int refcount() const; +// void incref(); +// void decref(); + +// void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant); + +// protected: +// void determine_inherits_xform(); +// }; + +// Imath::M44d get_matrix(const Alembic::USDGeom::IXformSchema &schema, const float time); + +#endif /* __USD_READER_OBJECT_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc new file mode 100644 index 00000000000..07ad27a7897 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_stage.cc @@ -0,0 +1,153 @@ +/* + * 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) 2016 Kévin Dietrich. + * All rights reserved. + */ + +#include "usd_reader_stage.h" +#include "usd_reader_camera.h" +#include "usd_reader_curve.h" +#include "usd_reader_mesh.h" +#include "usd_reader_prim.h" +#include "usd_reader_xform.h" + +#include "usd_util.h" + +extern "C" { +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "DNA_node_types.h" +#include "DNA_scene_types.h" +#include "DNA_world_types.h" + +#include "BKE_blender_version.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_scene.h" +#include "BKE_world.h" + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "WM_api.h" +#include "WM_types.h" +} +#include <iostream> + +namespace USD { + +USDStageReader::USDStageReader(struct Main *bmain, const char *filename) +{ + m_stage = pxr::UsdStage::Open(filename); +} + +USDStageReader::~USDStageReader() +{ + clear_readers(); + + m_stage->Unload(); +} + +bool USDStageReader::valid() const +{ + // TODO: Implement + return true; +} + +static USDPrimReader *_handlePrim(Main *bmain, + pxr::UsdStageRefPtr stage, + const USDImportParams ¶ms, + pxr::UsdPrim prim, + USDPrimReader *parent_reader, + std::vector<USDPrimReader *> &readers, + ImportSettings &settings) +{ + USDPrimReader *reader = NULL; + + reader = USD::create_reader(stage, prim, params, settings); + + if (reader == NULL) + return NULL; + + reader->parent(parent_reader); + reader->createObject(bmain, 0.0); + + // This check prevents the pseudo 'root' prim to be added + if (prim != stage->GetPseudoRoot()) { + readers.push_back(reader); + reader->incref(); + } + + for (const auto &childPrim : prim.GetChildren()) { + _handlePrim(bmain, stage, params, childPrim, reader, readers, settings); + } + + return reader; +} + +std::vector<USDPrimReader *> USDStageReader::collect_readers(Main *bmain, + const USDImportParams ¶ms, + ImportSettings &settings) +{ + m_params = params; + m_settings = settings; + + clear_readers(); + + // Iterate through stage + pxr::UsdPrim root = m_stage->GetPseudoRoot(); + + std::string prim_path_mask(params.prim_path_mask); + + if (prim_path_mask.size() > 0) { + std::cout << prim_path_mask << '\n'; + pxr::SdfPath path = pxr::SdfPath(prim_path_mask); + pxr::UsdPrim prim = m_stage->GetPrimAtPath(path.StripAllVariantSelections()); + if (prim.IsValid()) { + root = prim; + if (path.ContainsPrimVariantSelection()) { + // TODO: This will not work properly with setting variants on child prims + while (path.ContainsPrimVariantSelection()) { + std::pair<std::string, std::string> variantSelection = path.GetVariantSelection(); + root.GetVariantSet(variantSelection.first).SetVariantSelection(variantSelection.second); + path = path.GetParentPath(); + } + } + } + } + + m_stage->SetInterpolationType(pxr::UsdInterpolationType::UsdInterpolationTypeHeld); + _handlePrim(bmain, m_stage, params, root, NULL, m_readers, settings); + + return m_readers; +} + +void USDStageReader::clear_readers() +{ + std::vector<USDPrimReader *>::iterator iter; + for (iter = m_readers.begin(); iter != m_readers.end(); ++iter) { + if (((USDPrimReader *)*iter)->refcount() == 0) { + delete *iter; + } + } +} + +} // Namespace USD
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_stage.h b/source/blender/io/usd/intern/usd_reader_stage.h new file mode 100644 index 00000000000..d479c04c180 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_stage.h @@ -0,0 +1,91 @@ +/* + * 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) 2016 Kévin Dietrich. + * All rights reserved. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_ARCHIVE_H__ +#define __USD_READER_ARCHIVE_H__ + +struct Main; +struct Scene; + +#include "usd.h" +#include "usd_reader_prim.h" + +#include <pxr/pxr.h> +#include <pxr/usd/usd/stage.h> + +#include <vector> + +struct ImportSettings; + +namespace USD { + +/* Wrappers around input and output archives. The goal is to be able to use + * streams so that unicode paths work on Windows (T49112), and to make sure that + * the stream objects remain valid as long as the archives are open. + */ + +class USDStageReader { + pxr::UsdStageRefPtr m_stage; + USDImportParams m_params; + ImportSettings m_settings; + + std::vector<USDPrimReader *> m_readers; + + public: + USDStageReader(struct Main *bmain, const char *filename); + ~USDStageReader(); + + std::vector<USDPrimReader *> collect_readers(struct Main *bmain, + const USDImportParams ¶ms, + ImportSettings &settings); + + bool valid() const; + + pxr::UsdStageRefPtr stage() + { + return m_stage; + } + USDImportParams ¶ms() + { + return m_params; + } + ImportSettings &settings() + { + return m_settings; + } + + void params(USDImportParams &a_params) + { + m_params = a_params; + } + void settings(ImportSettings &a_settings) + { + m_settings = a_settings; + } + + void clear_readers(); +}; + +}; // namespace USD + +#endif /* __USD_READER_ARCHIVE_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_volume.cc b/source/blender/io/usd/intern/usd_reader_volume.cc new file mode 100644 index 00000000000..173c94e8b7d --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_volume.cc @@ -0,0 +1,126 @@ +/* + * 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. + */ + +#include "usd_reader_volume.h" + +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_force_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ +#include "DNA_volume_types.h" + +#include "BKE_constraint.h" +#include "BKE_lib_id.h" +#include "BKE_library.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_volume.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/pxr.h> +#include <pxr/usd/usdVol/openVDBAsset.h> +#include <pxr/usd/usdVol/volume.h> + +#include <iostream> + +void USDVolumeReader::createObject(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Creating volume for prim: %s", m_prim.GetPath().GetText()); + Volume *volume = (Volume *)BKE_volume_add(bmain, m_name.c_str()); + id_us_min(&volume->id); + + m_object = BKE_object_add_only_object(bmain, OB_VOLUME, m_name.c_str()); + m_object->data = volume; +} + +void USDVolumeReader::readObjectData(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Reading specific volume data: %s", m_prim.GetPath().GetText()); + + m_volume = pxr::UsdVolVolume::Get(m_stage, m_prim.GetPath()); + + pxr::UsdVolVolume::FieldMap fields = m_volume.GetFieldPaths(); + + std::string filepath; + + Volume *volume = (Volume *)m_object->data; + VolumeGrid *defaultGrid = BKE_volume_grid_active_get(volume); + + for (auto it = fields.begin(); it != fields.end(); ++it) { + + pxr::UsdPrim fieldPrim = m_stage->GetPrimAtPath(it->second); + + if (fieldPrim.IsA<pxr::UsdVolOpenVDBAsset>()) { + pxr::UsdVolOpenVDBAsset fieldBase(fieldPrim); + + pxr::UsdAttribute filepathAttr = fieldBase.GetFilePathAttr(); + pxr::UsdAttribute fieldNameAttr = fieldBase.GetFieldNameAttr(); + + std::string fieldName = "density"; + + if (fieldNameAttr.IsAuthored()) { + fieldNameAttr.Get(&fieldName, 0.0); + + // A Blender volume creates density by default + if (fieldName != "density") { + defaultGrid = BKE_volume_grid_add(volume, fieldName.c_str(), VOLUME_GRID_FLOAT); + } + } + + if (filepathAttr.IsAuthored()) { + + pxr::SdfAssetPath fp; + filepathAttr.Get(&fp, 0.0); + + if (filepathAttr.ValueMightBeTimeVarying()) { + std::vector<double> filePathTimes; + filepathAttr.GetTimeSamples(&filePathTimes); + + int start = (int)filePathTimes.front(); + int end = (int)filePathTimes.back(); + + volume->is_sequence = (char)true; + volume->frame_start = start; + volume->frame_duration = (end - start) + 1; + } + + filepath = fp.GetResolvedPath(); + + strcpy(volume->filepath, filepath.c_str()); + } + } + } + + USDXformReader::readObjectData(bmain, motionSampleTime); +} diff --git a/source/blender/io/usd/intern/usd_reader_volume.h b/source/blender/io/usd/intern/usd_reader_volume.h new file mode 100644 index 00000000000..773b5f43279 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_volume.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_VOLUME_H__ +#define __USD_READER_VOLUME_H__ + +#include "usd.h" +#include "usd_reader_xform.h" + +#include "pxr/usd/usdVol/volume.h" + +class USDVolumeReader : public USDXformReader { + + public: + USDVolumeReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDXformReader(stage, object, import_params, settings) + { + } + + void createObject(Main *bmain, double motionSampleTime) override; + void readObjectData(Main *bmain, double motionSampleTime) override; + + pxr::UsdVolVolume m_volume; +}; + +#endif /* __USD_READER_VOLUME_H__ */ diff --git a/source/blender/io/usd/intern/usd_reader_xform.cc b/source/blender/io/usd/intern/usd_reader_xform.cc new file mode 100644 index 00000000000..fbefa2a50bf --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_xform.cc @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#include "usd_reader_xform.h" +#include "usd_reader_prim.h" + +extern "C" { +#include "DNA_cachefile_types.h" +#include "DNA_constraint_types.h" +#include "DNA_modifier_types.h" +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "BKE_constraint.h" +#include "BKE_lib_id.h" +#include "BKE_library.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +#include <pxr/base/gf/math.h> +#include <pxr/pxr.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/primRange.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/xform.h> + +void USDXformReader::createObject(Main *bmain, double motionSampleTime) +{ + WM_reportf(RPT_WARNING, "Creating blender object for prim: %s", m_prim.GetPath().GetText()); + m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_name.c_str()); + m_object->empty_drawsize = 0.1f; + m_object->data = NULL; +} + +void USDXformReader::readObjectData(Main *bmain, double motionSampleTime) +{ + USDPrimReader::readObjectData(bmain, motionSampleTime); + + WM_reportf(RPT_WARNING, "Reading specific xform data: %s", m_prim.GetPath().GetText()); + + bool is_constant; + float transform_from_usd[4][4]; + + read_matrix(transform_from_usd, motionSampleTime, 1.0f, is_constant); + + if (!is_constant) { + bConstraint *con = BKE_constraint_add_for_object( + m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); + bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data); + BLI_strncpy(data->object_path, m_prim.GetPath().GetText(), FILE_MAX); + + data->cache_file = m_settings->cache_file; + id_us_plus(&data->cache_file->id); + } + + BKE_object_apply_mat4(m_object, transform_from_usd, true, false); +} + +typedef float m4[4]; + +void USDXformReader::read_matrix(float r_mat[4][4] /* local matrix */, + const float time, + const float scale, + bool &is_constant) +{ + is_constant = true; + pxr::UsdGeomXformable xformable = pxr::UsdGeomXformable( + m_prim); // pxr::UsdGeomXformable::Get(m_stage, m_prim.GetPath()); + + bool resetsXformStack = false; + std::vector<pxr::UsdGeomXformOp> orderedXformOps = xformable.GetOrderedXformOps( + &resetsXformStack); + + unit_m4(r_mat); + + if (orderedXformOps.size() <= 0) + return; + + int opCount = 0; + for (std::vector<pxr::UsdGeomXformOp>::iterator I = orderedXformOps.begin(); + I != orderedXformOps.end(); + ++I) { + + pxr::UsdGeomXformOp &xformOp = (*I); + + is_constant = !xformOp.MightBeTimeVarying(); + + pxr::GfMatrix4d mat = xformOp.GetOpTransform(time) * pxr::GfMatrix4d(1.0f).SetScale(scale); + + float t_mat[4][4]; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + t_mat[j][i] = mat[j][i]; + } + } + mul_m4_m4m4(r_mat, r_mat, t_mat); + opCount++; + } +}
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_reader_xform.h b/source/blender/io/usd/intern/usd_reader_xform.h new file mode 100644 index 00000000000..7c8bf397c5f --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_xform.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_READER_XFORM_H__ +#define __USD_READER_XFORM_H__ + +#include "usd.h" +#include "usd_reader_prim.h" + +class USDXformReader : public USDPrimReader { + + public: + USDXformReader(pxr::UsdStageRefPtr stage, + const pxr::UsdPrim &object, + const USDImportParams &import_params, + ImportSettings &settings) + : USDPrimReader(stage, object, import_params, settings) + { + } + + void createObject(Main *bmain, double motionSampleTime) override; + void readObjectData(Main *bmain, double motionSampleTime) override; + + void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant); +}; + +#endif /* __USD_READER_XFORM_H__ */ diff --git a/source/blender/io/usd/intern/usd_util.cc b/source/blender/io/usd/intern/usd_util.cc new file mode 100644 index 00000000000..1c70fe9cb28 --- /dev/null +++ b/source/blender/io/usd/intern/usd_util.cc @@ -0,0 +1,149 @@ +/* + * 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_util.h" +#include "usd_hierarchy_iterator.h" + +#include "usd_reader_camera.h" +#include "usd_reader_curve.h" +#include "usd_reader_geom.h" +#include "usd_reader_light.h" +#include "usd_reader_mesh.h" +#include "usd_reader_nurbs.h" +#include "usd_reader_prim.h" +#include "usd_reader_stage.h" +#include "usd_reader_volume.h" +#include "usd_reader_xform.h" + +extern "C" { +#include "BKE_animsys.h" +#include "BKE_colorband.h" +#include "BKE_colortools.h" +#include "BKE_key.h" +#include "BKE_node.h" + +#include "DNA_color_types.h" +#include "DNA_light_types.h" +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "BKE_blender_version.h" +#include "BKE_cachefile.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_layer.h" +#include "BKE_light.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_scene.h" +#include "BKE_world.h" + +#include "BLI_fileops.h" +#include "BLI_linklist.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" +} +#include "MEM_guardedalloc.h" + +#include <algorithm> +#include <cctype> +#include <string> +#include <utility> + +#include <pxr/base/tf/stringUtils.h> +#include <pxr/pxr.h> +#include <pxr/usd/usdGeom/camera.h> +#include <pxr/usd/usdGeom/curves.h> +#include <pxr/usd/usdGeom/mesh.h> +#include <pxr/usd/usdGeom/nurbsCurves.h> +#include <pxr/usd/usdGeom/scope.h> +#include <pxr/usd/usdLux/light.h> + +namespace USD { + +USDPrimReader *create_reader(const pxr::UsdStageRefPtr &stage, + const pxr::UsdPrim &prim, + const USDImportParams ¶ms, + ImportSettings &settings) +{ + USDPrimReader *reader = nullptr; + + if (params.import_cameras && prim.IsA<pxr::UsdGeomCamera>()) { + reader = new USDCameraReader(stage, prim, params, settings); + } + else if (params.import_curves && prim.IsA<pxr::UsdGeomBasisCurves>()) { + reader = new USDCurvesReader(stage, prim, params, settings); + } + else if (params.import_curves && prim.IsA<pxr::UsdGeomNurbsCurves>()) { + reader = new USDNurbsReader(stage, prim, params, settings); + } + else if (params.import_meshes && prim.IsA<pxr::UsdGeomMesh>()) { + reader = new USDMeshReader(stage, prim, params, settings); + } + else if (params.import_lights && prim.IsA<pxr::UsdLuxLight>()) { + reader = new USDLightReader(stage, prim, params, settings); + } + else if (params.import_volumes && prim.IsA<pxr::UsdVolVolume>()) { + reader = new USDVolumeReader(stage, prim, params, settings); + } + else { + reader = new USDXformReader(stage, prim, params, settings); + } + + return reader; +} + +// TODO: The handle does not have the proper import params or settings +USDPrimReader *create_fake_reader(USD::USDStageReader *archive, const pxr::UsdPrim &prim) +{ + USDPrimReader *reader = nullptr; + if (prim.IsA<pxr::UsdGeomCamera>()) { + reader = new USDCameraReader(archive->stage(), prim, archive->params(), archive->settings()); + } + else if (prim.IsA<pxr::UsdGeomBasisCurves>()) { + reader = new USDCurvesReader(archive->stage(), prim, archive->params(), archive->settings()); + } + else if (prim.IsA<pxr::UsdGeomNurbsCurves>()) { + reader = new USDNurbsReader(archive->stage(), prim, archive->params(), archive->settings()); + } + else if (prim.IsA<pxr::UsdGeomMesh>()) { + reader = new USDMeshReader(archive->stage(), prim, archive->params(), archive->settings()); + } + else if (prim.IsA<pxr::UsdLuxLight>()) { + reader = new USDLightReader(archive->stage(), prim, archive->params(), archive->settings()); + } + else if (prim.IsA<pxr::UsdVolVolume>()) { + reader = new USDVolumeReader(archive->stage(), prim, archive->params(), archive->settings()); + } + else { + reader = new USDXformReader(archive->stage(), prim, archive->params(), archive->settings()); + } + return reader; +} + +} // Namespace USD
\ No newline at end of file diff --git a/source/blender/io/usd/intern/usd_util.h b/source/blender/io/usd/intern/usd_util.h new file mode 100644 index 00000000000..7b9da0facc2 --- /dev/null +++ b/source/blender/io/usd/intern/usd_util.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +/** \file + * \ingroup busd + */ + +#ifndef __USD_UTIL_H__ +#define __USD_UTIL_H__ + +#include <string> + +#ifdef _MSC_VER +# define USD_INLINE static __forceinline +#else +# define USD_INLINE static inline +#endif + +#include <pxr/pxr.h> +#include <pxr/usd/usd/prim.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdLux/light.h> +#include <pxr/usd/usdShade/material.h> + +#include "usd.h" +#include "usd_exporter_context.h" + +class USDPrimReader; +struct ImportSettings; + +struct Light; + +struct Material; +struct bNodeTree; + +namespace USD { + +USDPrimReader *create_reader(const pxr::UsdStageRefPtr &stage, + const pxr::UsdPrim &prim, + const USDImportParams ¶ms, + ImportSettings &settings); +USDPrimReader *create_fake_reader(class USDStageReader *archive, const pxr::UsdPrim &prim); + +} // Namespace USD + +#endif /* __USD_UTIL_H__ */ diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index 40e2d0d8674..d2d3503c69f 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -26,6 +26,11 @@ extern "C" { #endif struct bContext; +struct Object; +struct CacheReader; +struct CacheFile; + +typedef struct USDStageHandle USDStageHandle; struct USDExportParams { bool export_animation; @@ -39,6 +44,26 @@ struct USDExportParams { enum eEvaluationMode evaluation_mode; }; +struct USDImportParams { + float scale; + float vel_scale; + bool is_sequence; + bool set_frame_range; + int sequence_len; + int offset; + bool validate_meshes; + char global_read_flag; + bool import_cameras; + bool import_curves; + bool import_lights; + bool import_materials; + bool import_meshes; + bool import_volumes; + char *prim_path_mask; + bool import_subdiv; + bool create_collection; +}; + /* The USD_export takes a as_background_job parameter, and returns a boolean. * * When as_background_job=true, returns false immediately after scheduling @@ -53,8 +78,46 @@ bool USD_export(struct bContext *C, const struct USDExportParams *params, bool as_background_job); +bool USD_import(struct bContext *C, + const char *filepath, + const struct USDImportParams *params, + bool as_background_job); + int USD_get_version(void); +// ----- USD Import and Mesh Cache interface + +USDStageHandle *USD_create_handle(struct Main *bmain, + const char *filename, + struct ListBase *object_paths); + +void USD_free_handle(USDStageHandle *handle); + +void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale); + +/* Either modifies current_mesh in-place or constructs a new mesh. */ +struct Mesh *USD_read_mesh(struct CacheReader *reader, + struct Object *ob, + struct Mesh *current_mesh, + const float time, + const char **err_str, + int flags, + float vel_scale); + +bool USD_mesh_topology_changed(struct CacheReader *reader, + struct Object *ob, + struct Mesh *existing_mesh, + const float time, + const char **err_str); + +struct CacheReader *CacheReader_open_usd_object(struct USDStageHandle *handle, + struct CacheReader *reader, + struct Object *object, + const char *object_path); + +void USDCacheReader_incref(struct CacheReader *reader); +void USDCacheReader_free(struct CacheReader *reader); + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_cachefile_defaults.h b/source/blender/makesdna/DNA_cachefile_defaults.h index d37994bb488..521b72567d4 100644 --- a/source/blender/makesdna/DNA_cachefile_defaults.h +++ b/source/blender/makesdna/DNA_cachefile_defaults.h @@ -36,6 +36,7 @@ .scale = 1.0f, \ .object_paths ={NULL, NULL}, \ \ + .type = 0, \ .handle = NULL, \ .handle_filepath[0] = '\0', \ .handle_readers = NULL, \ diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index 04c99c6c4b1..19c00d0d80a 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -31,6 +31,17 @@ extern "C" { struct GSet; +/* CacheFile::type */ +enum { + #ifdef WITH_ALEMBIC + CACHEFILE_TYPE_ALEMBIC = 1, + #endif + #ifdef WITH_USD + CACHEFILE_TYPE_USD = 2, + #endif + CACHE_FILE_TYPE_INVALID = 0, +}; + /* CacheFile::flag */ enum { CACHEFILE_DS_EXPAND = (1 << 0), @@ -46,11 +57,15 @@ enum { /* Representation of an object's path inside the Alembic file. * Note that this is not a file path. */ -typedef struct AlembicObjectPath { - struct AlembicObjectPath *next, *prev; +typedef struct CacheObjectPath { + struct CacheObjectPath *next, *prev; char path[4096]; -} AlembicObjectPath; +} CacheObjectPath; + +typedef struct CacheArchiveHandle { + int unused; +} CacheArchiveHandle; /* CacheFile::velocity_unit * Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */ @@ -83,15 +98,17 @@ typedef struct CacheFile { /** Animation flag. */ short flag; short draw_flag; /* UNUSED */ + + char type; - char _pad[3]; + char _pad[2]; char velocity_unit; /* Name of the velocity property in the Alembic file. */ char velocity_name[64]; /* Runtime */ - struct AbcArchiveHandle *handle; + struct CacheArchiveHandle *handle; char handle_filepath[1024]; struct GSet *handle_readers; } CacheFile; diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index e3b5ecfac04..ea585a59b53 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -75,7 +75,7 @@ typedef struct CustomData { * MUST be >= CD_NUMTYPES, but we cant use a define here. * Correct size is ensured in CustomData_update_typemap assert(). */ - int typemap[51]; + int typemap[56]; /** Number of layers, size of layers array. */ int totlayer, maxlayer; /** In editmode, total size of all data layers. */ @@ -156,8 +156,15 @@ typedef enum CustomDataType { CD_PROP_FLOAT2 = 49, CD_PROP_BOOL = 50, + + CD_VALUE_FLOAT = 51, + CD_VALUE_INT = 52, + CD_VALUE_F3 = 53, + CD_VALUE_I3 = 54, - CD_NUMTYPES = 51, + CD_VELOCITY = 55, + + CD_NUMTYPES = 56, } CustomDataType; /* Bits for CustomDataMask */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 03cf4aca963..edbfbbbf03d 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -2116,6 +2116,8 @@ typedef struct MeshSeqCacheModifierData { /** 1024 = FILE_MAX. */ char object_path[1024]; + float vel_fac; + char read_flag; char _pad[3]; @@ -2155,7 +2157,11 @@ enum { * the mesh topology changes, but this heuristic sometimes fails. In these cases, users can * disable interpolation with this flag. */ MOD_MESHSEQ_INTERPOLATE_VERTICES = (1 << 4), + MOD_MESHSEQ_READ_ATTR = (1 << 5), + MOD_MESHSEQ_READ_VELS = (1 << 6), }; +// USD Import re-added attr and vel. We are unsure as to why they were removed +// They are necessary for full USD Import of data typedef struct SDefBind { unsigned int *vert_inds; diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index c25cea1b4b3..b93f494072c 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -64,8 +64,8 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P /* cachefile.object_paths */ static void rna_def_alembic_object_path(BlenderRNA *brna) { - StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPath", NULL); - RNA_def_struct_sdna(srna, "AlembicObjectPath"); + StructRNA *srna = RNA_def_struct(brna, "CacheObjectPath", NULL); + RNA_def_struct_sdna(srna, "CacheObjectPath"); RNA_def_struct_ui_text(srna, "Object Path", "Path of an object inside of an Alembic archive"); RNA_def_struct_ui_icon(srna, ICON_NONE); @@ -81,8 +81,8 @@ static void rna_def_alembic_object_path(BlenderRNA *brna) /* cachefile.object_paths */ static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop) { - RNA_def_property_srna(cprop, "AlembicObjectPaths"); - StructRNA *srna = RNA_def_struct(brna, "AlembicObjectPaths", NULL); + RNA_def_property_srna(cprop, "CacheObjectPaths"); + StructRNA *srna = RNA_def_struct(brna, "CacheObjectPaths", NULL); RNA_def_struct_sdna(srna, "CacheFile"); RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths"); } @@ -169,8 +169,8 @@ static void rna_def_cachefile(BlenderRNA *brna) NULL, NULL, NULL); - RNA_def_property_struct_type(prop, "AlembicObjectPath"); - RNA_def_property_srna(prop, "AlembicObjectPaths"); + RNA_def_property_struct_type(prop, "CacheObjectPath"); + RNA_def_property_srna(prop, "CacheObjectPaths"); RNA_def_property_ui_text( prop, "Object Paths", "Paths of the objects inside the Alembic archive"); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 88953e8fddf..8a4c707e39c 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -6135,8 +6135,12 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna) {MOD_MESHSEQ_READ_POLY, "POLY", 0, "Faces", ""}, {MOD_MESHSEQ_READ_UV, "UV", 0, "UV", ""}, {MOD_MESHSEQ_READ_COLOR, "COLOR", 0, "Color", ""}, + {MOD_MESHSEQ_READ_ATTR, "ATTR", 0, "Attributes", ""}, + {MOD_MESHSEQ_READ_VELS, "VELS", 0, "Velocities", ""}, {0, NULL, 0, NULL, NULL}, }; + // USD Import re-added these. We are unsure as to why they were removed + // They are necessary for full USD Import of data prop = RNA_def_property(srna, "read_data", PROP_ENUM, PROP_NONE); RNA_def_property_flag(prop, PROP_ENUM_FLAG); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 3a7addcba94..6300bc73a15 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -139,6 +139,16 @@ if(WITH_ALEMBIC) ) endif() +if(WITH_USD) + add_definitions(-DWITH_USD) + list(APPEND INC + ../io/usd + ) + list(APPEND LIB + bf_usd + ) +endif() + if(WITH_MOD_REMESH) list(APPEND INC ../../../intern/dualcon diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 2c01857adb1..a2d65c49506 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -38,6 +38,7 @@ #include "BKE_cachefile.h" #include "BKE_context.h" +#include "BKE_customdata.h" #include "BKE_lib_query.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -49,24 +50,39 @@ #include "BLO_read_write.h" +#include "BLI_string.h" + #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" #include "MOD_modifiertypes.h" #include "MOD_ui_common.h" +#include "MEM_guardedalloc.h" + #ifdef WITH_ALEMBIC # include "ABC_alembic.h" # include "BKE_global.h" # include "BKE_lib_id.h" #endif +#ifdef WITH_USD +# include "BKE_global.h" +# include "BKE_library.h" +# include "usd.h" +#endif + static void initData(ModifierData *md) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mcmd, modifier)); + mcmd->cache_file = NULL; + mcmd->object_path[0] = '\0'; + mcmd->vel_fac = 1.0f; + mcmd->read_flag = MOD_MESHSEQ_READ_ALL; + MEMCPY_STRUCT_AFTER(mcmd, DNA_struct_default_get(MeshSeqCacheModifierData), modifier); } @@ -109,7 +125,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene), static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { -#ifdef WITH_ALEMBIC +#if defined(WITH_USD) || defined(WITH_ALEMBIC) MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; /* Only used to check whether we are operating on org data or not... */ @@ -121,7 +137,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * const float frame = DEG_get_ctime(ctx->depsgraph); const float time = BKE_cachefile_time_offset(cache_file, frame, FPS); const char *err_str = NULL; + switch (cache_file->type) { +# ifdef WITH_ALEMBIC + case CACHEFILE_TYPE_ALEMBIC: if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) { STRNCPY(mcmd->reader_object_path, mcmd->object_path); BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path); @@ -178,7 +197,67 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * mesh = org_mesh; } - return result ? result : mesh; + if (!result) { + result = mesh; + } + return result; + break; +# endif +# ifdef WITH_USD + case CACHEFILE_TYPE_USD: + if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) { + STRNCPY(mcmd->reader_object_path, mcmd->object_path); + BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path); + if (!mcmd->reader) { + printf("Could not create usd reader\n"); + modifier_setError(md, "Could not create USD reader for file %s", cache_file->filepath); + return mesh; + } + } + + /* If this invocation is for the ORCO mesh, and the mesh in Alembic hasn't changed topology, + * we must return the mesh as-is instead of deforming it. */ + if (ctx->flag & MOD_APPLY_ORCO && + !USD_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time * FPS, &err_str)) { + printf("ORCO and no topology changed\n"); + return mesh; + } + + if (me != NULL) { + MVert *mvert = mesh->mvert; + MEdge *medge = mesh->medge; + MPoly *mpoly = mesh->mpoly; + + /* TODO(sybren+bastien): possibly check relevant custom data layers (UV/color depending on + * flags) and duplicate those too. */ + if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { + /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ + BKE_id_copy_ex(NULL, + &mesh->id, + (ID **)&mesh, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW); + } + } + + Mesh *usd_result = USD_read_mesh( + mcmd->reader, ctx->object, mesh, time * FPS, &err_str, mcmd->read_flag, mcmd->vel_fac); + if (err_str) { + modifier_setError(md, "%s", err_str); + } + + if (!ELEM(usd_result, NULL, mesh) && (mesh != org_mesh)) { + BKE_id_free(NULL, mesh); + mesh = org_mesh; + } + + return usd_result ? usd_result : mesh; + break; +# endif + default: + return NULL; + break; + } #else UNUSED_VARS(ctx, md); return mesh; @@ -187,7 +266,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * static bool dependsOnTime(ModifierData *md) { -#ifdef WITH_ALEMBIC +#if defined(WITH_USD) || defined(WITH_ALEMBIC) MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; return (mcmd->cache_file != NULL); #else |