custom_shelf initial commit
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
info = {
|
||||
'icon' : 'FILE_TEXT',
|
||||
'description' : 'explore API in console at datapath of the popup',
|
||||
'data_path' : ''
|
||||
}
|
||||
|
||||
import bpy, mathutils
|
||||
|
||||
exclude = (
|
||||
### add lines here to exclude specific attribute
|
||||
'bl_rna', 'identifier','name_property','rna_type','properties',#basic
|
||||
## To avoid recursion/crash on direct object call (comment for API check on deeper props)
|
||||
'data', 'edges', 'faces', 'edge_keys', 'polygons', 'loops', 'face_maps', 'original',
|
||||
## Avoid some specific properties
|
||||
#'matrix_local', 'matrix_parent_inverse', 'matrix_basis','location','rotation_euler', 'rotation_quaternion', 'rotation_axis_angle', 'scale', 'translation',
|
||||
)
|
||||
|
||||
def list_attr(path, ct=0):
|
||||
for attr in dir(eval(path)):
|
||||
if not attr.startswith('__') and not attr in exclude:
|
||||
try:
|
||||
value = getattr(eval(path),attr)
|
||||
except AttributeError:
|
||||
value = None
|
||||
if value != None:
|
||||
if not callable(value):
|
||||
if type(value) in ( type(0),type(0.0),type(True),type('str'),type(mathutils.Vector()),type(mathutils.Color()), type(mathutils.Matrix()) ):
|
||||
print(ct*' ' + attr, value)
|
||||
else:
|
||||
print(ct*' ' + attr,value,type(value))
|
||||
ct+=1
|
||||
# print (ct*' ' + '>')
|
||||
list_attr('%s.%s'%(path,attr), ct)#Comment this line to kill recursion
|
||||
|
||||
|
||||
print('---')
|
||||
# write datapath as string. ex : "bpy.data.objects['Cube'].modifiers['Softbody']"
|
||||
|
||||
dt = info['data_path']
|
||||
if dt:
|
||||
list_attr(dt)
|
||||
print ('Done')
|
||||
else:
|
||||
print('no data path given')
|
||||
@@ -0,0 +1,56 @@
|
||||
info = {
|
||||
'icon' : 'EVENT_X',
|
||||
'description' : 'Delete all blend backup version (.blend1 and next backups) in passed directory',
|
||||
'folderpath' : '',
|
||||
'recursive' : True,
|
||||
'test' : False,
|
||||
}
|
||||
|
||||
# coding: utf-8
|
||||
import bpy
|
||||
import os
|
||||
import re, fnmatch, glob
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
C = bpy.context
|
||||
D = bpy.data
|
||||
scene = C.scene
|
||||
|
||||
|
||||
def kill_blend_backup_version(fp, recursive=True, test=False):
|
||||
if not fp:
|
||||
print('ERROR', 'no filepath given')
|
||||
return
|
||||
|
||||
re_blendbackup = re.compile(r'\.blend\d+')
|
||||
fpo = Path(fp)
|
||||
|
||||
if not fpo.exists():
|
||||
print('ERROR', f'invalid path: {fp}')
|
||||
return
|
||||
|
||||
ct = 0
|
||||
print(f'Removing blend backup files in : {fpo}')
|
||||
if recursive:
|
||||
for root, dirs, files in os.walk(fp):
|
||||
for name in files:
|
||||
fo = Path(root) / name
|
||||
if re_blendbackup.match(fo.suffix):
|
||||
ct += 1
|
||||
print(fo)
|
||||
if not test:
|
||||
fo.unlink()
|
||||
|
||||
else:
|
||||
for f in os.listdir(fp):
|
||||
fo = Path(fp) / f
|
||||
if re_blendbackup.match(fo.suffix):
|
||||
ct += 1
|
||||
print(fo)
|
||||
if not test:
|
||||
fo.unlink()
|
||||
|
||||
if ct:
|
||||
print('INFO', f'Deleted {ct} file(s)')
|
||||
|
||||
kill_blend_backup_version(info['folderpath'], recursive = info['recursive'], test = info['test'])
|
||||
@@ -0,0 +1,71 @@
|
||||
info = {
|
||||
'icon' : 'LIBRARY_DATA_BROKEN',
|
||||
'description' : 'Correct path (print in console, apply as option) when weirdly auto added unwanted parent directory (still break rotate order for armatures...)',
|
||||
'apply' : False
|
||||
}
|
||||
|
||||
import bpy
|
||||
import os
|
||||
from os import listdir
|
||||
from os.path import join, dirname, basename, exists, isfile, isdir, splitext, abspath
|
||||
import re, fnmatch, glob
|
||||
from mathutils import Vector, Matrix
|
||||
from math import radians, degrees
|
||||
C = bpy.context
|
||||
D = bpy.data
|
||||
scene = C.scene
|
||||
|
||||
""" rel = D.libraries[0].filepath.replace('//','')
|
||||
parent = rel.count('..')
|
||||
print('parent: ', parent)
|
||||
abspath(join(dirname(D.filepath), rel)) """
|
||||
|
||||
|
||||
## relpath
|
||||
|
||||
def to_abs(rfp):
|
||||
return abspath(bpy.path.abspath(rfp))
|
||||
|
||||
print('\n--- Cheking libraries filepath ---')
|
||||
apply = False
|
||||
apply = info['apply']#get it from info dic
|
||||
|
||||
folder = dirname(D.filepath)
|
||||
for lib in D.libraries:
|
||||
libfp = lib.filepath
|
||||
if exists(to_abs(libfp)):
|
||||
print('clean :', libfp)
|
||||
else:
|
||||
print('broken:', libfp)
|
||||
pct = libfp.count('..')
|
||||
for i in range(1, pct+1):
|
||||
newrel = ('').join(libfp.split('../',i))
|
||||
if exists(to_abs(newrel)):
|
||||
print(f'found at -{i} parent folder')
|
||||
print(f'-> {newrel}')
|
||||
if apply:
|
||||
lib.filepath = newrel
|
||||
print()
|
||||
break
|
||||
if i == pct:
|
||||
print(f'tested with {pct} folder up and nothing found')
|
||||
print('Done.')
|
||||
|
||||
'''
|
||||
## abspath technique
|
||||
folder = dirname(D.filepath)
|
||||
for lib in D.libraries:
|
||||
curfp = abspath(bpy.path.abspath(lib.filepath))
|
||||
if exists(curfp):
|
||||
print('clean :', lib.filepath)
|
||||
else:
|
||||
print('broken:', lib.filepath)
|
||||
pct = lib.filepath.count('..')
|
||||
print('up folder: ', pct)
|
||||
endlib = lib.filepath.lstrip(os.sep+'.')
|
||||
for i in range(1, pct+1):
|
||||
start = '/'.join(folder.split(os.sep)[:-i])
|
||||
nfp = join(start, endlib)
|
||||
if exists(nfp):
|
||||
print(f'{i} parent folder VS {pct} in current')
|
||||
'''
|
||||
@@ -0,0 +1,60 @@
|
||||
info = {
|
||||
'icon' : 'ARMATURE_DATA',
|
||||
'description' : 'run some check on proxys and armautre and print in console',
|
||||
}
|
||||
|
||||
# coding: utf-8
|
||||
import bpy
|
||||
import os
|
||||
from os import listdir
|
||||
from os.path import join, dirname, basename, exists, isfile, isdir, splitext
|
||||
import re, fnmatch, glob
|
||||
from mathutils import Vector, Matrix
|
||||
from math import radians, degrees
|
||||
C = bpy.context
|
||||
D = bpy.data
|
||||
scene = bpy.context.scene
|
||||
|
||||
print('\nCollection instance check -- ')
|
||||
problems = []
|
||||
for o in bpy.context.scene.objects:
|
||||
if o.instance_collection:
|
||||
for instob in o.instance_collection.objects:
|
||||
badname = withproxy = withcolproxy = alert = ''
|
||||
|
||||
if instob.type == 'ARMATURE':
|
||||
mess = f'{o.name} -> rig: {instob.name}'
|
||||
arm = instob.data
|
||||
# print("arm", arm.name)#Dbg
|
||||
if instob.name != arm.name:
|
||||
badname = 1
|
||||
mess += f' != arm data: {arm.name}'
|
||||
rigname = arm.name.replace('_rig','_proxy') if 'rig' in arm.name else arm.name + '_proxy'
|
||||
|
||||
proxy = bpy.context.scene.objects.get(rigname)
|
||||
|
||||
if proxy:
|
||||
withproxy = 1
|
||||
mess += ' ->> Proxy in scene'
|
||||
if not proxy:
|
||||
collec_proxy = instob.name.replace('_rig','_proxy') if 'rig' in instob.name else instob.name + '_proxy'
|
||||
proxy = bpy.context.scene.objects.get(collec_proxy)
|
||||
if proxy :
|
||||
withcolproxy = 1
|
||||
mess += ' ->> Proxy from colname in scene'
|
||||
|
||||
if proxy and proxy.animation_data and proxy.animation_data.action and len(proxy.animation_data.action.fcurves) > 0:
|
||||
mess += ' (animated)'
|
||||
|
||||
if badname and withcolproxy:
|
||||
alert = '!!!'
|
||||
elif badname and withproxy:
|
||||
alert = '!!'
|
||||
elif badname:
|
||||
alert = '!'
|
||||
mess = f'{alert} {mess}'
|
||||
if badname or withproxy or withcolproxy:
|
||||
problems.append(mess)
|
||||
print(mess)
|
||||
|
||||
print('Done')
|
||||
@@ -0,0 +1,140 @@
|
||||
info = {
|
||||
'icon' : 'DRIVER',
|
||||
'description' : 'create visibility on driver objects or armature selection from a bone of a rig',
|
||||
'prop_rig' : 'name_of_the_rig'
|
||||
'prop_name' : 'hide_something'
|
||||
'prop_bone' : 'root'
|
||||
}
|
||||
|
||||
import bpy
|
||||
|
||||
def add_driver(source, target, prop, dataPath, index = -1, negative = False, func = ''):
|
||||
''' Add driver to source prop (at index), driven by target dataPath '''
|
||||
|
||||
source.driver_remove(prop, index)
|
||||
if index != -1:
|
||||
d = source.driver_add( prop, index ).driver
|
||||
else:
|
||||
d = source.driver_add( prop ).driver
|
||||
|
||||
v = d.variables.new()
|
||||
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
|
||||
|
||||
def create_hide_custom_prop(src_object, prop_name, prop_bone = ''):
|
||||
'''
|
||||
add source propertie with boolean option
|
||||
place the hide prop on src_object with name prop_name
|
||||
'''
|
||||
|
||||
rig = bpy.data.objects.get(src_object)
|
||||
if not rig:
|
||||
print(f"No objects named {src_object}")
|
||||
return 1
|
||||
if rig.type != 'ARMATURE':
|
||||
print(f"Not an armature : {src_object}")
|
||||
return 1
|
||||
|
||||
#add target bone
|
||||
if prop_bone:
|
||||
holder = rig.pose.bones.get(prop_bone)
|
||||
else:
|
||||
holder = rig.pose.bones.get('root')
|
||||
|
||||
if not holder:
|
||||
print(f'problem finding bone {prop_bone} (or root)')
|
||||
return 1
|
||||
|
||||
# create
|
||||
if not holder.get('_RNA_UI'):
|
||||
holder['_RNA_UI'] = {}
|
||||
|
||||
if not prop_name in holder.keys() :
|
||||
holder[prop_name] = 0
|
||||
holder['_RNA_UI'][prop_name] = {"default": 0,"min":0,"max":1,"soft_min":0,"soft_max":1}
|
||||
else:
|
||||
print(f'{prop_name} : already exists on root key')
|
||||
return
|
||||
|
||||
return 0
|
||||
|
||||
def drive_selection_visibility(rig, prop_name, prop_bone = ''):
|
||||
# add driver on selection
|
||||
prefixs = ('MCH','DEF','ORG', 'WGT')
|
||||
|
||||
rig = bpy.data.objects.get(src_object)
|
||||
if not rig:
|
||||
print(f"No objects named {src_object}")
|
||||
return 1
|
||||
if rig.type != 'ARMATURE':
|
||||
print(f"Not an armature : {src_object}")
|
||||
return 1
|
||||
|
||||
#add target bone
|
||||
|
||||
if not prop_bone:
|
||||
prop_bone = 'root'
|
||||
if not rig.pose.bones.get(prop_bone):
|
||||
print(f'no bones {prop_bone} on rig {rig.name}')
|
||||
return 1
|
||||
|
||||
meshes = [i for i in bpy.context.selected_objects if i.type in ('MESH','CURVE','TEXT') and not i.name.startswith(('WGT', 'WDGT'))]
|
||||
armatures = [i for i in bpy.context.selected_objects if i.type == 'ARMATURE']
|
||||
|
||||
if bpy.context.mode == 'POSE':
|
||||
obarm = bpy.context.active_object
|
||||
for bone in bpy.context.selected_pose_bones_from_active_object:
|
||||
prop = 'bones["%s"].hide'%bone.name
|
||||
index = -1
|
||||
layer = bone.bone.layers
|
||||
protect_layer = rig.data.layers_protected
|
||||
### dont check for protected, strictly use selection.
|
||||
# if bone.name.startswith(prefixs) or any([i==j==1 for i,j in zip(layer,protect_layer)]) :
|
||||
# print(f'Skipped : Prefixed or protected bone : {bone.name}')
|
||||
# rig.data.driver_remove(prop, index)
|
||||
# continue
|
||||
print(f'New : Driver on bone {bone.name}')
|
||||
add_driver(obarm.data, rig, prop, f'pose.bones["{prop_bone}"]["{prop_name}"]', index)
|
||||
return
|
||||
|
||||
for ob in meshes :
|
||||
print('Object : ', obarm.name)
|
||||
|
||||
add_driver(ob, rig, 'hide_viewport', f'pose.bones["{prop_bone}"]["{prop_name}"]', -1)
|
||||
add_driver(ob, rig, 'hide_render', f'pose.bones["{prop_bone}"]["{prop_name}"]', -1)
|
||||
|
||||
for obarm in armatures:
|
||||
print('Armature : ', obarm.name)
|
||||
## mask armature object
|
||||
## add_driver(obarm, rig, 'hide_viewport', f'pose.bones["{prop_bone}"]["{prop_name}"]', -1)
|
||||
## bette mask pose bones since its a proxy...
|
||||
for bone in obarm.pose.bones :
|
||||
prop = 'bones["%s"].hide'%bone.name
|
||||
index = -1
|
||||
layer = bone.bone.layers
|
||||
protect_layer = rig.data.layers_protected
|
||||
if bone.name.startswith(prefixs) or any([i==j==1 for i,j in zip(layer,protect_layer)]) :
|
||||
print(f'Skipped : Prefixed or protected bone : {bone.name}')
|
||||
rig.data.driver_remove(prop, index)
|
||||
else :
|
||||
print(f'New : Driver on bone {bone.name}')
|
||||
add_driver(obarm.data, rig, prop, f'pose.bones["{prop_bone}"]["{prop_name}"]', index)
|
||||
|
||||
### ----
|
||||
|
||||
## write the name of the rig source (will put the propertie on the root of this armature)
|
||||
|
||||
prop_rig = info['prop_rig']# name_of_the_rig
|
||||
|
||||
## write the name of the propertie to attach
|
||||
prop_name = info["prop_name"]#'hide_headband'# hide_something
|
||||
|
||||
## prop_bone (bone holding the propertie), 'root' if left string empty.
|
||||
prop_bone = info["prop_bone"]
|
||||
|
||||
|
||||
create_hide_custom_prop(prop_rig, prop_name, prop_bone = prop_bone)
|
||||
drive_selection_visibility(prop_rig, prop_name, prop_bone = prop_bone)
|
||||
@@ -0,0 +1,27 @@
|
||||
info = {
|
||||
'icon' : 'ACTION_TWEAK',
|
||||
'description' : 'Rename selected armature actions (with name of the rig, replacing "_rig" with "_act")',
|
||||
}
|
||||
|
||||
# coding: utf-8
|
||||
import bpy
|
||||
import os
|
||||
from os import listdir
|
||||
from os.path import join, dirname, basename, exists, isfile, isdir, splitext
|
||||
import re, fnmatch, glob
|
||||
from mathutils import Vector, Matrix
|
||||
from math import radians, degrees
|
||||
C = bpy.context
|
||||
D = bpy.data
|
||||
scene = C.scene
|
||||
|
||||
for o in C.selected_objects:
|
||||
if o.type == 'ARMATURE':
|
||||
print(o.animation_data.action.name)
|
||||
if '_rig' in o.name:
|
||||
action = o.animation_data.action
|
||||
if action.name.replace('_act','') != o.name.replace('_rig', ''):
|
||||
newname = o.name.replace('_rig', '_act')
|
||||
print(f'action rename {action.name} > {newname}')
|
||||
action.name = newname
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
info = {
|
||||
'icon' : 'HIDE_OFF',
|
||||
'description' : 'Force viewport visibility ON for objects with hide_viewport prop animated',
|
||||
}
|
||||
|
||||
# coding: utf-8
|
||||
import bpy
|
||||
import os
|
||||
from os import listdir
|
||||
from os.path import join, dirname, basename, exists, isfile, isdir, splitext
|
||||
import re, fnmatch, glob
|
||||
from mathutils import Vector, Matrix
|
||||
from math import radians, degrees
|
||||
C = bpy.context
|
||||
D = bpy.data
|
||||
scene = C.scene
|
||||
|
||||
import bpy
|
||||
for o in bpy.context.scene.objects:
|
||||
if o.animation_data and o.animation_data.action and o.animation_data.action.fcurves.find('hide_viewport'):
|
||||
o.hide_viewport = False
|
||||
@@ -0,0 +1,22 @@
|
||||
info = {
|
||||
'icon' : 'OUTLINER_OB_ARMATURE',
|
||||
'description' : 'Hide/Unhide all rigs',
|
||||
}
|
||||
|
||||
import bpy
|
||||
C = bpy.context
|
||||
D = bpy.data
|
||||
scene = C.scene
|
||||
|
||||
#hide armature
|
||||
hide = True
|
||||
|
||||
arms = [o for o in C.scene.objects if o.type == 'ARMATURE']
|
||||
if arms:
|
||||
hide = not arms[0].hide_viewport
|
||||
|
||||
#invert of the state of the first armature found for all of them
|
||||
for o in C.scene.objects:
|
||||
if o.type == 'ARMATURE':
|
||||
o.hide_viewport = hide
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import bpy
|
||||
from bpy import data as D
|
||||
ob = D.objects['boom_hairs_group_ref']
|
||||
|
||||
ob.hide_viewport = not ob.hide_viewport
|
||||
Reference in New Issue
Block a user