diff options
author | makowalski <makowalski@nvidia.com> | 2020-12-07 07:36:37 +0300 |
---|---|---|
committer | makowalski <makowalski@nvidia.com> | 2020-12-07 07:36:37 +0300 |
commit | 082cb1656f3c52ce3716c8672ab5f3c561497714 (patch) | |
tree | c1366fcbe9a19c9c5f68752406c5c1d4f43f9974 | |
parent | c009ab8e7d12e5f96b3f748187e5049fb413cb46 (diff) |
USD importer: transform cache constraint.
Port of Tangent Animation's implementation of transform
cache constraint for USD (adapted and modified to fit
this version of the importer).
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cachefile.c | 227 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 21 | ||||
-rw-r--r-- | source/blender/io/alembic/ABC_alembic.h | 12 | ||||
-rw-r--r-- | source/blender/io/alembic/intern/alembic_capi.cc | 28 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_prim_iterator.cc | 47 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_prim_iterator.h | 14 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_reader_camera.cc | 5 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_reader_camera.h | 5 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_reader_light.cc | 5 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_reader_light.h | 5 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_reader_xformable.cc | 57 | ||||
-rw-r--r-- | source/blender/io/usd/import/usd_reader_xformable.h | 20 | ||||
-rw-r--r-- | source/blender/io/usd/intern/usd_capi.cc | 193 | ||||
-rw-r--r-- | source/blender/io/usd/usd.h | 35 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_cachefile_types.h | 27 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_cachefile.c | 12 |
17 files changed, 608 insertions, 112 deletions
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index cc5226a1ab7..68f7aa11a03 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -657,6 +657,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 9475ba7efcf..8e3f071d3e9 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) @@ -160,89 +164,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( + (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_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((CacheArchiveHandle *)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) @@ -291,8 +384,18 @@ 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 = 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 = USD_create_handle(bmain, filepath, &cache_file->object_paths); + BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); + } #endif if (DEG_is_active(depsgraph)) { diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 601704fc8c5..b91f232c5d4 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -89,6 +89,10 @@ # include "ABC_alembic.h" #endif +#ifdef WITH_USD +# include "usd.h" +#endif + /* ---------------------------------------------------------------------------- */ /* Useful macros for testing various common flag combinations */ @@ -5160,7 +5164,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; @@ -5178,7 +5182,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/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index 9785f6d68ab..6faf763f8a5 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, - const char *filename, - struct ListBase *object_paths); +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 eba7f64db02..7dbdb44407a 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -88,18 +88,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 @@ -149,8 +145,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); @@ -159,9 +155,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); @@ -177,7 +173,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); } @@ -358,8 +354,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); @@ -827,7 +823,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/import/usd_prim_iterator.cc b/source/blender/io/usd/import/usd_prim_iterator.cc index 946e4c05f4e..4cf353bf8a3 100644 --- a/source/blender/io/usd/import/usd_prim_iterator.cc +++ b/source/blender/io/usd/import/usd_prim_iterator.cc @@ -28,6 +28,12 @@ #include "usd_reader_xform.h" #include "usd_reader_xformable.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "DNA_cachefile_types.h" + +#include "MEM_guardedalloc.h" + #include <iostream> #include <pxr/pxr.h> #include <pxr/usd/usd/prim.h> @@ -49,6 +55,18 @@ USDPrimIterator::USDPrimIterator(pxr::UsdStageRefPtr stage, { } +USDPrimIterator::USDPrimIterator(const char *file_path, + const USDImporterContext &context, + Main *bmain) + : stage_(pxr::UsdStage::Open(file_path)), context_(context), bmain_(bmain) +{ +} + +bool USDPrimIterator::valid() const +{ + return stage_; +} + void USDPrimIterator::create_object_readers(std::vector<USDXformableReader *> &r_readers) const { if (!stage_) { @@ -90,6 +108,11 @@ void USDPrimIterator::debug_traverse_stage() const debug_traverse_stage(stage_); } +USDXformableReader *USDPrimIterator::get_object_reader(const pxr::UsdPrim &prim) +{ + return get_object_reader(prim, context_); +} + USDXformableReader *USDPrimIterator::get_object_reader(const pxr::UsdPrim &prim, const USDImporterContext &context) { @@ -126,7 +149,9 @@ void USDPrimIterator::create_object_readers(const pxr::UsdPrim &prim, pxr::UsdPrimSiblingRange child_prims = prim.GetFilteredChildren( pxr::UsdTraverseInstanceProxies(pxr::UsdPrimDefaultPredicate)); + int num_child_prims = 0; for (const pxr::UsdPrim &child_prim : child_prims) { + ++num_child_prims; create_object_readers(child_prim, context, r_readers, child_readers); } @@ -144,7 +169,7 @@ void USDPrimIterator::create_object_readers(const pxr::UsdPrim &prim, /* If this is an Xform prim, see if we can merge with the child reader. */ - if (prim.IsA<pxr::UsdGeomXform>() && child_readers.size() == 1 && + if (prim.IsA<pxr::UsdGeomXform>() && num_child_prims == 1 && !child_readers.front()->merged_with_parent() && child_readers.front()->can_merge_with_parent()) { child_readers.front()->set_merged_with_parent(true); @@ -209,6 +234,26 @@ void USDPrimIterator::cache_prototype_data(USDDataCache &r_cache) const } } +bool USDPrimIterator::gather_objects_paths(ListBase *object_paths) const +{ + if (!stage_) { + return false; + } + + pxr::UsdPrimRange prims = stage_->Traverse( + pxr::UsdTraverseInstanceProxies(pxr::UsdPrimDefaultPredicate)); + + for (const pxr::UsdPrim &prim : prims) { + void *usd_path_void = MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath"); + CacheObjectPath *usd_path = static_cast<CacheObjectPath *>(usd_path_void); + + BLI_strncpy(usd_path->path, prim.GetPrimPath().GetString().c_str(), sizeof(usd_path->path)); + BLI_addtail(object_paths, usd_path); + } + + return true; +} + void USDPrimIterator::debug_traverse_stage(const pxr::UsdStageRefPtr &usd_stage) { if (!usd_stage) { diff --git a/source/blender/io/usd/import/usd_prim_iterator.h b/source/blender/io/usd/import/usd_prim_iterator.h index 1605d919051..2cdd361381e 100644 --- a/source/blender/io/usd/import/usd_prim_iterator.h +++ b/source/blender/io/usd/import/usd_prim_iterator.h @@ -23,6 +23,7 @@ #include <pxr/usd/usd/common.h> #include <map> +#include <set> #include <vector> struct Main; @@ -41,6 +42,15 @@ class USDPrimIterator { public: USDPrimIterator(pxr::UsdStageRefPtr stage, const USDImporterContext &context, Main *bmain); + USDPrimIterator(const char *file_path, const USDImporterContext &context, Main *bmain); + + bool valid() const; + + pxr::UsdStageRefPtr stage() const + { + return stage_; + } + void create_object_readers(std::vector<USDXformableReader *> &r_readers) const; void create_prototype_object_readers( @@ -48,8 +58,12 @@ class USDPrimIterator { void cache_prototype_data(USDDataCache &r_cache) const; + bool gather_objects_paths(ListBase *object_paths) const; + void debug_traverse_stage() const; + USDXformableReader *get_object_reader(const pxr::UsdPrim &prim); + static USDXformableReader *get_object_reader(const pxr::UsdPrim &prim, const USDImporterContext &context); diff --git a/source/blender/io/usd/import/usd_reader_camera.cc b/source/blender/io/usd/import/usd_reader_camera.cc index 418d6a4ee77..cb574730ad7 100644 --- a/source/blender/io/usd/import/usd_reader_camera.cc +++ b/source/blender/io/usd/import/usd_reader_camera.cc @@ -110,9 +110,10 @@ void USDCameraReader::create_object(Main *bmain, double time, USDDataCache *data void USDCameraReader::read_matrix(float r_mat[4][4] /* local matrix */, const double time, - const float scale) const + const float scale, + bool &is_constant) const { - USDXformableReader::read_matrix(r_mat, time, scale); + USDXformableReader::read_matrix(r_mat, time, scale, is_constant); /* Conveting from y-up to z-up requires adjusting * the camera rotation. */ diff --git a/source/blender/io/usd/import/usd_reader_camera.h b/source/blender/io/usd/import/usd_reader_camera.h index 85e71e66bea..0609a7240b7 100644 --- a/source/blender/io/usd/import/usd_reader_camera.h +++ b/source/blender/io/usd/import/usd_reader_camera.h @@ -37,7 +37,10 @@ class USDCameraReader : public USDXformableReader { void create_object(Main *bmain, double time, USDDataCache *data_cache) override; - void read_matrix(float r_mat[4][4], const double time, const float scale) const override; + void read_matrix(float r_mat[4][4], + const double time, + const float scale, + bool &is_constant) const override; }; } // namespace blender::io::usd diff --git a/source/blender/io/usd/import/usd_reader_light.cc b/source/blender/io/usd/import/usd_reader_light.cc index a006523b2ec..26903f45d94 100644 --- a/source/blender/io/usd/import/usd_reader_light.cc +++ b/source/blender/io/usd/import/usd_reader_light.cc @@ -161,9 +161,10 @@ void USDLightReader::create_object(Main *bmain, double time, USDDataCache *data_ void USDLightReader::read_matrix(float r_mat[4][4] /* local matrix */, const double time, - const float scale) const + const float scale, + bool &is_constant) const { - USDXformableReader::read_matrix(r_mat, time, scale); + USDXformableReader::read_matrix(r_mat, time, scale, is_constant); /* Conveting from y-up to z-up requires adjusting * the light rotation. */ diff --git a/source/blender/io/usd/import/usd_reader_light.h b/source/blender/io/usd/import/usd_reader_light.h index db061c9f101..159bffcd1b0 100644 --- a/source/blender/io/usd/import/usd_reader_light.h +++ b/source/blender/io/usd/import/usd_reader_light.h @@ -37,7 +37,10 @@ class USDLightReader : public USDXformableReader { void create_object(Main *bmain, double time, USDDataCache *data_cache) override; - void read_matrix(float r_mat[4][4], const double time, const float scale) const override; + void read_matrix(float r_mat[4][4], + const double time, + const float scale, + bool &is_constant) const override; }; } // namespace blender::io::usd diff --git a/source/blender/io/usd/import/usd_reader_xformable.cc b/source/blender/io/usd/import/usd_reader_xformable.cc index f39abf802d4..539b388438a 100644 --- a/source/blender/io/usd/import/usd_reader_xformable.cc +++ b/source/blender/io/usd/import/usd_reader_xformable.cc @@ -20,17 +20,22 @@ #include "usd_reader_xformable.h" #include "usd_import_util.h" +#include "BKE_constraint.h" #include "BKE_lib_id.h" #include "BKE_object.h" +#include "DNA_cachefile_types.h" +#include "DNA_constraint_types.h" #include "DNA_object_types.h" #include "BLI_listbase.h" #include "BLI_math_geom.h" +#include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_utildefines.h" #include <pxr/base/gf/matrix4d.h> #include <pxr/base/gf/matrix4f.h> +#include <pxr/usd/usdGeom/xform.h> #include <pxr/usd/usdGeom/xformable.h> #include <iostream> @@ -51,27 +56,65 @@ Object *USDXformableReader::object() const return object_; } -void USDXformableReader::set_object_transform(const double time) +void USDXformableReader::eval_merged_with_parent() { - if (!this->object_) { + merged_with_parent_ = false; + if (valid() && can_merge_with_parent()) { + pxr::UsdPrim parent = prim_.GetParent(); + + // Merge with the parent if the parent is an Xform and has only one child. + if (parent && !parent.IsPseudoRoot() && parent.IsA<pxr::UsdGeomXform>()) { + + pxr::UsdPrimSiblingRange child_prims = parent.GetFilteredChildren( + pxr::UsdTraverseInstanceProxies(pxr::UsdPrimDefaultPredicate)); + + // Unfortunately, we need to iterate over the child primitives + // to count them. + int num_child_prims = 0; + for (const pxr::UsdPrim &child_prim : child_prims) { + ++num_child_prims; + if (num_child_prims > 1) { + break; + } + } + merged_with_parent_ = num_child_prims == 1; + } + } +} + +void USDXformableReader::set_object_transform(const double time, CacheFile *cache_file) +{ + if (!object_) { return; } float transform_from_usd[4][4]; + bool is_constant = true; - this->read_matrix(transform_from_usd, time, this->context_.import_params.scale); + this->read_matrix(transform_from_usd, time, this->context_.import_params.scale, is_constant); /* Apply the matrix to the object. */ BKE_object_apply_mat4(object_, transform_from_usd, true, false); BKE_object_to_mat4(object_, object_->obmat); - /* TODO(makowalski): Set up transform constraint if not constant. */ + if (cache_file && !is_constant) { + bConstraint *con = BKE_constraint_add_for_object( + object_, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); + bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data); + BLI_strncpy(data->object_path, this->prim_path().c_str(), FILE_MAX); + + data->cache_file = cache_file; + id_us_plus(&data->cache_file->id); + } } void USDXformableReader::read_matrix(float r_mat[4][4] /* local matrix */, const double time, - const float scale) const + const float scale, + bool &is_constant) const { + is_constant = true; + pxr::UsdGeomXformable xformable(prim_); if (!xformable) { @@ -79,6 +122,8 @@ void USDXformableReader::read_matrix(float r_mat[4][4] /* local matrix */, return; } + is_constant = !xformable.TransformMightBeTimeVarying(); + pxr::GfMatrix4d usd_local_xf; bool reset_xform_stack; xformable.GetLocalTransformation(&usd_local_xf, &reset_xform_stack, time); @@ -88,6 +133,8 @@ void USDXformableReader::read_matrix(float r_mat[4][4] /* local matrix */, pxr::UsdGeomXformable parent_xformable(prim_.GetParent()); if (parent_xformable) { + is_constant = is_constant && !parent_xformable.TransformMightBeTimeVarying(); + pxr::GfMatrix4d usd_parent_local_xf; parent_xformable.GetLocalTransformation(&usd_parent_local_xf, &reset_xform_stack, time); diff --git a/source/blender/io/usd/import/usd_reader_xformable.h b/source/blender/io/usd/import/usd_reader_xformable.h index e9b7dc49ea6..4f21f153482 100644 --- a/source/blender/io/usd/import/usd_reader_xformable.h +++ b/source/blender/io/usd/import/usd_reader_xformable.h @@ -25,6 +25,7 @@ #include <string> #include <vector> +struct CacheFile; struct Main; struct Mesh; struct Object; @@ -52,6 +53,11 @@ class USDXformableReader : public USDPrimReader { Object *object() const; + void set_object(Object *object) + { + object_ = object; + } + USDXformableReader *parent() const { return parent_; @@ -72,6 +78,13 @@ class USDXformableReader : public USDPrimReader { return merged_with_parent_; } + /* Determines whether or not this reader takes into + * account the encapsulated USD primitive's parent when + * computing the object's transform and sets the value + * of the merged_with_parent_ flag accordingly. Note that + * this function may be expensive to compute. */ + void eval_merged_with_parent(); + std::string get_object_name() const { return merged_with_parent_ ? this->parent_prim_name() : this->prim_name(); @@ -91,9 +104,12 @@ class USDXformableReader : public USDPrimReader { return true; } - void set_object_transform(const double time); + void set_object_transform(const double time, CacheFile *cache_file = nullptr); - virtual void read_matrix(float r_mat[4][4], const double time, const float scale) const; + virtual void read_matrix(float r_mat[4][4], + const double time, + const float scale, + bool &is_constant) const; }; } /* namespace blender::io::usd */ diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc index 06d634f8d1d..74b281807b5 100644 --- a/source/blender/io/usd/intern/usd_capi.cc +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -63,6 +63,8 @@ #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_screen.h" + +#include "DNA_cachefile_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -79,6 +81,36 @@ namespace blender::io::usd { +USDPrimIterator *archive_from_handle(CacheArchiveHandle *handle) +{ + return reinterpret_cast<USDPrimIterator *>(handle); +} + +CacheArchiveHandle *handle_from_archive(USDPrimIterator *archive) +{ + return reinterpret_cast<CacheArchiveHandle *>(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;*/ + return false; +} + struct ExportJobData { Main *bmain; Depsgraph *depsgraph; @@ -265,6 +297,23 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa USDPrimIterator usd_prim_iter(data->stage, import_ctx, data->bmain); + 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. */ + /* TODO(makowalski): rather than decrementing the use count, should + * we just call BKE_id_free_us() on the cache_file id when cleaning up? */ + 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; + // Optionally print the stage contents for debugging. if (data->params.debug) { usd_prim_iter.debug_traverse_stage(); @@ -333,7 +382,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa i = 0; for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { USDXformableReader *reader = *iter; - reader->set_object_transform(time); + reader->set_object_transform(time, cache_file); *data->progress = 0.7f + 0.3f * (++i / size); *data->do_update = true; @@ -552,3 +601,145 @@ int USD_get_version(void) */ return PXR_VERSION; } + +static blender::io::usd::USDPrimReader *get_usd_reader(CacheReader *reader, + Object *ob, + const char **err_str) +{ + blender::io::usd::USDPrimReader *usd_reader = + reinterpret_cast<blender::io::usd::USDPrimReader *>(reader); + pxr::UsdPrim iobject = usd_reader->prim(); + + if (!iobject.IsValid()) { + *err_str = "Invalid object: verify object path"; + 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) +{ + blender::io::usd::USDPrimReader *usd_reader = + reinterpret_cast<blender::io::usd::USDPrimReader *>(reader); + usd_reader->incref(); +} + +CacheReader *CacheReader_open_usd_object(CacheArchiveHandle *handle, + CacheReader *reader, + Object *object, + const char *object_path) +{ + if (object_path[0] == '\0') { + return reader; + } + + blender::io::usd::USDPrimIterator *archive = blender::io::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); + } + + blender::io::usd::USDXformableReader *usd_reader = archive->get_object_reader(prim); + + if (!usd_reader) { + /* This object is not supported */ + return nullptr; + } + + if (!usd_reader->valid()) { + std::cerr << "WARNING: cache reader attempting to open invalid object " << object_path + << std::endl; + return nullptr; + } + + usd_reader->eval_merged_with_parent(); + + usd_reader->set_object(object); + return reinterpret_cast<CacheReader *>(usd_reader); +} + +void USDCacheReader_free(CacheReader *reader) +{ + blender::io::usd::USDPrimReader *usd_reader = + reinterpret_cast<blender::io::usd::USDPrimReader *>(reader); + usd_reader->decref(); +} + +CacheArchiveHandle *USD_create_handle(struct Main *bmain, + const char *filename, + ListBase *object_paths) +{ + pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(filename); + if (!stage) { + std::cerr << "WARNING: Couldn't open '" << filename << "' when creating USD archive handle\n"; + return nullptr; + } + + // TODO(makowalski): Need to account for all import parameters. + pxr::TfToken up_axis = pxr::UsdGeomGetStageUpAxis(stage); + blender::io::usd::USDImporterContext import_ctx{up_axis, USDImportParams{}}; + + blender::io::usd::USDPrimIterator *archive = new blender::io::usd::USDPrimIterator( + stage, import_ctx, bmain); + + if (object_paths) { + archive->gather_objects_paths(object_paths); + } + + return blender::io::usd::handle_from_archive(archive); +} + +void USD_free_handle(CacheArchiveHandle *handle) +{ + blender::io::usd::USDPrimIterator *archive = blender::io::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; + } + + blender::io::usd::USDXformableReader *usd_reader = + reinterpret_cast<blender::io::usd::USDXformableReader *>(reader); + + bool is_constant = false; + usd_reader->read_matrix(r_mat, time, scale, is_constant); +} diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index d42cc9152b4..d993d7d62cf 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -28,6 +28,8 @@ extern "C" { struct Scene; struct bContext; +typedef struct CacheArchiveHandle CacheArchiveHandle; + struct USDExportParams { bool export_animation; bool export_hair; @@ -81,6 +83,39 @@ bool USD_import(struct bContext *C, int USD_get_version(void); +// ----- USD Import and Mesh Cache interface + +CacheArchiveHandle *USD_create_handle(struct Main *bmain, + const char *filename, + struct ListBase *object_paths); + +void USD_free_handle(CacheArchiveHandle *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 CacheArchiveHandle *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_types.h b/source/blender/makesdna/DNA_cachefile_types.h index 04c99c6c4b1..e4209461a46 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. */ @@ -84,14 +99,16 @@ typedef struct CacheFile { short flag; short draw_flag; /* UNUSED */ - char _pad[3]; + char type; + + 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/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"); |