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
185 lines
5.1 KiB
C++
185 lines
5.1 KiB
C++
/*
|
|
* 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
|