import bpy print("=== Custom Visibility Script Starting ===") print(f"Blender version: {bpy.app.version_string}") # 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 object and selected objects active_obj = bpy.context.active_object selected_objects = bpy.context.selected_objects if not active_obj: print("✗ ERROR: No active object selected") print("Please select an object and run the script again") raise Exception("No active object - script aborted") print(f"Found active object: {active_obj.name}") print(f"Found {len(selected_objects)} selected object(s): {[obj.name for obj in selected_objects]}") # Find the armature object in the scene armature_obj = None # First, check if the active object is an armature if active_obj and active_obj.type == 'ARMATURE': armature_obj = active_obj print(f"Using active armature: {armature_obj.name}") else: # Look for an armature that has a Settings bone print("Active object is not an armature, searching for armature with Settings bone...") for obj in bpy.data.objects: if obj.type == 'ARMATURE' and 'Settings' in obj.pose.bones: armature_obj = obj print(f"Found armature with Settings bone: {armature_obj.name}") break # If still no armature found, just use the first armature if not armature_obj: for obj in bpy.data.objects: if obj.type == 'ARMATURE': armature_obj = obj print(f"Using first available armature: {armature_obj.name}") break if not armature_obj: print("✗ ERROR: No armature object found in scene") raise Exception("No armature object found - script aborted") print(f"Selected armature object: {armature_obj.name}") # Get the Settings pose bone pose_bone = armature_obj.pose.bones.get('Settings') if not pose_bone: print("✗ ERROR: Settings pose bone not found in armature") print("Available bones:", [bone.name for bone in armature_obj.pose.bones]) raise Exception("Settings pose bone not found - script aborted") print("✓ Settings pose bone found") # Create property name based on active object name property_name = active_obj.name print(f"Creating visibility property: {property_name}") # Remove any existing property with this name to avoid duplication if property_name in pose_bone: del pose_bone[property_name] print(f"Removed existing {property_name} property") # Create custom property as boolean (default to visible) pose_bone[property_name] = True # Set up the property UI ui_data = pose_bone.id_properties_ui(property_name) ui_data.update( description=f"Toggle {active_obj.name} visibility", default=True ) # Make the property overridable for linked rigs try: # Try the newer Blender 4.x API first if hasattr(pose_bone, 'property_overridable_library_set'): pose_bone.property_overridable_library_set(f'["{property_name}"]', True) print(f"✓ Set {property_name} property as library overridable") else: print(f"Note: Library override API not available in this Blender version") except Exception as e: print(f"Note: Could not set library override: {e}") print(f"✓ Created '{property_name}' custom property with library override support") # Set up drivers for object visibility print(f"Setting up drivers for {active_obj.name} object...") try: # Set up drivers for all selected objects for obj in selected_objects: print(f" Setting up drivers for {obj.name}...") # Clear any existing drivers try: obj.driver_remove('hide_render') print(f" Removed existing hide_render driver") except: print(" No existing hide_render driver to remove") try: obj.driver_remove('hide_viewport') print(" Removed existing hide_viewport driver") except: print(" No existing hide_viewport driver to remove") # Create hide_render driver (hide when property = False, show when property = True) driver_fcurve = obj.driver_add('hide_render') driver = driver_fcurve.driver driver.type = 'SUM' var = driver.variables.new() var.name = 'vis_val' var.type = 'SINGLE_PROP' var.targets[0].id_type = 'OBJECT' var.targets[0].id = armature_obj var.targets[0].data_path = f'pose.bones["Settings"]["{property_name}"]' # Use polynomial modifier to invert: hide_render = 1 - vis_val mod = driver_fcurve.modifiers.new('GENERATOR') mod.mode = 'POLYNOMIAL' mod.poly_order = 1 mod.coefficients = (1.0, -1.0) # 1 - x print(f" ✓ Created hide_render driver for {obj.name}") # Create hide_viewport driver (same logic) driver_fcurve = obj.driver_add('hide_viewport') driver = driver_fcurve.driver driver.type = 'SUM' var = driver.variables.new() var.name = 'vis_val' var.type = 'SINGLE_PROP' var.targets[0].id_type = 'OBJECT' var.targets[0].id = armature_obj var.targets[0].data_path = f'pose.bones["Settings"]["{property_name}"]' # Use polynomial modifier to invert: hide_viewport = 1 - vis_val mod = driver_fcurve.modifiers.new('GENERATOR') mod.mode = 'POLYNOMIAL' mod.poly_order = 1 mod.coefficients = (1.0, -1.0) # 1 - x print(f" ✓ Created hide_viewport driver for {obj.name}") except Exception as e: print(f" Error creating drivers: {e}") print("✓ Driver setup complete") # Test the toggle functionality print(f"\n=== Testing {property_name} visibility functionality ===") # Force update to make sure drivers are working bpy.context.view_layer.update() bpy.context.evaluated_depsgraph_get().update() # Initial state (should be visible) print(f"Current state: {property_name} = {pose_bone[property_name]} (True=visible, False=hidden)") for obj in selected_objects: print(f" {obj.name}: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}") # Test toggle to False (objects hidden) print(f"\nToggling to False (objects hidden)...") pose_bone[property_name] = False bpy.context.view_layer.update() bpy.context.evaluated_depsgraph_get().update() print(f"New state: {property_name} = {pose_bone[property_name]}") for obj in selected_objects: print(f" {obj.name}: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}") # Test toggle back to True (objects visible) print(f"\nToggling to True (objects visible)...") pose_bone[property_name] = True bpy.context.view_layer.update() bpy.context.evaluated_depsgraph_get().update() print(f"Final state: {property_name} = {pose_bone[property_name]}") for obj in selected_objects: print(f" {obj.name}: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}") print("\n✓ Custom Visibility script completed successfully!") print(f"The '{property_name}' property is now available on the Settings bone as a checkbox") print(f"Use checkbox to toggle visibility of {len(selected_objects)} selected object(s): {[obj.name for obj in selected_objects]}") print(f" - {property_name} ON (checked): Shows all selected objects") print(f" - {property_name} OFF (unchecked): Hides all selected objects")