Blender V5.0
usd_writer_transform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
6
7#include <pxr/base/gf/matrix4d.h>
8#include <pxr/base/gf/matrix4f.h>
9#include <pxr/usd/usdGeom/xform.h>
10
11#include "BKE_object.hh"
12
13#include "BLI_math_matrix.h"
14#include "BLI_math_rotation.h"
15#include "BLI_string.h"
16#include "BLI_vector.hh"
17
18#include "CLG_log.h"
19static CLG_LogRef LOG = {"io.usd"};
20
21namespace blender::io::usd {
22
24
25pxr::UsdGeomXformable USDTransformWriter::create_xformable() const
26{
27 pxr::UsdGeomXform xform;
28
29 /* If prim exists, cast to #UsdGeomXform
30 * (Solves merge transform and shape issue for animated exports). */
31 pxr::UsdPrim existing_prim = usd_export_context_.stage->GetPrimAtPath(
32 usd_export_context_.usd_path);
33 if (existing_prim.IsValid() && existing_prim.IsA<pxr::UsdGeomXform>()) {
34 xform = pxr::UsdGeomXform(existing_prim);
35 }
36 else {
37 xform = pxr::UsdGeomXform::Define(usd_export_context_.stage, usd_export_context_.usd_path);
38 }
39
40 return pxr::UsdGeomXformable(xform.GetPrim());
41}
42
44{
45 if (!(usd_export_context_.export_params.convert_orientation ||
46 usd_export_context_.export_params.convert_scene_units))
47 {
48 return false;
49 }
50
51 if (!usd_export_context_.export_params.root_prim_path.empty()) {
52 return false;
53 }
54
55 if (context.export_parent != nullptr) {
56 return false;
57 }
58
59 return true;
60}
61
63{
64 if (context.is_point_proto || context.is_point_instance) {
65 return;
66 }
67
68 constexpr float UNIT_M4[4][4] = {
69 {1, 0, 0, 0},
70 {0, 1, 0, 0},
71 {0, 0, 1, 0},
72 {0, 0, 0, 1},
73 };
74
75 pxr::UsdGeomXformable xform = create_xformable();
76
77 if (!xform) {
78 CLOG_ERROR(&LOG, "USDTransformWriter: couldn't create xformable");
79 return;
80 }
81
82 float parent_relative_matrix[4][4]; /* The object matrix relative to the parent. */
83
84 if (should_apply_root_xform(context)) {
85 float matrix_world[4][4];
86 copy_m4_m4(matrix_world, context.matrix_world);
87
88 if (usd_export_context_.export_params.convert_orientation) {
89 float mrot[3][3];
90 float mat[4][4];
93 usd_export_context_.export_params.forward_axis,
94 usd_export_context_.export_params.up_axis,
95 mrot);
96 transpose_m3(mrot);
97 copy_m4_m3(mat, mrot);
98 mul_m4_m4m4(matrix_world, mat, context.matrix_world);
99 }
100
101 if (usd_export_context_.export_params.convert_scene_units !=
103 {
104 float scale_mat[4][4];
105 scale_m4_fl(scale_mat, float(1.0 / get_meters_per_unit(usd_export_context_.export_params)));
106 mul_m4_m4m4(matrix_world, scale_mat, matrix_world);
107 }
108
109 mul_m4_m4m4(parent_relative_matrix, context.parent_matrix_inv_world, matrix_world);
110 }
111 else {
112 mul_m4_m4m4(parent_relative_matrix, context.parent_matrix_inv_world, context.matrix_world);
113 }
114
115 /* USD Xforms are by default the identity transform; only write if necessary when static. */
116 if (is_animated_ || !compare_m4m4(parent_relative_matrix, UNIT_M4, 0.000000001f)) {
117 set_xform_ops(parent_relative_matrix, xform);
118 }
119
120 if (usd_export_context_.export_params.use_instancing && context.is_instance()) {
121 mark_as_instance(context, xform.GetPrim());
122 }
123
124 if (context.object) {
125 auto prim = xform.GetPrim();
126 write_id_properties(prim, context.object->id, get_export_time_code());
127 }
128}
129
131{
132 if (context.duplicator != nullptr) {
133 /* This object is being duplicated, so could be emitted by a particle system and thus
134 * influenced by forces. TODO(Sybren): Make this more strict. Probably better to get from the
135 * depsgraph whether this object instance has a time source. */
136 return true;
137 }
138 if (check_has_physics(context)) {
139 return true;
140 }
141 return BKE_object_moves_in_time(context.object, context.animation_check_include_parent);
142}
143
144void USDTransformWriter::set_xform_ops(float parent_relative_matrix[4][4],
145 const pxr::UsdGeomXformable &xf)
146{
147 if (!xf) {
148 return;
149 }
150
151 eUSDXformOpMode xfOpMode = usd_export_context_.export_params.xform_op_mode;
152
153 if (xformOps_.is_empty()) {
154 switch (xfOpMode) {
155 case USD_XFORM_OP_TRS:
156 xformOps_.append(xf.AddTranslateOp());
157 xformOps_.append(xf.AddRotateXYZOp());
158 xformOps_.append(xf.AddScaleOp());
159 break;
160 case USD_XFORM_OP_TOS:
161 xformOps_.append(xf.AddTranslateOp());
162 xformOps_.append(xf.AddOrientOp());
163 xformOps_.append(xf.AddScaleOp());
164 break;
165 case USD_XFORM_OP_MAT:
166 xformOps_.append(xf.AddTransformOp());
167 break;
168 default:
169 CLOG_WARN(&LOG, "Unknown XformOp type");
170 xformOps_.append(xf.AddTransformOp());
171 break;
172 }
173 }
174
175 if (xformOps_.is_empty()) {
176 /* Shouldn't happen. */
177 return;
178 }
179
180 pxr::UsdTimeCode time_code = get_export_time_code();
181
182 if (xformOps_.size() == 1) {
183 pxr::GfMatrix4d mat_val(parent_relative_matrix);
184 usd_value_writer_.SetAttribute(xformOps_[0].GetAttr(), mat_val, time_code);
185 }
186 else if (xformOps_.size() == 3) {
187
188 float loc[3];
189 float quat[4];
190 float scale[3];
191
192 mat4_decompose(loc, quat, scale, parent_relative_matrix);
193
194 if (xfOpMode == USD_XFORM_OP_TRS) {
195 float rot[3];
196 quat_to_eul(rot, quat);
197 rot[0] *= 180.0 / M_PI;
198 rot[1] *= 180.0 / M_PI;
199 rot[2] *= 180.0 / M_PI;
200
201 pxr::GfVec3d loc_val(loc);
202 usd_value_writer_.SetAttribute(xformOps_[0].GetAttr(), loc_val, time_code);
203
204 pxr::GfVec3f rot_val(rot);
205 usd_value_writer_.SetAttribute(xformOps_[1].GetAttr(), rot_val, time_code);
206
207 pxr::GfVec3f scale_val(scale);
208 usd_value_writer_.SetAttribute(xformOps_[2].GetAttr(), scale_val, time_code);
209 }
210 else if (xfOpMode == USD_XFORM_OP_TOS) {
211 pxr::GfVec3d loc_val(loc);
212 usd_value_writer_.SetAttribute(xformOps_[0].GetAttr(), loc_val, time_code);
213
214 pxr::GfQuatf quat_val(quat[0], quat[1], quat[2], quat[3]);
215 usd_value_writer_.SetAttribute(xformOps_[1].GetAttr(), quat_val, time_code);
216
217 pxr::GfVec3f scale_val(scale);
218 usd_value_writer_.SetAttribute(xformOps_[2].GetAttr(), scale_val, time_code);
219 }
220 }
221}
222
223} // namespace blender::io::usd
General operations, lookup, etc. for blender objects.
bool BKE_object_moves_in_time(const Object *object, bool recurse_parent)
#define M_PI
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4])
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void scale_m4_fl(float R[4][4], float scale)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void transpose_m3(float R[3][3])
bool compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit)
void quat_to_eul(float eul[3], const float quat[4])
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
@ IO_AXIS_Y
@ IO_AXIS_Z
static bool check_has_physics(const HierarchyContext &context)
virtual bool mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim)
pxr::UsdTimeCode get_export_time_code() const
pxr::UsdUtilsSparseValueWriter usd_value_writer_
USDAbstractWriter(const USDExporterContext &usd_export_context)
void write_id_properties(const pxr::UsdPrim &prim, const ID &id, pxr::UsdTimeCode=pxr::UsdTimeCode::Default()) const
const USDExporterContext usd_export_context_
USDTransformWriter(const USDExporterContext &ctx)
bool check_is_animated(const HierarchyContext &context) const override
void do_write(HierarchyContext &context) override
void set_xform_ops(float parent_relative_matrix[4][4], const pxr::UsdGeomXformable &xf)
virtual pxr::UsdGeomXformable create_xformable() const
bool should_apply_root_xform(const HierarchyContext &context) const
#define rot(x, k)
#define LOG(level)
Definition log.h:97
@ USD_XFORM_OP_TRS
Definition usd.hh:92
@ USD_XFORM_OP_TOS
Definition usd.hh:93
@ USD_XFORM_OP_MAT
Definition usd.hh:94
@ USD_SCENE_UNITS_METERS
Definition usd.hh:118
double get_meters_per_unit(const USDExportParams &params)