full WIP parent operator
parent
8cccc7ba8c
commit
b3edd51284
|
@ -8,6 +8,7 @@ from gp_interpolate.utils import (get_gp_draw_plane,
|
||||||
create_plane,
|
create_plane,
|
||||||
following_keys,
|
following_keys,
|
||||||
place_object_to_ref_facing_cam,
|
place_object_to_ref_facing_cam,
|
||||||
|
empty_at,
|
||||||
attr_set)
|
attr_set)
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,18 +28,11 @@ class GP_OT_parent_layer(bpy.types.Operator):
|
||||||
cls.poll_message_set("Need a Grease pencil object with an active layer")
|
cls.poll_message_set("Need a Grease pencil object with an active layer")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
direct_parent : bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'})
|
direct_parent : bpy.props.BoolProperty(default=False, options={'SKIP_SAVE'})
|
||||||
|
|
||||||
def parent_and_compensate(self, context):
|
def parent_and_compensate(self, obj, bone=None):
|
||||||
settings = context.scene.gp_interpo_settings
|
'''If bone is None, parent layer only to object'''
|
||||||
bone = None
|
self.lay.parent = obj
|
||||||
if settings.target_rig.type == 'ARMATURE':
|
|
||||||
bone = settings.target_rig.pose.bones.get(settings.target_bone)
|
|
||||||
if not bone:
|
|
||||||
self.report({'ERROR'}, f'{settings.target_bone} not found in armature {settings.target_rig.name}')
|
|
||||||
return {'CANCELLED'}
|
|
||||||
|
|
||||||
self.lay.parent = settings.target_rig
|
|
||||||
if bone:
|
if bone:
|
||||||
self.lay.parent_type = 'BONE'
|
self.lay.parent_type = 'BONE'
|
||||||
self.lay.parent_bone = bone.name
|
self.lay.parent_bone = bone.name
|
||||||
|
@ -65,18 +59,24 @@ class GP_OT_parent_layer(bpy.types.Operator):
|
||||||
if not settings.target_rig:
|
if not settings.target_rig:
|
||||||
self.report({'ERROR'}, 'No object Selected')
|
self.report({'ERROR'}, 'No object Selected')
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
if not settings.target_bone:
|
self.bone = None
|
||||||
self.report({'ERROR'}, 'No Bone Selected')
|
if settings.target_rig.type == 'ARMATURE':
|
||||||
return {'CANCELLED'}
|
if not settings.target_bone:
|
||||||
|
self.report({'ERROR'}, 'No Bone Selected')
|
||||||
|
return {'CANCELLED'}
|
||||||
|
self.bone = settings.target_rig.pose.bones.get(settings.target_bone)
|
||||||
|
if not self.bone:
|
||||||
|
self.report({'ERROR'}, f'{settings.target_bone} not found in armature {settings.target_rig.name}')
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
|
||||||
if self.direct_parent:
|
if self.direct_parent:
|
||||||
return self.parent_and_compensate(context)
|
return self.parent_and_compensate(settings.target_rig, settings.target_bone)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
return {'FINISHED'}
|
## Place on a 2d intermediate
|
||||||
|
|
||||||
parent_name = f'ref_{self.gp.name}_{self.lay.info}'
|
parent_name = f'ref_{self.gp.name}_{self.lay.info}'
|
||||||
parent_collec_name = 'gp_parents'
|
parent_collec_name = 'gp_parents'
|
||||||
included_cols = [c.name for c in self.gp.users_collection]
|
included_cols = [c.name for c in self.gp.users_collection]
|
||||||
|
@ -87,20 +87,17 @@ class GP_OT_parent_layer(bpy.types.Operator):
|
||||||
col = bpy.data.collections.get(parent_collec_name)
|
col = bpy.data.collections.get(parent_collec_name)
|
||||||
if not col:
|
if not col:
|
||||||
col = bpy.data.collections.new(parent_collec_name)
|
col = bpy.data.collections.new(parent_collec_name)
|
||||||
|
|
||||||
if col.name not in bpy.context.scene.collection.children:
|
if col.name not in bpy.context.scene.collection.children:
|
||||||
bpy.context.scene.collection.children.link(col)
|
bpy.context.scene.collection.children.link(col)
|
||||||
col.hide_viewport = True
|
## hide parent collection ?
|
||||||
|
# col.hide_viewport = True
|
||||||
|
|
||||||
# Get/create meshplane
|
# Get/create empty parent
|
||||||
parent = bpy.data.objects.get(parent_name)
|
parent = bpy.data.objects.get(parent_name)
|
||||||
if not parent:
|
if not parent:
|
||||||
parent = create_plane(name=parent_name)
|
parent = empty_at(name=parent_name, size=0.1, show_name=True)
|
||||||
parent.select_set(False)
|
parent.select_set(False)
|
||||||
|
|
||||||
if parent.name not in col.objects:
|
|
||||||
col.objects.link(parent)
|
|
||||||
|
|
||||||
## Prepare context manager
|
## Prepare context manager
|
||||||
store_list = [
|
store_list = [
|
||||||
(context.tool_settings, 'use_keyframe_insert_auto', False),
|
(context.tool_settings, 'use_keyframe_insert_auto', False),
|
||||||
|
@ -109,31 +106,32 @@ class GP_OT_parent_layer(bpy.types.Operator):
|
||||||
for vlc in context.view_layer.layer_collection.children:
|
for vlc in context.view_layer.layer_collection.children:
|
||||||
store_list.append(
|
store_list.append(
|
||||||
(vlc, 'exclude', vlc.name not in included_cols),
|
(vlc, 'exclude', vlc.name not in included_cols),
|
||||||
|
# (),
|
||||||
# (vlc, 'hide_viewport', vlc.name not in included_cols), # viewport viz
|
# (vlc, 'hide_viewport', vlc.name not in included_cols), # viewport viz
|
||||||
)
|
)
|
||||||
|
|
||||||
## Offset at curent frame to compensate for object, GP (and GP layer ?) transformations
|
## Offset at curent frame to compensate for object, GP (and GP layer ?) transformations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## If GP object is animated, animate parent obj to compensate
|
## If GP object is animated, animate parent obj to compensate
|
||||||
|
|
||||||
## How to smart-test if self.gp is animated in space ?
|
## How to smart-test if self.gp is animated in space ?
|
||||||
if not is_animated(self.gp):
|
# if not is_animated(self.gp):
|
||||||
# direct parent with one offset
|
|
||||||
pass
|
|
||||||
|
|
||||||
else:
|
with attr_set(store_list):
|
||||||
with attr_set(store_list):
|
parent.animation_data_clear() # Kill animation data to redo it
|
||||||
|
for i in range(scn.frame_start, scn.frame_end+1):
|
||||||
|
scn.frame_set(i)
|
||||||
place_object_to_ref_facing_cam(parent,
|
place_object_to_ref_facing_cam(parent,
|
||||||
ref_ob=settings.target_rig,
|
ref_ob=settings.target_rig,
|
||||||
bone=bone,
|
bone=self.bone,
|
||||||
set_rotation=settings.use_bone_rotation
|
set_rotation=settings.use_bone_rotation)
|
||||||
)
|
parent.keyframe_insert('location')
|
||||||
|
|
||||||
|
parent.keyframe_insert('rotation_euler')
|
||||||
|
parent.keyframe_insert('scale')
|
||||||
|
|
||||||
|
|
||||||
|
self.parent_and_compensate(parent)
|
||||||
print('Done')
|
print('Parent Done')
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
|
5
ui.py
5
ui.py
|
@ -59,7 +59,10 @@ class GP_PT_interpolate(bpy.types.Panel):
|
||||||
if settings.mode == 'FRAME':
|
if settings.mode == 'FRAME':
|
||||||
col.prop(settings, 'padding')
|
col.prop(settings, 'padding')
|
||||||
|
|
||||||
layout.operator('gp.parent_layer', text='Parent Layer To Target')
|
col = layout.column()
|
||||||
|
col.label(text='Layer Parent')
|
||||||
|
col.operator('gp.parent_layer', text='Direct Parent').direct_parent = True
|
||||||
|
col.operator('gp.parent_layer', text='Empty Parent').direct_parent = False
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
GP_PT_interpolate,
|
GP_PT_interpolate,
|
||||||
|
|
21
utils.py
21
utils.py
|
@ -91,6 +91,27 @@ def ray_cast_point(point, origin, depsgraph):
|
||||||
return object_hit, np.array(hit_location), tri, tri_indices
|
return object_hit, np.array(hit_location), tri, tri_indices
|
||||||
|
|
||||||
|
|
||||||
|
def empty_at(name='Empty', pos=(0,0,0), collection=None, type='PLAIN_AXES', size=1, show_name=False):
|
||||||
|
'''
|
||||||
|
Create an empty at given Vector3 position.
|
||||||
|
Optional type (default 'PLAIN_AXES') in ,'ARROWS','SINGLE_ARROW','CIRCLE','CUBE','SPHERE','CONE','IMAGE'
|
||||||
|
default size is 1.0
|
||||||
|
'''
|
||||||
|
|
||||||
|
mire = bpy.data.objects.get(name)
|
||||||
|
if not mire:
|
||||||
|
mire = bpy.data.objects.new(name, None)
|
||||||
|
if collection is None:
|
||||||
|
collection = bpy.context.collection
|
||||||
|
if mire.name not in collection.all_objects:
|
||||||
|
collection.objects.link(mire)
|
||||||
|
|
||||||
|
mire.location = pos
|
||||||
|
mire.empty_display_type = type
|
||||||
|
mire.empty_display_size = size
|
||||||
|
mire.show_name = show_name
|
||||||
|
return mire
|
||||||
|
|
||||||
def plane_on_bone(bone, arm=None, cam=None, set_rotation=True, mesh=True):
|
def plane_on_bone(bone, arm=None, cam=None, set_rotation=True, mesh=True):
|
||||||
'''
|
'''
|
||||||
bone (posebone): reference pose bone
|
bone (posebone): reference pose bone
|
||||||
|
|
Loading…
Reference in New Issue