diff options
author | Michael Kowalski <makowalski> | 2021-08-03 12:55:53 +0300 |
---|---|---|
committer | Sybren A. Stüvel <sybren@blender.org> | 2021-08-03 13:33:36 +0300 |
commit | ea54cbe1b42efb3107285c89685f555c06997062 (patch) | |
tree | bfaf0cb2315172e330c982ae081a4299cc3dc82b /source/blender/io/usd/intern/usd_reader_xform.cc | |
parent | 28b9dd7b1f0a8d4ae56eafca188796936a6e3723 (diff) |
USD: add USD importer
This is an initial implementation of a USD importer.
This work is comprised of Tangent Animation's open source USD importer,
combined with features @makowalski had implemented.
The design is very similar to the approach taken in the Alembic
importer. The core functionality resides in a collection of "reader"
classes, each of which is responsible for converting an instance of a
USD prim to the corresponding Blender Object representation.
The flow of control for the conversion can be followed in the
`import_startjob()` and `import_endjob()` functions in `usd_capi.cc`.
The `USDStageReader` class is responsible for traversing the USD stage
and instantiating the appropriate readers.
Reviewed By: sybren, HooglyBoogly
Differential Revision: https://developer.blender.org/D10700
Diffstat (limited to 'source/blender/io/usd/intern/usd_reader_xform.cc')
-rw-r--r-- | source/blender/io/usd/intern/usd_reader_xform.cc | 184 |
1 files changed, 184 insertions, 0 deletions
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..eebcc5eb3d5 --- /dev/null +++ b/source/blender/io/usd/intern/usd_reader_xform.cc @@ -0,0 +1,184 @@ +/* + * 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. + * + * Adapted from the Blender Alembic importer implementation. + * + * Modifications Copyright (C) 2021 Tangent Animation. + * All rights reserved. + */ + +#include "usd_reader_xform.h" + +#include "BKE_constraint.h" +#include "BKE_lib_id.h" +#include "BKE_library.h" +#include "BKE_modifier.h" +#include "BKE_object.h" + +#include "BLI_math_geom.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_cachefile_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 <pxr/base/gf/math.h> +#include <pxr/base/gf/matrix4f.h> + +#include <pxr/usd/usdGeom/xform.h> + +namespace blender::io::usd { + +void USDXformReader::create_object(Main *bmain, const double /* motionSampleTime */) +{ + object_ = BKE_object_add_only_object(bmain, OB_EMPTY, name_.c_str()); + object_->empty_drawsize = 0.1f; + object_->data = nullptr; +} + +void USDXformReader::read_object_data(Main * /* bmain */, const double motionSampleTime) +{ + bool is_constant; + float transform_from_usd[4][4]; + + read_matrix(transform_from_usd, motionSampleTime, import_params_.scale, &is_constant); + + if (!is_constant) { + bConstraint *con = BKE_constraint_add_for_object( + object_, nullptr, CONSTRAINT_TYPE_TRANSFORM_CACHE); + bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data); + + std::string prim_path = use_parent_xform_ ? prim_.GetParent().GetPath().GetAsString() : + prim_path_; + + BLI_strncpy(data->object_path, prim_path.c_str(), FILE_MAX); + + data->cache_file = settings_->cache_file; + id_us_plus(&data->cache_file->id); + } + + BKE_object_apply_mat4(object_, transform_from_usd, true, false); +} + +void USDXformReader::read_matrix(float r_mat[4][4] /* local matrix */, + const float time, + const float scale, + bool *r_is_constant) +{ + if (r_is_constant) { + *r_is_constant = true; + } + + unit_m4(r_mat); + + pxr::UsdGeomXformable xformable; + + if (use_parent_xform_) { + xformable = pxr::UsdGeomXformable(prim_.GetParent()); + } + else { + xformable = pxr::UsdGeomXformable(prim_); + } + + if (!xformable) { + /* This might happen if the prim is a Scope. */ + return; + } + + if (r_is_constant) { + *r_is_constant = !xformable.TransformMightBeTimeVarying(); + } + + pxr::GfMatrix4d usd_local_xf; + bool reset_xform_stack; + xformable.GetLocalTransformation(&usd_local_xf, &reset_xform_stack, time); + + /* Convert the result to a float matrix. */ + pxr::GfMatrix4f mat4f = pxr::GfMatrix4f(usd_local_xf); + mat4f.Get(r_mat); + + /* Apply global scaling and rotation only to root objects, parenting + * will propagate it. */ + if ((scale != 1.0 || settings_->do_convert_mat) && is_root_xform_) { + + if (scale != 1.0f) { + float scale_mat[4][4]; + scale_m4_fl(scale_mat, scale); + mul_m4_m4m4(r_mat, scale_mat, r_mat); + } + + if (settings_->do_convert_mat) { + mul_m4_m4m4(r_mat, settings_->conversion_mat, r_mat); + } + } +} + +bool USDXformReader::prim_has_xform_ops() const +{ + pxr::UsdGeomXformable xformable(prim_); + + if (!xformable) { + /* This might happen if the prim is a Scope. */ + return false; + } + + bool reset_xform_stack = false; + + return !xformable.GetOrderedXformOps(&reset_xform_stack).empty(); +} + +bool USDXformReader::is_root_xform_prim() const +{ + if (!prim_.IsValid()) { + return false; + } + + if (prim_.IsInMaster()) { + /* We don't consider prototypes to be root prims, + * because we never want to apply global scaling + * or rotations to the prototypes themselves. */ + return false; + } + + if (prim_.IsA<pxr::UsdGeomXformable>()) { + /* If this prim doesn't have an ancestor that's a + * UsdGeomXformable, then it's a root prim. Note + * that it's not sufficient to only check the immediate + * parent prim, since the immediate parent could be a + * UsdGeomScope that has an xformable ancestor. */ + pxr::UsdPrim cur_parent = prim_.GetParent(); + + if (use_parent_xform_) { + cur_parent = cur_parent.GetParent(); + } + + while (cur_parent && !cur_parent.IsPseudoRoot()) { + if (cur_parent.IsA<pxr::UsdGeomXformable>()) { + return false; + } + cur_parent = cur_parent.GetParent(); + } + + /* We didn't find an xformable ancestor. */ + return true; + } + + return false; +} + +} // namespace blender::io::usd |