USD Export: Added option to specify types of XForm ops written.
Different pipelines standardize on different XForm op setups (T-R-S, T-orient quat-S, Matrix). Having this options means that this standard can be chosen at export time instead of having to patch on load. Speaking from experience, this is a very helpful option. Co-authored-by: kiki <charles@skeletalstudios.com> Pull Request: https://projects.blender.org/blender/blender/pulls/121627
This commit is contained in:
committed by
Jesse Yurkovich
parent
ac33b9f693
commit
36f1a4f94f
@@ -129,6 +129,21 @@ const EnumPropertyItem rna_enum_usd_export_subdiv_mode_items[] = {
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_usd_xform_op_mode_items[] = {
|
||||
{USD_XFORM_OP_TRS,
|
||||
"TRS",
|
||||
0,
|
||||
"Translate, Rotate, Scale",
|
||||
"Export with translate, rotate, and scale Xform operators"},
|
||||
{USD_XFORM_OP_TOS,
|
||||
"TOS",
|
||||
0,
|
||||
"Translate, Orient, Scale",
|
||||
"Export with translate, orient quaternion, and scale Xform operators"},
|
||||
{USD_XFORM_OP_MAT, "MAT", 0, "Matrix", "Export matrix operator"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
|
||||
* This is set when the operator is invoked, and not set when it is only executed. */
|
||||
enum { AS_BACKGROUND_JOB = 1 };
|
||||
@@ -215,6 +230,8 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
|
||||
const int global_forward = RNA_enum_get(op->ptr, "export_global_forward_selection");
|
||||
const int global_up = RNA_enum_get(op->ptr, "export_global_up_selection");
|
||||
|
||||
const eUSDXformOpMode xform_op_mode = eUSDXformOpMode(RNA_enum_get(op->ptr, "xform_op_mode"));
|
||||
|
||||
char root_prim_path[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "root_prim_path", root_prim_path);
|
||||
process_prim_path(root_prim_path);
|
||||
@@ -243,6 +260,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
|
||||
convert_orientation,
|
||||
eIOAxis(global_forward),
|
||||
eIOAxis(global_up),
|
||||
xform_op_mode,
|
||||
};
|
||||
|
||||
STRNCPY(params.root_prim_path, root_prim_path);
|
||||
@@ -269,6 +287,9 @@ static void wm_usd_export_draw(bContext *C, wmOperator *op)
|
||||
uiItemR(col, ptr, "visible_objects_only", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
col = uiLayoutColumn(box, true);
|
||||
uiItemR(col, ptr, "xform_op_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
|
||||
col = uiLayoutColumn(box, true);
|
||||
uiItemR(col, ptr, "export_animation", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "export_hair", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
@@ -523,6 +544,13 @@ void WM_OT_usd_export(wmOperatorType *ot)
|
||||
"Use relative paths to reference external files (i.e. textures, volumes) in "
|
||||
"USD, otherwise use absolute paths");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"xform_op_mode",
|
||||
rna_enum_usd_xform_op_mode_items,
|
||||
USD_XFORM_OP_TRS,
|
||||
"Xform Ops",
|
||||
"The type of transform operators to write");
|
||||
|
||||
RNA_def_string(ot->srna,
|
||||
"root_prim_path",
|
||||
"/root",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "CLG_log.h"
|
||||
static CLG_LogRef LOG = {"io.usd"};
|
||||
@@ -99,12 +100,7 @@ void USDTransformWriter::do_write(HierarchyContext &context)
|
||||
|
||||
/* USD Xforms are by default set with an identity transform; only write if necessary. */
|
||||
if (!compare_m4m4(parent_relative_matrix, UNIT_M4, 0.000000001f)) {
|
||||
if (!xformOp_) {
|
||||
xformOp_ = xform.AddTransformOp();
|
||||
}
|
||||
|
||||
pxr::GfMatrix4d mat_val(parent_relative_matrix);
|
||||
usd_value_writer_.SetAttribute(xformOp_.GetAttr(), mat_val, get_export_time_code());
|
||||
set_xform_ops(parent_relative_matrix, xform);
|
||||
}
|
||||
|
||||
if (context.object) {
|
||||
@@ -127,4 +123,82 @@ bool USDTransformWriter::check_is_animated(const HierarchyContext &context) cons
|
||||
return BKE_object_moves_in_time(context.object, context.animation_check_include_parent);
|
||||
}
|
||||
|
||||
void USDTransformWriter::set_xform_ops(float xf_matrix[4][4], pxr::UsdGeomXformable &xf)
|
||||
{
|
||||
if (!xf) {
|
||||
return;
|
||||
}
|
||||
|
||||
eUSDXformOpMode xfOpMode = usd_export_context_.export_params.xform_op_mode;
|
||||
blender::Vector<pxr::UsdGeomXformOp> xformOps;
|
||||
|
||||
switch (xfOpMode) {
|
||||
case USD_XFORM_OP_TRS:
|
||||
xformOps.append(xf.AddTranslateOp());
|
||||
xformOps.append(xf.AddRotateXYZOp());
|
||||
xformOps.append(xf.AddScaleOp());
|
||||
|
||||
break;
|
||||
case USD_XFORM_OP_TOS:
|
||||
xformOps.append(xf.AddTranslateOp());
|
||||
xformOps.append(xf.AddOrientOp());
|
||||
xformOps.append(xf.AddScaleOp());
|
||||
break;
|
||||
case USD_XFORM_OP_MAT:
|
||||
xformOps.append(xf.AddTransformOp());
|
||||
break;
|
||||
default:
|
||||
CLOG_WARN(&LOG, "Warning: unknown XformOp type\n");
|
||||
xformOps.append(xf.AddTransformOp());
|
||||
break;
|
||||
}
|
||||
|
||||
if (xformOps.is_empty()) {
|
||||
/* Shouldn't happen. */
|
||||
return;
|
||||
}
|
||||
|
||||
pxr::UsdTimeCode time_code = get_export_time_code();
|
||||
|
||||
if (xformOps.size() == 1) {
|
||||
pxr::GfMatrix4d mat_val(xf_matrix);
|
||||
usd_value_writer_.SetAttribute(xformOps[0].GetAttr(), mat_val, time_code);
|
||||
}
|
||||
else if (xformOps.size() == 3) {
|
||||
|
||||
float loc[3];
|
||||
float quat[4];
|
||||
float scale[3];
|
||||
|
||||
mat4_decompose(loc, quat, scale, xf_matrix);
|
||||
|
||||
if (xfOpMode == USD_XFORM_OP_TRS) {
|
||||
float rot[3];
|
||||
quat_to_eul(rot, quat);
|
||||
rot[0] *= 180.0 / M_PI;
|
||||
rot[1] *= 180.0 / M_PI;
|
||||
rot[2] *= 180.0 / M_PI;
|
||||
|
||||
pxr::GfVec3d loc_val(loc);
|
||||
usd_value_writer_.SetAttribute(xformOps[0].GetAttr(), loc_val, time_code);
|
||||
|
||||
pxr::GfVec3f rot_val(rot);
|
||||
usd_value_writer_.SetAttribute(xformOps[1].GetAttr(), rot_val, time_code);
|
||||
|
||||
pxr::GfVec3f scale_val(scale);
|
||||
usd_value_writer_.SetAttribute(xformOps[2].GetAttr(), scale_val, time_code);
|
||||
}
|
||||
else if (xfOpMode == USD_XFORM_OP_TOS) {
|
||||
pxr::GfVec3d loc_val(loc);
|
||||
usd_value_writer_.SetAttribute(xformOps[0].GetAttr(), loc_val, time_code);
|
||||
|
||||
pxr::GfQuatf quat_val(quat[0], quat[1], quat[2], quat[3]);
|
||||
usd_value_writer_.SetAttribute(xformOps[1].GetAttr(), quat_val, time_code);
|
||||
|
||||
pxr::GfVec3f scale_val(scale);
|
||||
usd_value_writer_.SetAttribute(xformOps[2].GetAttr(), scale_val, time_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
namespace blender::io::usd {
|
||||
|
||||
class USDTransformWriter : public USDAbstractWriter {
|
||||
private:
|
||||
pxr::UsdGeomXformOp xformOp_;
|
||||
|
||||
public:
|
||||
USDTransformWriter(const USDExporterContext &ctx);
|
||||
|
||||
@@ -20,6 +17,7 @@ class USDTransformWriter : public USDAbstractWriter {
|
||||
void do_write(HierarchyContext &context) override;
|
||||
bool check_is_animated(const HierarchyContext &context) const override;
|
||||
bool should_apply_root_xform(const HierarchyContext &context) const;
|
||||
void set_xform_ops(float parent_relative_matrix[4][4], pxr::UsdGeomXformable &xf);
|
||||
|
||||
/* Subclasses may override this to create prims other than UsdGeomXform. */
|
||||
virtual pxr::UsdGeomXformable create_xformable() const;
|
||||
|
||||
@@ -78,6 +78,12 @@ enum eSubdivExportMode {
|
||||
USD_SUBDIV_BEST_MATCH = 2,
|
||||
};
|
||||
|
||||
typedef enum eUSDXformOpMode {
|
||||
USD_XFORM_OP_TRS = 0,
|
||||
USD_XFORM_OP_TOS = 1,
|
||||
USD_XFORM_OP_MAT = 2,
|
||||
} eUSDXformOpMode;
|
||||
|
||||
struct USDExportParams {
|
||||
bool export_animation = false;
|
||||
bool export_hair = true;
|
||||
@@ -102,6 +108,7 @@ struct USDExportParams {
|
||||
bool convert_orientation = false;
|
||||
enum eIOAxis forward_axis = eIOAxis::IO_AXIS_NEGATIVE_Z;
|
||||
enum eIOAxis up_axis = eIOAxis::IO_AXIS_Y;
|
||||
eUSDXformOpMode xform_op_mode = eUSDXformOpMode::USD_XFORM_OP_TRS;
|
||||
char root_prim_path[1024] = ""; /* FILE_MAX */
|
||||
char collection[MAX_IDPROP_NAME] = "";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user