Fix: USD: Write vertex crease data correctly and add tests
While adding test coverage for mesh subdivision surface scenarios, a few problems were noticed with vertex crease support. This PR fixes: - Used incorrect `crease_sharpnesses` instead of `corner_sharpnesses` - Used incorrect value for an "infinitely sharp" vertex crease - Unnecessarily wrote out Blender's `crease_vert` attribute as a primvar Tests are added which validate everything we support. Pull Request: https://projects.blender.org/blender/blender/pulls/126209
This commit is contained in:
committed by
Jesse Yurkovich
parent
56779c7bb0
commit
cb9ca2f7a7
@@ -166,7 +166,7 @@ void USDGenericMeshWriter::write_custom_data(const Object *obj,
|
||||
* Skip edge domain because USD doesn't have a good conversion for them. */
|
||||
if (attribute_id.name()[0] == '.' || attribute_id.is_anonymous() ||
|
||||
meta_data.domain == bke::AttrDomain::Edge ||
|
||||
ELEM(attribute_id.name(), "position", "material_index", "velocity"))
|
||||
ELEM(attribute_id.name(), "position", "material_index", "velocity", "crease_vert"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -459,7 +459,7 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context,
|
||||
usd_value_writer_.SetAttribute(
|
||||
attr_corner_indices, pxr::VtValue(usd_mesh_data.corner_indices), timecode);
|
||||
usd_value_writer_.SetAttribute(
|
||||
attr_corner_sharpnesses, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
|
||||
attr_corner_sharpnesses, pxr::VtValue(usd_mesh_data.corner_sharpnesses), timecode);
|
||||
}
|
||||
|
||||
write_custom_data(context.object, mesh, usd_mesh);
|
||||
@@ -638,9 +638,10 @@ static void get_vert_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
|
||||
}
|
||||
const VArraySpan creases(*attribute);
|
||||
for (const int i : creases.index_range()) {
|
||||
const float sharpness = creases[i];
|
||||
const float crease = creases[i];
|
||||
|
||||
if (sharpness != 0.0f) {
|
||||
if (crease > 0.0f) {
|
||||
const float sharpness = crease >= 1.0f ? pxr::UsdGeomMesh::SHARPNESS_INFINITE : crease;
|
||||
usd_mesh_data.corner_indices.push_back(i);
|
||||
usd_mesh_data.corner_sharpnesses.push_back(sharpness);
|
||||
}
|
||||
|
||||
@@ -318,6 +318,81 @@ class USDExportTest(AbstractUSDTest):
|
||||
self.assertEqual(UsdGeom.PrimvarsAPI(mesh2).GetPrimvar("test").GetTimeSamples(), [])
|
||||
self.assertEqual(UsdGeom.PrimvarsAPI(mesh3).GetPrimvar("test").GetTimeSamples(), sparse_frames)
|
||||
|
||||
def test_export_mesh_subd(self):
|
||||
"""Test exporting Subdivision Surface attributes and values"""
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_mesh_subd.blend"))
|
||||
export_path = self.tempdir / "usd_mesh_subd.usda"
|
||||
res = bpy.ops.wm.usd_export(
|
||||
filepath=str(export_path),
|
||||
export_subdivision='BEST_MATCH',
|
||||
evaluation_mode="RENDER",
|
||||
)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to export to {export_path}")
|
||||
|
||||
stage = Usd.Stage.Open(str(export_path))
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/uv_smooth_none_boundary_smooth_all/mesh1"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'all')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/uv_smooth_corners_boundary_smooth_all/mesh2"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'cornersOnly')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/uv_smooth_corners_junctions_boundary_smooth_all/mesh3"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'cornersPlus1')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/uv_smooth_corners_junctions_concave_boundary_smooth_all/mesh4"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'cornersPlus2')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/uv_smooth_boundaries_boundary_smooth_all/mesh5"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'boundaries')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/uv_smooth_all_boundary_smooth_all/mesh6"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'none')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/uv_smooth_boundaries_boundary_smooth_keep/mesh7"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'boundaries')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeAndCorner')
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/crease_verts/crease_verts"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'boundaries')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
self.assertEqual(len(mesh.GetCornerIndicesAttr().Get()), 7)
|
||||
usd_vert_sharpness = mesh.GetCornerSharpnessesAttr().Get()
|
||||
self.assertEqual(len(usd_vert_sharpness), 7)
|
||||
# A 1.0 crease is INFINITE (10) in USD
|
||||
self.assertAlmostEqual(min(usd_vert_sharpness), 0.1, 5)
|
||||
self.assertEqual(len([sharp for sharp in usd_vert_sharpness if sharp < 1]), 6)
|
||||
self.assertEqual(len([sharp for sharp in usd_vert_sharpness if sharp == 10]), 1)
|
||||
|
||||
mesh = UsdGeom.Mesh(stage.GetPrimAtPath("/root/crease_edge/crease_edge"))
|
||||
self.assertEqual(mesh.GetSubdivisionSchemeAttr().Get(), 'catmullClark')
|
||||
self.assertEqual(mesh.GetFaceVaryingLinearInterpolationAttr().Get(), 'boundaries')
|
||||
self.assertEqual(mesh.GetInterpolateBoundaryAttr().Get(), 'edgeOnly')
|
||||
self.assertEqual(len(mesh.GetCreaseIndicesAttr().Get()), 20)
|
||||
usd_crease_lengths = mesh.GetCreaseLengthsAttr().Get()
|
||||
self.assertEqual(len(usd_crease_lengths), 10)
|
||||
self.assertTrue(all([length == 2 for length in usd_crease_lengths]))
|
||||
usd_crease_sharpness = mesh.GetCreaseSharpnessesAttr().Get()
|
||||
self.assertEqual(len(usd_crease_sharpness), 10)
|
||||
# A 1.0 crease is INFINITE (10) in USD
|
||||
self.assertAlmostEqual(min(usd_crease_sharpness), 0.1, 5)
|
||||
self.assertEqual(len([sharp for sharp in usd_crease_sharpness if sharp < 1]), 9)
|
||||
self.assertEqual(len([sharp for sharp in usd_crease_sharpness if sharp == 10]), 1)
|
||||
|
||||
def test_animation(self):
|
||||
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_anim_test.blend"))
|
||||
export_path = self.tempdir / "usd_anim_test.usda"
|
||||
|
||||
Reference in New Issue
Block a user