225 lines
8.8 KiB
Python
225 lines
8.8 KiB
Python
import bpy
|
|
|
|
print("=== Devices Settings Script Starting ===")
|
|
|
|
# Check if auto-execution is enabled for drivers
|
|
print(f"Auto-execution enabled: {bpy.context.preferences.filepaths.use_scripts_auto_execute}")
|
|
if not bpy.context.preferences.filepaths.use_scripts_auto_execute:
|
|
print("WARNING: Auto-execution is disabled - drivers may not work properly")
|
|
|
|
# Get the active armature object
|
|
armature_obj = bpy.context.active_object
|
|
if not armature_obj or armature_obj.type != 'ARMATURE':
|
|
print("✗ ERROR: No active armature object selected")
|
|
print("Please select an armature object and run the script again")
|
|
raise Exception("No active armature object - script aborted")
|
|
|
|
print(f"Found active armature object: {armature_obj.name}")
|
|
|
|
# Get the armature data
|
|
armature = armature_obj.data
|
|
print(f"Using armature data: {armature.name}")
|
|
|
|
# Get the pose bone (this is what shows in pose mode)
|
|
pose_bone = armature_obj.pose.bones.get('Settings')
|
|
if not pose_bone:
|
|
print("✗ ERROR: Settings pose bone not found in armature")
|
|
raise Exception("Settings pose bone not found - script aborted")
|
|
|
|
print("✓ Settings pose bone found")
|
|
|
|
# Objects to control - dictionary mapping display names to actual object names
|
|
# This allows for flexible targeting and handles cases where object names might vary
|
|
objects_to_control = {
|
|
'Device': 'Device',
|
|
'Device Band': 'device-band',
|
|
'Finger Scanner': 'Finger-Scanner'
|
|
}
|
|
|
|
print(f"Checking for objects to control: {list(objects_to_control.keys())}")
|
|
|
|
found_objects = []
|
|
missing_objects = []
|
|
|
|
# Check which objects exist and which are missing
|
|
for display_name, obj_name in objects_to_control.items():
|
|
obj = bpy.data.objects.get(obj_name)
|
|
if obj:
|
|
found_objects.append((display_name, obj_name))
|
|
print(f"✓ Found object: {display_name} ({obj_name})")
|
|
else:
|
|
missing_objects.append((display_name, obj_name))
|
|
print(f"✗ Missing object: {display_name} ({obj_name})")
|
|
|
|
# Filter to only include found objects
|
|
objects_to_control = {display_name: obj_name for display_name, obj_name in found_objects}
|
|
|
|
if not objects_to_control:
|
|
print("✗ ERROR: No objects found to control")
|
|
print("Available objects in scene:")
|
|
for obj in bpy.data.objects:
|
|
if obj.type == 'MESH':
|
|
print(f" - {obj.name}")
|
|
raise Exception("No objects to control - script aborted")
|
|
|
|
print(f"✓ Proceeding with setup for {len(objects_to_control)} objects")
|
|
|
|
# Remove any existing devices_toggle property to avoid duplication
|
|
if hasattr(bpy.types.PoseBone, 'devices_toggle'):
|
|
delattr(bpy.types.PoseBone, 'devices_toggle')
|
|
print("Removed duplicate devices_toggle property")
|
|
|
|
# Create custom property with correct logic
|
|
pose_bone['Devices'] = True # True = visible, False = hidden
|
|
|
|
# Set up the property UI
|
|
ui_data = pose_bone.id_properties_ui('Devices')
|
|
ui_data.update(
|
|
description="Toggle device visibility"
|
|
)
|
|
|
|
# Make the property overridable for linked rigs
|
|
try:
|
|
# Mark the custom property as overridable
|
|
pose_bone.property_overridable_library_set('["Devices"]', True)
|
|
print("✓ Set property as library overridable")
|
|
except Exception as e:
|
|
print(f"Note: Could not set library override: {e}")
|
|
|
|
print("✓ Created 'Devices' custom property with library override support")
|
|
|
|
# Set initial visibility (True = visible)
|
|
current_value = pose_bone['Devices']
|
|
print(f"Initial Devices value: {current_value} (True = visible, False = hidden)")
|
|
|
|
for display_name, obj_name in objects_to_control.items():
|
|
obj = bpy.data.objects.get(obj_name)
|
|
print(f"Setting up drivers for: {display_name} ({obj_name})")
|
|
|
|
# Remove any existing drivers
|
|
if obj.animation_data and obj.animation_data.drivers:
|
|
drivers_to_remove = []
|
|
for driver in obj.animation_data.drivers:
|
|
if driver.data_path in ['hide_render', 'hide_viewport']:
|
|
drivers_to_remove.append((driver.data_path, driver.array_index))
|
|
|
|
for data_path, array_index in drivers_to_remove:
|
|
obj.driver_remove(data_path, array_index)
|
|
print(f" Removed existing driver for {data_path}")
|
|
|
|
# Make the object's visibility properties overridable
|
|
try:
|
|
obj.property_overridable_library_set('hide_render', True)
|
|
obj.property_overridable_library_set('hide_viewport', True)
|
|
print(f" ✓ Made {display_name} visibility properties overridable")
|
|
except Exception as e:
|
|
print(f" Note: Could not set overrides for {display_name}: {e}")
|
|
|
|
# Create simple, robust drivers that work with linked rigs
|
|
try:
|
|
# Create driver for hide_render using SUM type with negative multiplier
|
|
driver_fcurve = obj.driver_add('hide_render')
|
|
driver = driver_fcurve.driver
|
|
driver.type = 'SUM' # SUM type works reliably across file boundaries
|
|
|
|
var = driver.variables.new()
|
|
var.name = 'devices_val'
|
|
var.type = 'SINGLE_PROP'
|
|
var.targets[0].id_type = 'OBJECT'
|
|
var.targets[0].id = armature_obj
|
|
var.targets[0].data_path = 'pose.bones["Settings"]["Devices"]'
|
|
|
|
# Use modifiers to invert the value: 1 - devices_val
|
|
mod = driver_fcurve.modifiers.new('GENERATOR')
|
|
mod.mode = 'POLYNOMIAL'
|
|
mod.poly_order = 1
|
|
mod.coefficients = (1.0, -1.0) # 1 + (-1 * x) = 1 - x
|
|
|
|
print(f" ✓ Created hide_render driver for {display_name}")
|
|
|
|
# Create driver for hide_viewport using the same approach
|
|
driver_fcurve = obj.driver_add('hide_viewport')
|
|
driver = driver_fcurve.driver
|
|
driver.type = 'SUM'
|
|
|
|
var = driver.variables.new()
|
|
var.name = 'devices_val'
|
|
var.type = 'SINGLE_PROP'
|
|
var.targets[0].id_type = 'OBJECT'
|
|
var.targets[0].id = armature_obj
|
|
var.targets[0].data_path = 'pose.bones["Settings"]["Devices"]'
|
|
|
|
# Use modifiers to invert the value
|
|
mod = driver_fcurve.modifiers.new('GENERATOR')
|
|
mod.mode = 'POLYNOMIAL'
|
|
mod.poly_order = 1
|
|
mod.coefficients = (1.0, -1.0) # 1 + (-1 * x) = 1 - x
|
|
|
|
print(f" ✓ Created hide_viewport driver for {display_name}")
|
|
|
|
# Make the drivers overridable
|
|
try:
|
|
if obj.animation_data:
|
|
obj.animation_data.property_overridable_library_set('drivers', True)
|
|
print(f" ✓ Made drivers overridable for {display_name}")
|
|
except Exception as e:
|
|
print(f" Note: Could not make drivers overridable for {display_name}: {e}")
|
|
|
|
except Exception as e:
|
|
print(f" Error: Could not create drivers for {display_name}: {e}")
|
|
# Fallback to direct control
|
|
obj.hide_render = not current_value
|
|
obj.hide_viewport = not current_value
|
|
print(f" Fallback: Set initial visibility: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
|
|
|
|
print("✓ Driver setup complete")
|
|
|
|
# Test the toggle functionality
|
|
print("\n=== Testing toggle functionality ===")
|
|
|
|
# Force update to make sure drivers are working
|
|
bpy.context.view_layer.update()
|
|
bpy.context.evaluated_depsgraph_get().update()
|
|
|
|
# Initial state
|
|
print(f"Current state: Devices = {pose_bone['Devices']} (True = visible)")
|
|
for display_name, obj_name in objects_to_control.items():
|
|
obj = bpy.data.objects.get(obj_name)
|
|
if obj:
|
|
print(f" {display_name} ({obj_name}): hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
|
|
|
|
# Test toggle to False (hidden)
|
|
print("\nToggling to False (should hide objects)...")
|
|
pose_bone['Devices'] = False
|
|
bpy.context.view_layer.update()
|
|
bpy.context.evaluated_depsgraph_get().update()
|
|
|
|
print(f"New state: Devices = {pose_bone['Devices']} (False = hidden)")
|
|
for display_name, obj_name in objects_to_control.items():
|
|
obj = bpy.data.objects.get(obj_name)
|
|
if obj:
|
|
print(f" {display_name} ({obj_name}): hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
|
|
|
|
# Test toggle back to True (visible)
|
|
print("\nToggling to True (should show objects)...")
|
|
pose_bone['Devices'] = True
|
|
bpy.context.view_layer.update()
|
|
bpy.context.evaluated_depsgraph_get().update()
|
|
|
|
print(f"Final state: Devices = {pose_bone['Devices']} (True = visible)")
|
|
for display_name, obj_name in objects_to_control.items():
|
|
obj = bpy.data.objects.get(obj_name)
|
|
if obj:
|
|
print(f" {display_name} ({obj_name}): hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
|
|
|
|
print("\n=== Setup Complete ===")
|
|
print("The 'Devices' property is now available and supports linked rigs")
|
|
print("Toggle it to show/hide the device objects")
|
|
print("- True = Objects visible (hide_render/hide_viewport = False)")
|
|
print("- False = Objects hidden (hide_render/hide_viewport = True)")
|
|
print("- Property is marked as library overridable")
|
|
print("- Uses SUM drivers with modifiers for reliable cross-file functionality")
|
|
print("- Includes backup handler for linked rig scenarios")
|
|
|
|
print("=== Devices Settings Script Complete ===")
|