Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
bl_info = {
"name": "Autogrip",
"author": "Jetpack Crow",
"version": (1, 21),
"blender": (3, 4, 1),
"version": (2, 2),
"blender": (4, 0, 0),
"location": "View3D > Extended Tools > AutoGrip",
"description": "Automatically poses hand rigs",
"category": '3D View'}
Expand Down
114 changes: 56 additions & 58 deletions handrig.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""INSTRUCTIONS
Run "autogrip.py" in Blender's text editor or install it as an add-on through the preferences menu.
Run "handrig.py" in Blender's text editor or install it as an add-on through the preferences menu.
Once that's done, check object mode, and all the buttons you need are in a tab in the N-panel called
"AutoGrip."

Expand Down Expand Up @@ -38,12 +38,17 @@
If you're sick of it and you want your old armature back, "Reset Hand R" and "Reset Hand L" clean up
after themselves pretty well, deleting everything this script did and leaving the original rig
untouched.

CONTRIBUTION INFO
Dmeerev:
- Modified to work with blender 4.X
- Controller bones now has location limits to calm control transforms
"""


bl_info = {
"name": "AutoGrip",
"blender": (3, 3, 0),
"blender": (4, 0, 0),
"category": "Object",
"description": "Automatically poses hands to grab props."
}
Expand Down Expand Up @@ -375,57 +380,30 @@ def constrain_IK(self):
aim = obj.pose.bones[namestring]
addIK(joint, aim)

def clean_layers(self):

# Moves all the project bones and the control bone to designated layers.
# You'd expect this to take an input, but I defined that out in
# set_armature_layers instead. May rearrange that for some clarity

for joint in self.projectors:
i = 0
joint.bone.layers[self.project_layer] = True
# Doing this in a weird order bc it won't let me set all layers to false
while (i < 32):
if self.project_layer != i:
joint.bone.layers[i] = False
i = i+1
i = 0
self.control_bone.bone.layers[self.control_layer] = True
while (i<32):
if self.control_layer != i:
self.control_bone.bone.layers[i] = False
i = i+1

def clean_layers(arm):
# Get rid of old blender layers system
pass

def set_armature_layers(self):

rig_choice = bpy.props.EnumProperty(
name="Rig selection",
description="Select an option",

items = [
('MHX', "MHX", "MakeHuman Exchange"),
('RFY', "Rigify", "Modular armature from the Rigify add-on"),
('ARP', "AutoRig Pro", "Auto rig pro"),
]
)
arm = bpy.context.object.data

rig_choice = obj.global_rig_choice

if rig_choice == 'MHX':
if self.control_bone.name[-1] == 'R':
print("setting layer for RIGHT finger")
self.control_layer = 22
elif self.control_bone.name[-1] == 'L':
print("setting layer for LEFT finger")
self.control_layer = 6
self.project_layer = 24
elif rig_choice == 'RFY':
self.control_layer = 6
self.project_layer = 23
elif rig_choice == 'ARP':
self.control_layer = 16
self.project_layer = 16
self.clean_layers()
if self.control_bone is not None:
collection_name = f"Layer {self.control_layer + 1}"
if collection_name not in arm.collections:
arm.collections.new(collection_name)
try:
arm.collections[collection_name].assign(self.control_bone.bone)
except RuntimeError:
pass

for projector in self.projectors:
collection_name = f"Layer {self.project_layer + 1}"
if collection_name not in arm.collections:
arm.collections.new(collection_name)
try:
arm.collections[collection_name].assign(projector.bone)
except RuntimeError:
pass

def reconstruct(self):
# When the finger already has a bonechain, finds projectors and control bone
Expand Down Expand Up @@ -631,9 +609,9 @@ def assemble_hand(handbone):

def control_drivers(finger):

# Puts rotation limits on control bone, then hooks up the influence of all those IK constraints
# Puts rotation and location limits on control bone, then hooks up the influence of all those IK constraints
# to depend on control bone rotation. Maybe the rotation limit part should be somewhere else

finger.control_bone.rotation_mode = "XYZ"

print("\nApplying rotation limits to " + finger.name + " control bone")
Expand All @@ -645,10 +623,29 @@ def control_drivers(finger):
rotationlock.use_limit_y = True
rotationlock.use_limit_z = True

print("Applying location limits to " + finger.name + " control bone")
locationlock = finger.control_bone.constraints.new("LIMIT_LOCATION")
locationlock.owner_space = "LOCAL"
locationlock.name = prefix + "Location Limit"
locationlock.use_min_x = True
locationlock.use_min_y = True
locationlock.use_min_z = True
locationlock.use_max_x = True
locationlock.use_max_y = True
locationlock.use_max_z = True
locationlock.min_x = 0
locationlock.min_y = 0
locationlock.min_z = 0
locationlock.max_x = 0
locationlock.max_y = 0
locationlock.max_z = 0

print("Applying angle drivers")
for joint in finger.phalanges:
#print('driver for bone ' + joint.name)
driver = obj.driver_add('pose.bones["' + joint.name + '"].constraints["' + prefix + 'IK"].influence').driver
fcurve = obj.driver_add('pose.bones["' + joint.name + '"].constraints["' + prefix + 'IK"].influence')
driver = fcurve.driver
fcurve.mute = False

v = driver.variables.new()
v.name = 'gripcontrol'

Expand All @@ -659,10 +656,11 @@ def control_drivers(finger):

print("Applying scale drivers")
for p in finger.projectors:
#print(p.name)
stringholder = p.name
scaledriver = obj.driver_add('pose.bones["' + stringholder + '"].constraints["' + prefix
+ 'shrinkwrap"].distance').driver
fcurve = obj.driver_add('pose.bones["' + stringholder + '"].constraints["' + prefix + 'shrinkwrap"].distance')
scaledriver = fcurve.driver
fcurve.mute = False

v = scaledriver.variables.new()
v.name = 'gripscale'

Expand Down