131 lines
5.2 KiB
Python
131 lines
5.2 KiB
Python
import math
|
|
import sys
|
|
|
|
import bpy
|
|
|
|
|
|
def keyframe_rotation(target, frame, degrees):
|
|
target.rotation_euler[2] = math.radians(degrees)
|
|
target.keyframe_insert(data_path="rotation_euler", index=2, frame=frame)
|
|
|
|
|
|
def main(output_path: str) -> None:
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
|
|
mesh = bpy.data.meshes.new("PoseConstraintMesh")
|
|
mesh.from_pydata(
|
|
[(-1.0, -1.0, 0.0), (1.0, -1.0, 0.0), (1.0, 1.0, 0.0), (-1.0, 1.0, 0.0)],
|
|
[],
|
|
[(0, 1, 2), (0, 2, 3)],
|
|
)
|
|
mesh.update()
|
|
mesh_object = bpy.data.objects.new("PoseConstraintMeshObject", mesh)
|
|
bpy.context.collection.objects.link(mesh_object)
|
|
mesh_object.location = (0.35, -0.2, 0.15)
|
|
mesh_object.rotation_euler = (math.radians(7.0), math.radians(-11.0), math.radians(5.0))
|
|
mesh_object.scale = (1.2, 0.8, 1.1)
|
|
|
|
scaled_parent = bpy.data.objects.new("ScaledRigParent", None)
|
|
bpy.context.collection.objects.link(scaled_parent)
|
|
scaled_parent.location = (-0.25, 0.3, 0.1)
|
|
scaled_parent.rotation_euler = (math.radians(4.0), math.radians(3.0), math.radians(-8.0))
|
|
scaled_parent.scale = (1.35, 0.7, 1.15)
|
|
|
|
armature_data = bpy.data.armatures.new("PoseConstraintArmature")
|
|
armature_object = bpy.data.objects.new("PoseConstraintArmatureObject", armature_data)
|
|
bpy.context.collection.objects.link(armature_object)
|
|
armature_object.parent = scaled_parent
|
|
armature_object.location = (-0.15, 0.1, -0.05)
|
|
armature_object.rotation_euler = (math.radians(-6.0), math.radians(9.0), math.radians(12.0))
|
|
armature_object.scale = (0.9, 1.1, 1.05)
|
|
bpy.context.view_layer.objects.active = armature_object
|
|
armature_object.select_set(True)
|
|
bpy.ops.object.mode_set(mode="EDIT")
|
|
root = armature_data.edit_bones.new("Root")
|
|
root.head = (0.0, 0.0, 0.0)
|
|
root.tail = (0.0, 0.0, 1.0)
|
|
mid = armature_data.edit_bones.new("Mid")
|
|
mid.head = (0.0, 0.0, 1.0)
|
|
mid.tail = (0.0, 0.0, 2.0)
|
|
mid.parent = root
|
|
mid.use_connect = True
|
|
tip = armature_data.edit_bones.new("Tip")
|
|
tip.head = (0.0, 0.0, 2.0)
|
|
tip.tail = (0.0, 0.0, 3.0)
|
|
tip.parent = mid
|
|
tip.use_connect = True
|
|
auxiliary = armature_data.edit_bones.new("Auxiliary")
|
|
auxiliary.head = (0.5, 0.0, 0.5)
|
|
auxiliary.tail = (0.5, 0.0, 1.25)
|
|
auxiliary.parent = root
|
|
bpy.ops.object.mode_set(mode="POSE")
|
|
pose_root = armature_object.pose.bones["Root"]
|
|
pose_root.rotation_mode = "XYZ"
|
|
for frame, degrees in ((1, 0.0), (5, 18.0), (10, 36.0), (15, 48.0)):
|
|
pose_root.rotation_euler[1] = math.radians(degrees)
|
|
pose_root.keyframe_insert(data_path="rotation_euler", index=1, frame=frame)
|
|
bpy.ops.object.mode_set(mode="OBJECT")
|
|
|
|
target = bpy.data.objects.new("PoseConstraintTarget", None)
|
|
bpy.context.collection.objects.link(target)
|
|
target.location = (0.0, 0.0, 1.0)
|
|
for frame, degrees in ((1, 0.0), (5, 35.0), (10, 70.0), (15, 95.0)):
|
|
keyframe_rotation(target, frame, degrees)
|
|
|
|
copy_rotation = armature_object.pose.bones["Auxiliary"].constraints.new("COPY_ROTATION")
|
|
copy_rotation.name = "Animated Copy Rotation"
|
|
copy_rotation.target = target
|
|
copy_rotation.owner_space = "WORLD"
|
|
copy_rotation.target_space = "WORLD"
|
|
copy_rotation.use_x = False
|
|
copy_rotation.use_y = False
|
|
copy_rotation.use_z = True
|
|
copy_rotation.influence = 0.75
|
|
|
|
ik_target = bpy.data.objects.new("PoseIKTarget", None)
|
|
bpy.context.collection.objects.link(ik_target)
|
|
pole_target = bpy.data.objects.new("PoseIKPole", None)
|
|
bpy.context.collection.objects.link(pole_target)
|
|
pole_target.location = (1.5, -1.0, 1.25)
|
|
for frame, location in (
|
|
(1, (0.35, 0.15, 2.65)),
|
|
(5, (0.75, 0.25, 2.45)),
|
|
(10, (1.0, -0.15, 2.15)),
|
|
(15, (0.45, -0.55, 2.55)),
|
|
):
|
|
ik_target.location = location
|
|
ik_target.keyframe_insert(data_path="location", frame=frame)
|
|
ik = armature_object.pose.bones["Tip"].constraints.new("IK")
|
|
ik.name = "Animated Two Bone IK"
|
|
ik.target = ik_target
|
|
ik.pole_target = pole_target
|
|
ik.chain_count = 2
|
|
ik.iterations = 128
|
|
ik.influence = 0.85
|
|
|
|
root_group = mesh_object.vertex_groups.new(name="Root")
|
|
mid_group = mesh_object.vertex_groups.new(name="Mid")
|
|
tip_group = mesh_object.vertex_groups.new(name="Tip")
|
|
auxiliary_group = mesh_object.vertex_groups.new(name="Auxiliary")
|
|
root_group.add([0, 1], 1.0, "REPLACE")
|
|
root_group.add([2, 3], 0.25, "REPLACE")
|
|
mid_group.add([0, 1], 0.0, "REPLACE")
|
|
mid_group.add([2, 3], 0.35, "REPLACE")
|
|
tip_group.add([0, 1], 0.0, "REPLACE")
|
|
tip_group.add([2, 3], 0.40, "REPLACE")
|
|
auxiliary_group.add([0, 1, 2, 3], 0.05, "REPLACE")
|
|
armature_modifier = mesh_object.modifiers.new(name="Armature Deform", type="ARMATURE")
|
|
armature_modifier.object = armature_object
|
|
|
|
scene = bpy.context.scene
|
|
scene.frame_start = 1
|
|
scene.frame_end = 15
|
|
scene.frame_set(1)
|
|
bpy.ops.wm.save_as_mainfile(filepath=output_path, compress=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if "--" not in sys.argv or len(sys.argv) <= sys.argv.index("--") + 1:
|
|
raise SystemExit("usage: blender -b --python generate-pose-constraint-fixture.py -- output.blend")
|
|
main(sys.argv[sys.argv.index("--") + 1])
|