USD: Add support for animated point instancers
The existing point instancer reader is slightly refactored to allow for animated setups. The primary change is simply to inherit from `USDGeomReader` rather than `USDXformReader`. This allows access to the `read_geometry` API used by the cache modifier. The existing `read_object_data` method is split into two parts with `read_geometry` loading per-frame USD data and `read_object_data` coordinating the initial loading process, including creating the GN node tree just once. A new test has been added (a variation of the nested point instancer file) with time samples on various attributes and on both point instancers. This also fixes #129502 and the file provided in that issue. ---- The already added test file is `tests/data/usd/usd_point_instancer_anim.usda` Pull Request: https://projects.blender.org/blender/blender/pulls/129881
This commit is contained in:
committed by
Jesse Yurkovich
parent
8bcb714b9e
commit
2523958e0e
@@ -36,8 +36,8 @@ class USDImportTest(AbstractUSDTest):
|
||||
# Utility function to round each component of a vector to a few digits. The "+ 0" is to
|
||||
# ensure that any negative zeros (-0.0) are converted to positive zeros (0.0).
|
||||
@staticmethod
|
||||
def round_vector(vector):
|
||||
return [round(c, 5) + 0 for c in vector]
|
||||
def round_vector(vector, digits=5):
|
||||
return [round(c, digits) + 0 for c in vector]
|
||||
|
||||
def test_import_operator(self):
|
||||
"""Test running the import operator on valid and invalid files."""
|
||||
@@ -863,6 +863,58 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.assertEqual(3, vertical_points)
|
||||
self.assertEqual(2, horizontal_points)
|
||||
|
||||
def test_import_point_instancer_animation(self):
|
||||
"""Test importing an animated point instancer setup."""
|
||||
|
||||
infile = str(self.testdir / "usd_point_instancer_anim.usda")
|
||||
res = bpy.ops.wm.usd_import(filepath=infile)
|
||||
self.assertEqual({'FINISHED'}, res, f"Unable to import USD file {infile}")
|
||||
|
||||
prev_unique_positions = set()
|
||||
prev_unique_scales = set()
|
||||
prev_unique_quats = set()
|
||||
|
||||
# Check all frames to ensure instances are moving correctly
|
||||
for frame in range(1, 5):
|
||||
bpy.context.scene.frame_set(frame)
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||
|
||||
# Gather the instance data in a set so we can detect unique values
|
||||
unique_positions = set()
|
||||
unique_scales = set()
|
||||
unique_quats = set()
|
||||
mesh_count = 0
|
||||
for inst in depsgraph.object_instances:
|
||||
if inst.is_instance and inst.object.type == 'MESH':
|
||||
mesh_count += 1
|
||||
unique_positions.add(tuple(self.round_vector(inst.matrix_world.to_translation())))
|
||||
unique_scales.add(tuple(self.round_vector(inst.matrix_world.to_scale(), 1)))
|
||||
unique_quats.add(tuple(self.round_vector(inst.matrix_world.to_quaternion())))
|
||||
|
||||
# There should be 6 total mesh instances
|
||||
self.assertEqual(mesh_count, 6)
|
||||
|
||||
# Positions: All positions should be unique during each frame.
|
||||
# Scale and Orientation: One unique value on frame 1. Subsequent frames have different
|
||||
# combinations of unique values.
|
||||
self.assertEqual(len(unique_positions), 6, f"Frame {frame}: positions are unexpected")
|
||||
if frame == 1:
|
||||
self.assertEqual(len(unique_scales), 1, f"Frame {frame}: scales are unexpected")
|
||||
self.assertEqual(len(unique_quats), 1, f"Frame {frame}: orientations are unexpected")
|
||||
else:
|
||||
self.assertEqual(len(unique_scales), 2, f"Frame {frame}: scales are unexpected")
|
||||
self.assertEqual(len(unique_quats), 3, f"Frame {frame}: orientations are unexpected")
|
||||
|
||||
# Every frame is different. Ensure that the current frame's values do NOT match the
|
||||
# previous frame's data.
|
||||
self.assertNotEqual(unique_positions, prev_unique_positions)
|
||||
self.assertNotEqual(unique_scales, prev_unique_scales)
|
||||
self.assertNotEqual(unique_quats, prev_unique_quats)
|
||||
|
||||
prev_unique_positions = unique_positions
|
||||
prev_unique_scales = unique_scales
|
||||
prev_unique_quats = unique_quats
|
||||
|
||||
def test_import_light_types(self):
|
||||
"""Test importing light types and attributes."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user