Compare commits

...

16 Commits

Author SHA1 Message Date
c7df358fe8 Merge pull request 'fix: shape geometry link behavior.' (#2) from swann.martinez/rig_picker:fix-collection-link-for-create-shape into master
Before the patch, shapes were systematically linked to the scene's main collection (Maybe that's the way it's supposed to be?), regardless of the collection selection. The patch changes this to link geometry only if no canvas collection is selected.

Reviewed-on: #2
Reviewed-by: Jonas Holzman <jonas@autourdeminuit.com>
2025-06-27 16:16:58 +02:00
s.martinez
21c4fe2117 clean: change typo 2025-06-24 18:08:40 +02:00
s.martinez
f35fbb95b8 fix: shape geometry link behavior.
Before the patch, shapes were systematically linked to the scene's main collection, regardless of the collection selection. The patch changes this to link geometry only if no canvas collection is selected.
2025-06-24 17:59:53 +02:00
30064faf3d Create a Property on the scene to handle the use_pick_bone 2025-06-16 15:00:01 +02:00
f4f8ee1613 unregister collection instead scene 2025-06-11 18:38:37 +02:00
e6c9dde63c remove scn.picker : not longer exists 2025-06-11 14:50:27 +02:00
e1abb88b7e create shape in rihg picker collections 2025-06-10 16:53:14 +02:00
747cfa0f7a Show create shape in pose mode context 2025-06-10 16:21:38 +02:00
fbdd994d67 Rename all shapes from related bones name 2025-06-10 15:43:44 +02:00
7d2216bc3b get picker collection since rig is stored on the picker collection and not on the scene 2025-06-10 15:24:10 +02:00
b4defc1296 fix canvas size 2025-06-10 15:24:09 +02:00
6798053389 Update README.md 2024-10-30 17:36:07 +01:00
de3b78e741 Update README.md 2024-10-30 17:35:16 +01:00
76ea717df8 Update README.md 2024-10-30 17:34:17 +01:00
ChristopheSeux
7d2d69ba0f Fix pack picker if missing 2024-03-04 09:55:46 +01:00
ChristopheSeux
75bc414e26 bone space in context menu 2024-02-28 09:59:11 +01:00
9 changed files with 76 additions and 36 deletions

View File

@ -2,6 +2,8 @@
> Blender addon for picking rig contollers
Rig_picker is an OpenGl tool for having a 2d interface for the 3d animators allowing them to pick a controller easily.
The addon is drawing 2d shapes inside a dedicated Node Editor Area using the gpu module.
You can use multiple pickers for one rig, each picker shapes are in there own collection.
Video of the previous version : https://vimeo.com/241970235
@ -23,7 +25,12 @@ Video of the previous version : https://vimeo.com/241970235
<!-- INSTALLATION -->
## Installation
For external user, you can clone the repository using:
```sh
git clone https://git.autourdeminuit.com/autour_de_minuit/rig_picker.git
```
For Internal user:
1. Create your own local directory in
```sh
/home/<USER>/dev

View File

@ -155,6 +155,7 @@ classes = (
def register():
# Remove the tools inside the picker space
bpy.types.WM_OT_tool_set_by_id._execute = bpy.types.WM_OT_tool_set_by_id.execute #tool_set_by_id
bpy.types.WM_OT_tool_set_by_id.execute = tool_set_by_id

View File

@ -459,7 +459,7 @@ class Picker:
if shape.type == 'bone' and shape.hover:
shape.assign_bone_event()
bpy.ops._rigpicker.save_picker(index=self.index)
bpy.ops.rigpicker.save_picker(index=self.index)
def press_event(self, mode='SET'):
for shape in self.shapes:
@ -712,7 +712,7 @@ class PickerGroup:
def load_picker_data(rig):
if 'pickers' in rig.data.rig_picker:
picker_datas = [p.to_dict() for p in rig.rig_picker['pickers']]
picker_datas = [[s.to_dict() for s in p] for p in rig.data.rig_picker['pickers']]
else:
picker_datas = []
@ -736,8 +736,11 @@ def get_picker_path(rig, source, start=None):
def pack_picker(rig, start=None):
if not 'rig_picker' in rig.data:
return
pickers = []
for picker_source in rig.data.get('rig_picker', {}).get('sources', {}):
for picker_source in rig.data['rig_picker'].get('sources', []):
picker_path = get_picker_path(rig, picker_source['source'], start)
if not picker_path.exists():
print(f'{picker_path} not exists')

View File

@ -93,7 +93,7 @@ def get_shape_data(ob, matrix=None, depsgraph=None):
for vert in mesh.vertices:
co = matrix @ (ob.matrix_world @ Vector(vert.co))
points.append([round(co[0]), round(co[1])])
points.append([round(co[0], 1), round(co[1], 1)])
depths += [co[2]]
@ -148,8 +148,8 @@ def get_picker_data(collection):
canvas_coords = [canvas.matrix_world@Vector((p.co)) for p in canvas_points]
height = abs(max(canvas_coords).y - min(canvas_coords).y)
width = abs(max(canvas_coords).x - min(canvas_coords).x)
height = abs(max(co.y for co in canvas_coords) - min(co.y for co in canvas_coords))
width = abs(max(co.x for co in canvas_coords) - min(co.x for co in canvas_coords))
center = sum(canvas_coords, Vector()) / len(canvas_coords)
scale = 2048 / max(height, width)# Reference height for the canvas

View File

@ -68,6 +68,8 @@ class RP_GT_gizmo(Gizmo):
context.region.tag_redraw()
#print(location)
return -1

View File

@ -130,9 +130,8 @@ class RP_OT_box_select(Operator):
return {'RUNNING_MODAL'}
def release_event(self, context):
scn = context.scene
if scn.rig_picker.use_pick_bone:
if get_picker_collection():
self.picker.assign_bone_event()
elif (self.start_mouse[0] != self.mouse[0] or self.start_mouse[1] != self.mouse[1]):
@ -392,24 +391,19 @@ class RP_OT_reload_picker(Operator):
# return
def execute(self, context):
#PICKERS.clear()
if context.object.type == 'ARMATURE':
rig = context.object
else:
collection = get_picker_collection(context.object)
rig = collection.rig_picker.rig
#print('Reload', rig)
load_picker_data(rig)
'''
for area in context.screen.areas:
#print(area.type, is_picker_space(area.spaces.active))
if is_picker_space(area.spaces.active):
print('Tag Redraw Region', area.type)
area.regions[0].tag_redraw()
area.tag_redraw()
'''
return {"FINISHED"}
@ -551,7 +545,8 @@ class RP_MT_context_menu(Menu):
def draw(self, context):
layout = self.layout
col = layout.column()
col.use_property_split = True
col.operator_context = 'INVOKE_DEFAULT'
#col.use_property_split = True
ob = context.object
picker = PICKERS.get(ob)
@ -561,9 +556,25 @@ class RP_MT_context_menu(Menu):
else:
bone = context.active_pose_bone
# Draw Space Switch Operator
if getattr(ob.data, 'space_switch'):
space_switch = ob.data.space_switch
data_paths = [f'pose.bones["{bone.name}"]["{k}"]' for k in bone.keys()]
space_bone = next((s for s in space_switch.bones if s.data_path in data_paths), None)
if space_bone:
index = list(space_switch.bones).index(space_bone)
value = ob.path_resolve(space_bone.data_path)
space = next((s.name for s in space_bone.spaces if s.value == value), None)
op = col.operator("spaceswitch.change_space", text=f'({space})', icon='PINNED')
op.index=index
col.separator()
if bone:
for key in bone.keys():
layout.prop(bone,f'["{key}"]', slider=True)
col.prop(bone,f'["{key}"]', slider=True)
#layout.operator("rigpicker.show_bone_layer", text="Show Bone Layer", ).type = 'ACTIVE'
#layout.operator("rigidbody.objects_add", text="B Add Passive").type = 'PASSIVE'

View File

@ -20,6 +20,14 @@ class RP_OT_create_shape(Operator):
@classmethod
def poll(cls, context):
return (context.object and context.object.mode == 'POSE')
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
for col in bpy.data.collections:
if col.rig_picker.enabled:
self.layout.prop(col.rig_picker, 'link_shape', text=col.name)
def execute(self,context):
scn = context.scene
@ -40,8 +48,10 @@ class RP_OT_create_shape(Operator):
mesh.from_pydata(verts, edges, faces)
for c in scn.rig_picker.canvas.users_collection:
c.objects.link(ob)
picker_selected_cols = [col for col in bpy.data.collections if col.rig_picker.link_shape]
for col in picker_selected_cols or [scn.collection]:
col.objects.link(ob)
ob.location.z = 0.05
ob.location.x = offset
@ -60,16 +70,16 @@ class RP_OT_create_shape(Operator):
class RP_OT_name_from_bone(Operator):
bl_label = 'Name Shape from selected bones'
bl_idname = 'rigpicker.name_from_bone'
bl_description = 'Rename all shapes from related bones name'
#bl_options = {'REGISTER', 'UNDO'}
def execute(self,context):
scene = context.scene
rig = scene.rig_picker.rig
bone = rig.data.bones.active
if bone:
context.object.name = bone.name
context.object.rig_picker.name = bone.name
col = get_picker_collection(context.object)
for ob in col.all_objects:
if ob.rig_picker.shape_type == 'BONE':
ob.name = ob.rig_picker.name
return {'FINISHED'}
@ -84,9 +94,7 @@ class RP_OT_mirror_shape(Operator):
return (context.object and context.object.type in ('MESH', 'CURVE', 'TEXT'))
def execute(self,context):
scn = context.scene
ob = context.object
collection = get_picker_collection(ob)
collection = get_picker_collection(context.object)
objects = context.selected_objects
# Remove mirror object:
@ -95,7 +103,7 @@ class RP_OT_mirror_shape(Operator):
continue
for mod in ob.modifiers:
if (mod.type == 'NODES' and mod.node_group.name == 'Symmetrize' and
if (mod.type == 'NODES' and mod.node_group and mod.node_group.name == 'Symmetrize' and
mod.get('Socket_2') in objects):
bpy.data.objects.remove(ob)
@ -124,7 +132,7 @@ class RP_OT_mirror_shape(Operator):
for mod in list(flipped_object.modifiers):
flipped_object.modifiers.remove(mod)
# Add symmetrize modifier
# Add symmetrize modifier TODO add it into a resource
mod = flipped_object.modifiers.new(name='Symmetrize', type='NODES')
mod.node_group = bpy.data.node_groups['Symmetrize']
mod['Socket_2'] = ob
@ -222,7 +230,6 @@ class RP_OT_save_picker(Operator):
bpy.ops.rigpicker.reload_picker()
return {'FINISHED'}
classes = (

View File

@ -44,14 +44,17 @@ class RP_PG_object_ui_settings(bpy.types.PropertyGroup):
name: StringProperty()
class RP_PG_scene_ui_settings(bpy.types.PropertyGroup):
class RP_PG_collection_ui_settings(bpy.types.PropertyGroup):
enabled : BoolProperty(default=False)
rig: PointerProperty(type=bpy.types.Object)
canvas: PointerProperty(type=bpy.types.Object)
symmetry: PointerProperty(type=bpy.types.Object)
#idname: EnumProperty(items=[])
destination: StringProperty(subtype='FILE_PATH')
#bone_list: bpy.props.EnumProperty(items = bones_item
use_pick_bone : BoolProperty(default=False)
link_shape : BoolProperty(default=False)
class RP_PG_scene_ui_settings(bpy.types.PropertyGroup):
use_pick_bone : BoolProperty(default=False)
@ -78,6 +81,7 @@ class RP_OT_operator_selector(bpy.types.Operator):
classes = (
RP_PG_picker_source,
RP_PG_object_ui_settings,
RP_PG_collection_ui_settings,
RP_PG_scene_ui_settings,
RP_PG_armature_ui_settings,
RP_OT_operator_selector,
@ -89,11 +93,12 @@ def register():
bpy.types.Armature.rig_picker = bpy.props.PointerProperty(type=RP_PG_armature_ui_settings)
bpy.types.Object.rig_picker = bpy.props.PointerProperty(type=RP_PG_object_ui_settings)
bpy.types.Collection.rig_picker = bpy.props.PointerProperty(type=RP_PG_collection_ui_settings)
bpy.types.Scene.rig_picker = bpy.props.PointerProperty(type=RP_PG_scene_ui_settings)
bpy.types.Collection.rig_picker = bpy.props.PointerProperty(type=RP_PG_scene_ui_settings)
def unregister():
del bpy.types.Scene.rig_picker
del bpy.types.Collection.rig_picker
del bpy.types.Object.rig_picker
del bpy.types.Armature.rig_picker

6
ui.py
View File

@ -91,8 +91,12 @@ class RP_PT_shape(bpy.types.Panel):
row = col.row(align=True)
row.operator('rigpicker.create_shape', icon='MESH_DATA', text='Create Shape')
row.operator('rigpicker.mirror_shape', icon='MOD_MIRROR', text='Mirror Shape')
col.operator('rigpicker.name_from_bone', icon='SORTALPHA' , text='Name From Bones')
col.prop(scn.rig_picker, 'use_pick_bone', icon='EYEDROPPER', text='Auto Bone Assign')
col.operator('rigpicker.name_from_bone', icon='SORTALPHA' , text='Name From Bones')
else:
col = layout.column(align=True)
row = col.row(align=True)
row.operator('rigpicker.create_shape', icon='MESH_DATA', text='Create Shape')
if ob.type != 'ARMATURE':
box = layout.box()