I have an armature with multiple bones and a different object connected to each bone
when I hide my bone I want the object that is connected to it to hide as well
How do I achieve this? maybe via driver?
Blender Stack Exchange is a question and answer site for people who use Blender to create 3D graphics, animations, or games. It only takes a minute to sign up.
Sign up to join this communityI have an armature with multiple bones and a different object connected to each bone
when I hide my bone I want the object that is connected to it to hide as well
How do I achieve this? maybe via driver?
yes you can, but it works "not fine":
right click on your bones "TV" -> copy as new driver
then right click on your objects "TV" and click "paste driver".
Then it "kind of" works.
The disadvantage: if you are in pose mode and press H you have to change to object/edit mode so that the object hides too....
To make it work in rendering as well, copy paste the driver to the object camera Icon.
Good to know the more simple answer works, but I also wrote a custom operator to accomplish this task, It works in pose and edit_armature mode, but does not yet have an "unhide" method that works in reverse. I will leave this to you to reverse engineer how to accomplish.
It only works if the object is parented to the bone via Parent> Bone not Parent > With Automatic Weights or any of the other ones, but I figure you know this.
You can just run the script in the text editor, call it from the search menu and then set a hotkey for it there.
import bpy
class ToggleHiddenObjectBone(bpy.types.Operator):
bl_idname = "object.toggle_hide_bone_object"
bl_label = "Toggle Hide on Parented Bones and Objects"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.active_bone is not None and context.mode in {"POSE", "EDIT_ARMATURE"}
def invoke(self, context, event):
self.mode = context.mode
self.parent_bones = dict(zip(
[obj.parent_bone for obj in bpy.data.objects],
[obj.name for obj in bpy.data.objects],
))
self.bone = context.active_bone
self.armature = [
arm for arm in bpy.data.armatures[:]
if self.bone.basename in
[bone.basename for bone in arm.bones[:]
]][0]
try:
self.obj_name = self.parent_bones[self.bone.name]
except KeyError:
self.report({"INFO"}, "Bone not found in object parent bones, make sure you set 'Parent > Bone'")
return {"CANCELLED"}
if not self.obj_name:
self.report({"INFO"}, "Active bone has no child object.")
return {"CANCELLED"}
else:
return self.execute(context)
def execute(self, context):
obj = bpy.data.objects[self.obj_name]
if self.mode == "POSE":
bpy.ops.pose.hide()
else:
bpy.ops.armature.hide()
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.select_all(action="DESELECT")
context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.hide_view_set()
context.view_layer.objects.active = bpy.data.objects[self.armature.name]
print(context.view_layer.objects.active)
try:
bpy.ops.object.mode_set(mode=self.mode)
except TypeError:
bpy.ops.object.mode_set(mode="EDIT")
return {'FINISHED'}
# Register and add to the "object" menu (required to also use F3 search "Simple Object Operator" for quick access).
def register():
bpy.utils.register_class(ToggleHiddenObjectBone)
def unregister():
bpy.utils.unregister_class(ToggleHiddenObjectBone)
if __name__ == "__main__":
register()
Using this answer
you can achieve the same process via scripting, just in case you want to automate the process
import bpy
from bpy import context
def add_hide_driver(
source, target, prop, dataPath,
index = -1, negative = False, func = ''):
if index != -1:
d = source.driver_add( prop, index ).driver
else:
d = source.driver_add( prop ).driver
v = d.variables.new()
v.name = prop
v.targets[0].id_type = 'ARMATURE'
v.targets[0].id = target
v.targets[0].data_path = dataPath
d.expression = func + "(" + v.name + ")" if func else v.name
d.expression = d.expression if not negative else "-1 * " + d.expression
armature=bpy.data.armatures["Armature"]
for bone in armature.bones:
target_obj=bpy.data.objects[bone.name]
add_hide_driver(target_obj,bone.id_data, 'hide_render', 'bones["'+bone.name+'"].hide')
This will achieve the same thing as copying driver from TV to Camera as mentioned in this answer