Fix: vertex crease data was imported incorrectly from USD

While adding tests for subd import I discovered that our vertex crease
data was imported incorrectly.

This PR adds tests and fixes:
- We tried to read crease sharpness data as ints instead of floats. This
  caused the import process to early-return, meaning we never load any
  data at all
- Empty USD data would still cause us to create the `crease_vert`
  attribute unnecessarily
- Sharpness data needs clamped to 0-1 to handle USD's SHARPNESS_INFINITE
  value of 10.0
- We need to fill the `crease_vert` span with 0's since incoming USD
  data may not have values set for all the verts

Pull Request: https://projects.blender.org/blender/blender/pulls/131516
This commit is contained in:
Jesse Yurkovich
2024-12-06 22:19:31 +01:00
committed by Jesse Yurkovich
parent e3c6c2c6fc
commit 76c699ada5
2 changed files with 30 additions and 2 deletions

View File

@@ -355,11 +355,16 @@ void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTim
return;
}
pxr::VtIntArray corner_sharpnesses;
pxr::VtFloatArray corner_sharpnesses;
if (!mesh_prim_.GetCornerSharpnessesAttr().Get(&corner_sharpnesses, motionSampleTime)) {
return;
}
/* Prevent the creation of the `crease_vert` attribute if we have no data. */
if (corner_indices.empty() || corner_sharpnesses.empty()) {
return;
}
/* It is fine to have fewer indices than vertices, but never the other way other. */
if (corner_indices.size() > mesh->verts_num) {
CLOG_WARN(&LOG, "Too many vertex creases for mesh %s", prim_path_.c_str());
@@ -375,9 +380,10 @@ void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTim
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter creases = attributes.lookup_or_add_for_write_only_span<float>(
"crease_vert", bke::AttrDomain::Point);
creases.span.fill(0.0f);
for (size_t i = 0; i < corner_indices.size(); i++) {
creases.span[corner_indices[i]] = corner_sharpnesses[i];
creases.span[corner_indices[i]] = std::clamp(corner_sharpnesses[i], 0.0f, 1.0f);
}
creases.finish();
}

View File

@@ -198,6 +198,28 @@ class USDImportTest(AbstractUSDTest):
coords = list(filter(lambda x: x[0] > 1.0, coords))
self.assertGreater(len(coords), 16)
def test_import_mesh_subd(self):
"""Test importing meshes with subdivision attributes."""
# Use the existing mesh subd test file to create the USD file
# for import. It is validated as part of the bl_usd_export test.
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "usd_mesh_subd.blend"))
testfile = str(self.tempdir / "usd_mesh_subd.usda")
bpy.ops.wm.usd_export(filepath=testfile, export_subdivision='BEST_MATCH', evaluation_mode="RENDER")
res = bpy.ops.wm.usd_export(filepath=testfile, export_materials=True)
self.assertEqual({'FINISHED'}, res, f"Unable to export to {testfile}")
# Reload the empty file and import back in
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "empty.blend"))
res = bpy.ops.wm.usd_import(filepath=testfile)
self.assertEqual({'FINISHED'}, res, f"Unable to import USD file {testfile}")
# Validate crease attributes
mesh = bpy.data.objects["crease_verts"].data
blender_crease_vert_data = [round(d.value, 5) for d in mesh.attributes["crease_vert"].data]
self.assertEqual(blender_crease_vert_data, [0.3, 0.0, 0.2, 0.1, 0.8, 0.7, 1.0, 0.9])
def test_import_camera_properties(self):
"""Test importing camera to ensure properties set correctly."""