Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormakowalski <makowalski@nvidia.com>2020-12-07 07:36:37 +0300
committermakowalski <makowalski@nvidia.com>2020-12-07 07:36:37 +0300
commit082cb1656f3c52ce3716c8672ab5f3c561497714 (patch)
treec1366fcbe9a19c9c5f68752406c5c1d4f43f9974
parentc009ab8e7d12e5f96b3f748187e5049fb413cb46 (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.txt7
-rw-r--r--source/blender/blenkernel/intern/cachefile.c227
-rw-r--r--source/blender/blenkernel/intern/constraint.c21
-rw-r--r--source/blender/io/alembic/ABC_alembic.h12
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc28
-rw-r--r--source/blender/io/usd/import/usd_prim_iterator.cc47
-rw-r--r--source/blender/io/usd/import/usd_prim_iterator.h14
-rw-r--r--source/blender/io/usd/import/usd_reader_camera.cc5
-rw-r--r--source/blender/io/usd/import/usd_reader_camera.h5
-rw-r--r--source/blender/io/usd/import/usd_reader_light.cc5
-rw-r--r--source/blender/io/usd/import/usd_reader_light.h5
-rw-r--r--source/blender/io/usd/import/usd_reader_xformable.cc57
-rw-r--r--source/blender/io/usd/import/usd_reader_xformable.h20
-rw-r--r--source/blender/io/usd/intern/usd_capi.cc193
-rw-r--r--source/blender/io/usd/usd.h35
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h27
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c12
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");