Blender V4.3
usd_reader_xform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Tangent Animation. All rights reserved.
2 * SPDX-FileCopyrightText: 2023 Blender Authors
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 * Adapted from the Blender Alembic importer implementation. */
7
8#include "usd_reader_xform.hh"
9
10#include "BKE_constraint.h"
11#include "BKE_lib_id.hh"
12#include "BKE_object.hh"
13
14#include "BLI_math_matrix.h"
15#include "BLI_string.h"
16
17#include "DNA_cachefile_types.h"
19#include "DNA_object_types.h"
20
21#include <pxr/base/gf/matrix4f.h>
22#include <pxr/usd/usdGeom/xformable.h>
23
24#include <string>
25
26namespace blender::io::usd {
27
28void USDXformReader::create_object(Main *bmain, const double /*motionSampleTime*/)
29{
31 object_->empty_drawsize = 0.1f;
32 object_->data = nullptr;
33}
34
35void USDXformReader::read_object_data(Main * /*bmain*/, const double motionSampleTime)
36{
37 bool is_constant;
38 float transform_from_usd[4][4];
39
40 read_matrix(transform_from_usd, motionSampleTime, import_params_.scale, &is_constant);
41
42 if (!is_constant && settings_->get_cache_file) {
45 bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
46
47 std::string prim_path = use_parent_xform_ ? prim_.GetParent().GetPath().GetAsString() :
49
50 STRNCPY(data->object_path, prim_path.c_str());
51
52 data->cache_file = settings_->get_cache_file();
53 id_us_plus(&data->cache_file->id);
54 }
55
56 BKE_object_apply_mat4(object_, transform_from_usd, true, false);
57
58 /* Make sure to collect custom attributes */
59 set_props(use_parent_xform(), motionSampleTime);
60}
61
62void USDXformReader::read_matrix(float r_mat[4][4] /* local matrix */,
63 const float time,
64 const float scale,
65 bool *r_is_constant) const
66{
67 BLI_assert(r_mat);
68 BLI_assert(r_is_constant);
69
70 *r_is_constant = true;
71 unit_m4(r_mat);
72
73 std::optional<XformResult> xf_result = get_local_usd_xform(time);
74
75 if (!xf_result) {
76 return;
77 }
78
79 std::get<0>(*xf_result).Get(r_mat);
80 *r_is_constant = std::get<1>(*xf_result);
81
82 /* Apply global scaling and rotation only to root objects, parenting
83 * will propagate it. */
84 if ((scale != 1.0 || settings_->do_convert_mat) && is_root_xform_) {
85
86 if (scale != 1.0f) {
87 float scale_mat[4][4];
88 scale_m4_fl(scale_mat, scale);
89 mul_m4_m4m4(r_mat, scale_mat, r_mat);
90 }
91
93 mul_m4_m4m4(r_mat, settings_->conversion_mat, r_mat);
94 }
95 }
96}
97
99{
100 pxr::UsdGeomXformable xformable(prim_);
101
102 if (!xformable) {
103 /* This might happen if the prim is a Scope. */
104 return false;
105 }
106
107 bool reset_xform_stack = false;
108
109 return !xformable.GetOrderedXformOps(&reset_xform_stack).empty();
110}
111
113{
114 if (!prim_.IsValid()) {
115 return false;
116 }
117
118 if (is_in_proto()) {
119 /* We don't consider prototypes to be root prims,
120 * because we never want to apply global scaling
121 * or rotations to the prototypes themselves. */
122 return false;
123 }
124
125 if (prim_.IsA<pxr::UsdGeomXformable>()) {
126 /* If this prim doesn't have an ancestor that's a
127 * UsdGeomXformable, then it's a root prim. Note
128 * that it's not sufficient to only check the immediate
129 * parent prim, since the immediate parent could be a
130 * UsdGeomScope that has an xformable ancestor. */
131 pxr::UsdPrim cur_parent = prim_.GetParent();
132
133 if (use_parent_xform_) {
134 cur_parent = cur_parent.GetParent();
135 }
136
137 while (cur_parent && !cur_parent.IsPseudoRoot()) {
138 if (cur_parent.IsA<pxr::UsdGeomXformable>()) {
139 return false;
140 }
141 cur_parent = cur_parent.GetParent();
142 }
143
144 /* We didn't find an xformable ancestor. */
145 return true;
146 }
147
148 return false;
149}
150
151std::optional<XformResult> USDXformReader::get_local_usd_xform(const float time) const
152{
153 pxr::UsdGeomXformable xformable = use_parent_xform_ ? pxr::UsdGeomXformable(prim_.GetParent()) :
154 pxr::UsdGeomXformable(prim_);
155
156 if (!xformable) {
157 /* This might happen if the prim is a Scope. */
158 return std::nullopt;
159 }
160
161 bool is_constant = !xformable.TransformMightBeTimeVarying();
162
163 bool reset_xform_stack;
164 pxr::GfMatrix4d xform;
165 if (!xformable.GetLocalTransformation(&xform, &reset_xform_stack, time)) {
166 return std::nullopt;
167 }
168
169 /* The USD bind transform is a matrix of doubles,
170 * but we cast it to GfMatrix4f because Blender expects
171 * a matrix of floats. */
172 return XformResult(pxr::GfMatrix4f(xform), is_constant);
173}
174
175} // namespace blender::io::usd
struct bConstraint * BKE_constraint_add_for_object(struct Object *ob, const char *name, short type)
void id_us_plus(ID *id)
Definition lib_id.cc:351
General operations, lookup, etc. for blender objects.
void BKE_object_apply_mat4(Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
#define BLI_assert(a)
Definition BLI_assert.h:50
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void unit_m4(float m[4][4])
Definition rct.c:1127
void scale_m4_fl(float R[4][4], float scale)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
@ CONSTRAINT_TYPE_TRANSFORM_CACHE
Object is a sort of wrapper for general info.
@ OB_EMPTY
const std::string & prim_path() const
const ImportSettings * settings_
void set_props(bool merge_with_parent=false, pxr::UsdTimeCode motionSampleTime=pxr::UsdTimeCode::Default())
const USDImportParams & import_params_
void create_object(Main *bmain, double motionSampleTime) override
void read_object_data(Main *bmain, double motionSampleTime) override
virtual std::optional< XformResult > get_local_usd_xform(float time) const
void read_matrix(float r_mat[4][4], float time, float scale, bool *r_is_constant) const
std::tuple< pxr::GfMatrix4f, bool > XformResult
float empty_drawsize
std::function< CacheFile *()> get_cache_file