Modifiers: Armature deformation test for various modifier settings

Test for armature deform modifier settings that are not yet covered by other tests:

- Vertex Group vs. Envelope deformation and both combined.
- Vertex group masking ('vertex_group' setting of the modifier)
- Inverted vertex group masking
- Preserve Volume (dual quaternions)
- Vertex Group/Envelope influence mixing (bone option)
- B-Bone deformation
- Multi-modifier mixing

Each case has a new test/expected mesh pair in the modifiers test.

Pull Request: https://projects.blender.org/blender/blender/pulls/141054
This commit is contained in:
Lukas Tönne
2025-07-01 14:18:58 +02:00
parent c49e9e1773
commit fe869232ee
3 changed files with 87 additions and 3 deletions

View File

@@ -10,7 +10,7 @@ from random import seed
import bpy
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
from modules.mesh_test import RunTest, ModifierSpec, SpecMeshTest, OperatorSpecObjectMode
from modules.mesh_test import RunTest, ModifierSpec, MultiModifierSpec, SpecMeshTest, OperatorSpecObjectMode
seed(0)
@@ -323,6 +323,60 @@ def main():
SpecMeshTest("CurveCurve", "testObjBezierCurveCurve", "expObjBezierCurveCurve",
[ModifierSpec('curve_Curve', 'CURVE', {'object': bpy.data.objects['NurbsCurve']})]),
#############################################
# Armature Deform Modifier Settings
#############################################
# 70
SpecMeshTest("ArmatureDefault", "testMonkeyArmatureDefault", "expectedMonkeyArmatureDefault",
[ModifierSpec('armature', 'ARMATURE',
{'object': bpy.data.objects['testArmatureDefault'],
'use_vertex_groups': True})]),
SpecMeshTest("ArmatureEnvelope", "testMonkeyArmatureEnvelope", "expectedMonkeyArmatureEnvelope",
[ModifierSpec('armature', 'ARMATURE',
{'object': bpy.data.objects['testArmatureEnvelope'],
'use_vertex_groups': False,
'use_bone_envelopes': True})]),
SpecMeshTest("ArmatureVGroupEnvelope", "testMonkeyArmatureVGroupEnvelope", "expectedMonkeyArmatureVGroupEnvelope",
[ModifierSpec('armature', 'ARMATURE',
{'object': bpy.data.objects['testArmatureVGroupEnvelope'],
'use_vertex_groups': True,
'use_bone_envelopes': True})]),
SpecMeshTest("ArmaturePreserveVolume", "testMonkeyArmaturePreserveVolume", "expectedMonkeyArmaturePreserveVolume",
[ModifierSpec('armature', 'ARMATURE',
{'object': bpy.data.objects['testArmaturePreserveVolume'],
'use_vertex_groups': True,
'use_deform_preserve_volume': True})]),
SpecMeshTest("ArmatureMasked", "testMonkeyArmatureMasked", "expectedMonkeyArmatureMasked",
[ModifierSpec('armature', 'ARMATURE',
{'object': bpy.data.objects['testArmatureMasked'],
'use_vertex_groups': True,
'vertex_group': "Mask"})]),
SpecMeshTest("ArmatureMaskedInverse", "testMonkeyArmatureMaskedInverse", "expectedMonkeyArmatureMaskedInverse",
[ModifierSpec('armature', 'ARMATURE',
{'object': bpy.data.objects['testArmatureMaskedInverse'],
'use_vertex_groups': True,
'vertex_group': "Mask",
'invert_vertex_group': True})]),
SpecMeshTest("ArmatureMultiModifier", "testMonkeyArmatureMultiModifier", "expectedMonkeyArmatureMultiModifier",
[MultiModifierSpec(
[ModifierSpec('armature1', 'ARMATURE',
{'object': bpy.data.objects['testArmatureMultiModifier1'],
'use_vertex_groups': True}),
ModifierSpec('armature2', 'ARMATURE',
{'object': bpy.data.objects['testArmatureMultiModifier2'],
'use_vertex_groups': True,
'use_multi_modifier': True})])]),
SpecMeshTest("ArmatureMultiModifierMasked", "testMonkeyArmatureMultiModifierMasked", "expectedMonkeyArmatureMultiModifierMasked",
[MultiModifierSpec(
[ModifierSpec('armature1', 'ARMATURE',
{'object': bpy.data.objects['testArmatureMultiModifierMasked1'],
'use_vertex_groups': True,
'vertex_group': "Mask"}),
ModifierSpec('armature2', 'ARMATURE',
{'object': bpy.data.objects['testArmatureMultiModifierMasked2'],
'use_vertex_groups': True,
'vertex_group': "Mask",
'use_multi_modifier': True})])]),
]
boolean_basename = "CubeBooleanDiffBMeshObject"

View File

@@ -61,6 +61,23 @@ class ModifierSpec:
" with parameters: " + str(self.modifier_parameters)
class MultiModifierSpec:
"""
Holds a list of Deform modifiers that must be applied together to yield the expected result.
"""
def __init__(self, modifiers):
"""
Constructs a multi-modifier spec.
:arg modifiers - list of modifier specs
"""
self.modifiers = modifiers
def __str__(self):
return "Multi-Modifier: [" + ', '.join(str(modspec) for modspec in self.modifiers) + "]"
class ParticleSystemSpec:
"""
Holds a Particle System modifier and its parameters.
@@ -491,6 +508,13 @@ class SpecMeshTest(MeshTest):
self._apply_modifier(
evaluated_test_object, operation.modifier_name)
elif isinstance(operation, MultiModifierSpec):
for modspec in operation.modifiers:
self._add_modifier(evaluated_test_object, modspec)
if self.apply_modifier:
self._apply_all_modifiers(
evaluated_test_object)
elif isinstance(operation, OperatorSpecEditMode):
self._apply_operator_edit_mode(
evaluated_test_object, operation)
@@ -598,6 +622,12 @@ class SpecMeshTest(MeshTest):
else:
raise Exception("This object type is not yet supported!")
def _apply_all_modifiers(self, test_object):
if test_object.type in ['CURVE', 'MESH']:
bpy.ops.object.convert(target='MESH')
else:
raise Exception("This object type is not yet supported!")
def _bake_current_simulation(self, test_object, test_modifier_name, frame_end):
"""
FLUID: Bakes the simulation