USD: Add option to merge shape with parent xform during import
This new import option will allow users to chose if we merge USD prims
with their Xform parent.
Given a USD like:
```
def Xform "MyObject"
{
def Mesh "MyObject_LOD0"
{
}
}
```
When the option is set to True (existing default), only the mesh will be
imported and its parent Xform transformation will be baked into the
Mesh.
```
# In blender after import
- MyObject_LOD0 (Mesh)
```
When the option is set to False, the parent Xform will always be
imported as an Empty object:
```
# In blender after import
- MyObject (Empty)
├─ MyObject_LOD0 (Mesh)
```
Co-authored-by: Odréanne Breton <odreanne.breton@ubisoft.com>
Co-authored-by: Sttevan Carnali Joga <sttevan.carnali-joga@ubisoft.com>
This commit is contained in:
committed by
Jesse Yurkovich
parent
7074daed04
commit
000416c933
@@ -935,6 +935,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
|
||||
|
||||
const bool create_world_material = RNA_boolean_get(op->ptr, "create_world_material");
|
||||
|
||||
const bool merge_parent_xform = RNA_boolean_get(op->ptr, "merge_parent_xform");
|
||||
|
||||
/* TODO(makowalski): Add support for sequences. */
|
||||
const bool is_sequence = false;
|
||||
int offset = 0;
|
||||
@@ -982,6 +984,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
|
||||
params.import_blendshapes = import_blendshapes;
|
||||
|
||||
params.validate_meshes = validate_meshes;
|
||||
params.merge_parent_xform = merge_parent_xform;
|
||||
|
||||
params.import_guide = import_guide;
|
||||
params.import_proxy = import_proxy;
|
||||
@@ -1073,6 +1076,7 @@ static void wm_usd_import_draw(bContext *C, wmOperator *op)
|
||||
|
||||
col = uiLayoutColumn(panel, false);
|
||||
uiItemR(col, ptr, "validate_meshes", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "merge_parent_xform", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
if (uiLayout *panel = uiLayoutPanel(C, layout, "USD_import_rigging", true, IFACE_("Rigging"))) {
|
||||
@@ -1322,6 +1326,13 @@ void WM_OT_usd_import(wmOperatorType *ot)
|
||||
"Defined Primitives Only",
|
||||
"Import only defined USD primitives. When disabled this allows importing USD "
|
||||
"primitives which are not defined, such as those with an override specifier");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"merge_parent_xform",
|
||||
true,
|
||||
"Merge parent Xform",
|
||||
"Allow USD primitives to merge with their Xform parent "
|
||||
"if they are the only child in the hierarchy");
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
|
||||
@@ -281,11 +281,13 @@ bool USDStageReader::include_by_purpose(const pxr::UsdGeomImageable &imageable)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Determine if the given reader can use the parent of the encapsulated USD prim
|
||||
* to compute the Blender object's transform. If so, the reader is appropriately
|
||||
* flagged and the function returns true. Otherwise, the function returns false. */
|
||||
static bool merge_with_parent(USDPrimReader *reader)
|
||||
bool USDStageReader::merge_with_parent(USDPrimReader *reader) const
|
||||
{
|
||||
/* Don't merge if the param is set to false */
|
||||
if (!params_.merge_parent_xform) {
|
||||
return false;
|
||||
}
|
||||
|
||||
USDXformReader *xform_reader = dynamic_cast<USDXformReader *>(reader);
|
||||
|
||||
if (!xform_reader) {
|
||||
|
||||
@@ -170,6 +170,13 @@ class USDStageReader {
|
||||
*/
|
||||
bool include_by_purpose(const pxr::UsdGeomImageable &imageable) const;
|
||||
|
||||
/**
|
||||
* Returns true if the given reader can use the parent of the encapsulated USD prim
|
||||
* to compute the Blender object's transform. If so, the reader is appropriately
|
||||
* flagged and the function returns true. Otherwise, the function returns false.
|
||||
*/
|
||||
bool merge_with_parent(USDPrimReader *reader) const;
|
||||
|
||||
/**
|
||||
* Returns true if the specified UsdPrim is a UsdGeom primitive,
|
||||
* procedural shape, such as UsdGeomCube.
|
||||
|
||||
@@ -212,6 +212,7 @@ struct USDImportParams {
|
||||
bool set_material_blend;
|
||||
|
||||
bool validate_meshes;
|
||||
bool merge_parent_xform;
|
||||
|
||||
eUSDMtlPurpose mtl_purpose;
|
||||
eUSDMtlNameCollisionMode mtl_name_collision_mode;
|
||||
|
||||
@@ -72,6 +72,30 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.assertEqual(objects['World'], objects['Empty'].parent, "Empty should be a child of /World")
|
||||
self.assertEqual(objects['Empty'], objects['Plane_002'].parent, "Plane_002 should be a child of /World")
|
||||
|
||||
def test_import_xform_and_mesh_merged_false(self):
|
||||
"""Test importing a simple object hierarchy (xform and mesh) from a USDA file."""
|
||||
|
||||
infile = str(self.testdir / "usd_mesh_polygon_types.usda")
|
||||
|
||||
res = bpy.ops.wm.usd_import(filepath=infile, merge_parent_xform=False)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to import USD file {infile}")
|
||||
|
||||
objects = bpy.context.scene.collection.objects
|
||||
self.assertEqual(10, len(objects), f"Test scene {infile} should have ten objects; found {len(objects)}")
|
||||
|
||||
# Test the hierarchy.
|
||||
self.assertEqual(
|
||||
objects['degenerate'],
|
||||
objects['m_degenerate'].parent,
|
||||
"m_degenerate should be child of /degenerate")
|
||||
self.assertEqual(
|
||||
objects['triangles'],
|
||||
objects['m_triangles'].parent,
|
||||
"m_triangles should be a child of /triangles")
|
||||
self.assertEqual(objects['quad'], objects['m_quad'].parent, "m_quad should be a child of /quad")
|
||||
self.assertEqual(objects['ngon_concave'], objects['m_ngon_concave'].parent,
|
||||
"m_ngon_concave should be a child of /ngon_concave")
|
||||
|
||||
def test_import_mesh_topology(self):
|
||||
"""Test importing meshes with different polygon types."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user