2025-12-01
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# SPDX-FileCopyrightText: 2025 Blender Studio Tools Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import bpy
|
||||
from bpy.types import PoseBone, Object, VertexGroup, Bone, EditBone
|
||||
|
||||
from . import __package__ as base_package
|
||||
|
||||
|
||||
def get_addon_prefs(context=None):
|
||||
if not context:
|
||||
context = bpy.context
|
||||
if base_package.startswith('bl_ext'):
|
||||
# 4.2
|
||||
return context.preferences.addons[base_package].preferences
|
||||
else:
|
||||
return context.preferences.addons[base_package.split(".")[0]].preferences
|
||||
|
||||
|
||||
def poll_deformed_mesh_with_vgroups(operator, context, must_deform=True) -> bool:
|
||||
obj = context.active_object
|
||||
if not obj or obj.type != 'MESH':
|
||||
operator.poll_message_set("No active mesh object.")
|
||||
return False
|
||||
if must_deform and ('ARMATURE' not in [m.type for m in obj.modifiers]):
|
||||
operator.poll_message_set("This mesh is not deformed by an Armature modifier.")
|
||||
return False
|
||||
if not obj.vertex_groups:
|
||||
operator.poll_message_set("This mesh has no vertex groups yet.")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def delete_vgroups(mesh_ob, vgroups: list[VertexGroup]):
|
||||
for vgroup in vgroups:
|
||||
mesh_ob.vertex_groups.remove(vgroup)
|
||||
|
||||
|
||||
def get_deforming_vgroups(mesh_ob: Object, arm_ob: Object = None) -> list[VertexGroup]:
|
||||
"""Get the vertex groups of a mesh object that correspond to a deform bone in the given armature."""
|
||||
|
||||
if not arm_ob:
|
||||
arm_ob = get_deforming_armature(mesh_ob)
|
||||
if not arm_ob:
|
||||
return []
|
||||
|
||||
deforming_vgroups = []
|
||||
|
||||
for bone in arm_ob.data.bones:
|
||||
if bone.name in mesh_ob.vertex_groups and bone.use_deform:
|
||||
deforming_vgroups.append(mesh_ob.vertex_groups[bone.name])
|
||||
|
||||
return deforming_vgroups
|
||||
|
||||
|
||||
def get_deforming_armature(mesh_ob: Object) -> Object | None:
|
||||
"""Return first Armature modifier's target object."""
|
||||
for mod in mesh_ob.modifiers:
|
||||
if mod.type == 'ARMATURE':
|
||||
return mod.object
|
||||
|
||||
|
||||
def poll_weight_paint_mode(operator, context, with_rig=False, with_groups=False):
|
||||
"""Function used for operator poll functions, ie. to determine whether
|
||||
operators should be available or not."""
|
||||
|
||||
obj = context.active_object
|
||||
if context.mode != 'PAINT_WEIGHT':
|
||||
operator.poll_message_set("Must be in Weight Paint mode.")
|
||||
return False
|
||||
if with_rig:
|
||||
if not 'ARMATURE' in (m.type for m in obj.modifiers):
|
||||
operator.poll_message_set("This mesh is not deformed by an Armature modifier.")
|
||||
return False
|
||||
if not context.pose_object or context.pose_object != get_deforming_armature(obj):
|
||||
operator.poll_message_set(
|
||||
"Couldn't find deforming armature, or it is not in pose mode."
|
||||
)
|
||||
return False
|
||||
|
||||
if with_groups and not obj.vertex_groups:
|
||||
operator.poll_message_set("This mesh object has no vertex groups yet.")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def reveal_bone(bone: Bone or EditBone or PoseBone, select=True):
|
||||
"""Reveall and optionally select a bone, regardless of current
|
||||
selection or visibility states.
|
||||
"""
|
||||
if type(bone) == PoseBone:
|
||||
bone = bone.bone
|
||||
armature = bone.id_data
|
||||
|
||||
if hasattr(armature, 'layers'):
|
||||
# Blender 3.6 and below: Bone Layers.
|
||||
enabled_layers = [i for i in range(32) if armature.layers[i]]
|
||||
|
||||
# If none of this bone's layers are enabled, enable the first one.
|
||||
bone_layers = [i for i in range(32) if bone.layers[i]]
|
||||
if not any([i in enabled_layers for i in bone_layers]):
|
||||
armature.layers[bone_layers[0]] = True
|
||||
else:
|
||||
# Blender 4.0 and above: Bone Collections.
|
||||
ensure_visible_bone_collection(bone)
|
||||
|
||||
bone.hide = False
|
||||
|
||||
if select:
|
||||
bone.select = True
|
||||
|
||||
|
||||
def ensure_visible_bone_collection(bone: Bone or EditBone or PoseBone):
|
||||
"""If target bone not in any enabled collections, enable first one."""
|
||||
# NOTE: This function was lifted from CloudRig.
|
||||
if type(bone) == PoseBone:
|
||||
bone = bone.bone
|
||||
|
||||
armature = bone.id_data
|
||||
collections = armature.collections
|
||||
|
||||
if len(bone.collections) == 0:
|
||||
return
|
||||
|
||||
if not any([coll.is_visible_effectively for coll in bone.collections]):
|
||||
coll = bone.collections[0]
|
||||
while coll:
|
||||
if collections.is_solo_active:
|
||||
coll.is_solo = True
|
||||
else:
|
||||
coll.is_visible = True
|
||||
coll = coll.parent
|
||||
Reference in New Issue
Block a user