Skip to content

Instantly share code, notes, and snippets.

@metalix00
Created July 3, 2014 11:38
Show Gist options
  • Save metalix00/f87baf3595e099b82136 to your computer and use it in GitHub Desktop.
Save metalix00/f87baf3595e099b82136 to your computer and use it in GitHub Desktop.
Blender Utilities
"""
Blender Utilities created by Alex Telford for Metalix Studios
alextelford.carbonmade.com
This file contains a sub section of the commands I have converted from Maya to Blender. Enjoy!
"""
import bpy
#from core.lib.types import fi, li, asList, parseArgs
#from blender.utils.nodeTree import addDriver
DEFAULT_ATTRIBUTES = ["Translate X", "Translate Y", "Translate Z",
"Rotate X", "Rotate Y", "Rotate Z",
"Scale X", "Scale Y", "Scale Z", "Visibility"]
IGNORE_ATTRIBUTES = ["_RNA_UI", "cycles_visibility"]
def asList(items):
"""
Usage:
asList(list items)
Description:
returns a list from the input
In:
[type] items
"""
for dataType in [list, tuple]:
if isinstance(items, dataType) or issubclass(type(items), dataType):
return list(items)
if isinstance(items, dict) or issubclass(type(items), dict):
return [value for variable, value in items.iteritems()]
return [items]
def fi(items):
"""
Usage:
fi(list items)
Description:
returns the first item in a list
In:
[list] items
"""
items = asList(items)
if len(items) == 0:
return None
return items[0]
def parseArgs(*args, **kwargs):
for arg in args:
if arg is None:
continue
return arg
if kwargs and "default" in kwargs.keys():
return kwargs.get("default")
return None
def addDriver(baseNode, location, targetId, targetDataPath, index=None):
if index is not None:
driver = baseNode.driver_add(location, index)
else:
driver = baseNode.driver_add(location)
var = driver.driver.variables.new()
var.targets[0].id = targetId
var.targets[0].data_path = '["{0}"]'.format(targetDataPath)
driver.driver.expression = "var"
return driver
def select(objects=None, replace=False, clear=False):
"""
selectObjects(list/string objects)
Selects objects in blender
"""
if clear or replace:
# bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.data.objects:
obj.select = False
if clear:
return
if not isinstance(objects, list):
objects = [objects]
for obj in objects:
obj.select = True
bpy.context.scene.objects.active = obj
def listAttr(node):
if isinstance(node, list):
results = []
for n in node:
results.append(listAttr(n))
return list(set(results))
return asObject(node).keys()
def ls(search=None, selection=None, sl=None):
selection = parseArgs(selection, sl, default=False)
if selection:
# try:
# objs = bpy.context.selected_objects
# except:
objs = [obj for obj in bpy.data.objects if obj.select]
active_object = MSContext().active_object
if active_object:
if active_object in objs:
objs.remove(active_object)
objs.insert(0, active_object)
else:
objs = bpy.data.objects
if search is not None:
objs = [obj for obj in objs if search in obj.name]
return objs
def getAttributes(nodes=None):
nodes = nodes or ls(sl=1)
default = DEFAULT_ATTRIBUTES
data = {}
for node in nodes:
nodeAttributes = [k for k in node.keys() if k not in IGNORE_ATTRIBUTES]
for attr in nodeAttributes:
if attr not in data.keys():
data[attr] = 1
else:
data[attr] += 1
customAttributes = [key for key in data.keys() if data[key] == len(nodes)]
return dict(default=default, custom=customAttributes)
def get3DWindow():
for win in fi(bpy.data.window_managers).windows:
for area in [area for area in win.screen.areas if area.type=="VIEW_3D"]:
return fi([region for region in area.regions if region.type=="WINDOW"])
def getContext(context=None):
return MSContext().context
class MSContext(object):
def __init__(self):
"""
VIEW_3D|WINDOW
TIMELINE|WINDOW
"""
super(MSContext, self).__init__()
self._areaType = "VIEW_3D"
self._regionType = "WINDOW"
self._mode = "OBJECT"
self._active_operator = None
@property
def context(self):
results = dict()
for f, m in MSContext.__dict__.items():
if f.startswith("__"):
continue
results[f] = m
return results
"""
OBJECTS
"""
@property
def active_object(self):
return self.scene.objects.active
@active_object.setter
def active_object(self, obj):
inObj = obj
obj = asObject(obj)
if not obj:
raise RuntimeError("{0} does not exist in this scene".format(inObj))
self.scene.objects.active = obj
@property
def particle_edit_object(self):
return self.active_object
@property
def object(self):
return self.active_object
@property
def edit_object(self):
return self.active_object
@property
def sculpt_object(self):
obj = self.active_object
if not obj.type == "MESH":
return None
return self.active_object
@property
def selectable_objects(self):
return [obj for obj in self.scene.objects if not obj.hide_select]
@property
def selected_editable_objects(self):
return ls(sl=1)
@property
def selected_objects(self):
return ls(sl=1)
@selected_objects.setter
def selected_objects(self, objects):
objects = [asObject(obj) for obj in objects]
for obj in self.scene.objects:
obj.select = bool(obj in objects)
@property
def visible_objects(self):
return [obj for obj in bpy.data.objects if obj.is_visible(self.scene)]
@property
def weight_paint_object(self):
return self.active_object
@property
def vertex_paint_object(self):
return self.active_object
"""
BASES
"""
@property
def active_base(self):
return self.scene.object_bases.active
@property
def selectable_bases(self):
# Implement this at some point
return self.scene.object_bases
@property
def selected_bases(self):
# Implement this at some point
return None
@property
def visible_bases(self):
# Implement this at some point
return self.scene.object_bases
@property
def selected_editable_bases(self):
# Implement this at some point
return self.scene.object_bases
"""
BONES
"""
@property
def editable_bones(self):
# Implement this at some point
return self.active_object.data.bones
@property
def selected_bones(self):
obj = self.active_object
if not obj.type == "ARMATURE":
return None
return [bone for bone in obj.bones if not bone.hide_select]
@property
def selected_editable_bones(self):
# Implement this at some point
return self.selected_bones
@property
def selected_pose_bones(self):
# Implement this at some point
return self.selected_bones
@property
def visible_bones(self):
# Implement this at some point
return self.active_object.data.bones
@property
def active_pose_bone(self):
bone = self.active_bone
if not bone:
return None
pose = self.active_object.pose.bones.get(bone.name)
return pose
@property
def active_bone(self):
obj = self.active_object
if not obj.type == "ARMATURE":
return None
return obj.data.bones.active
@property
def visible_pose_bones(self):
# Implement this at some point
return self.visible_bones
"""
WINDOW
"""
@property
def window(self):
return fi(self.window_manager.windows)
@property
def region(self):
area = self.area
if not area:
return
region = fi([r for r in area.regions if r.type==self._regionType])
return region
@property
def screen(self):
return self.window.screen
@property
def region_data(self):
return None
@property
def space_data(self):
#TODO
pass
@property
def scene(self):
return bpy.context.scene
@property
def area(self):
for win in self.window_manager.windows:
area = fi([a for a in win.screen.areas if a.type==self._areaType])
if not area:
continue
return area
@area.setter
def area(self, area):
self._areaType = area
@property
def window_manager(self):
return bpy.data.window_managers[0]
"""
OTHER
"""
@property
def active_operator(self):
return self._active_operator
@active_operator.setter
def active_operator(self, operator):
self._active_operator = operator
@property
def mode(self):
return self._mode
@property
def tool_settings(self):
return self.scene.tool_settings
"""
SEQUENCES
"""
@property
def selected_sequences(self):
# Implement this at some point
return None
@property
def selected_editable_sequences(self):
# Implement this at some point
return None
@property
def sequences(self):
# Implement this at some point
return None
def groupNodes(nodes=None, name="group"):
selection = nodes or ls(sl=1)
bpy.ops.object.empty_add(type='PLAIN_AXES')
empty = ls(sl=1)[0]
empty.name = name
select(selection, replace=True)
bpy.context.scene.objects.active = empty
bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
select(selection, replace=True)
select(selection, replace=True)
return empty
class CONSTRAINTS(object):
parent = "COPY_TRANSFORMS"
point = "COPY_LOCATION"
orient = "COPY_ROTATION"
scale = "COPY_SCALE"
def parentConstraint(source, target, maintainOffset=False, influence=1.0):
constraint = createConstraint(source, target, CONSTRAINTS.parent, maintainOffset, influence)
return constraint
def pointConstraint(source, target, maintainOffset=False, influence=1.0, x=True, y=True, z=True):
constraint = createConstraint(source, target, CONSTRAINTS.point, maintainOffset, influence)
constraint.use_x = x
constraint.use_y = y
constraint.use_z = z
return constraint
def orientConstraint(source, target, maintainOffset=False, influence=1.0, x=True, y=True, z=True):
constraint = createConstraint(source, target, CONSTRAINTS.orient, maintainOffset, influence)
constraint.use_x = x
constraint.use_y = y
constraint.use_z = z
return constraint
def scaleConstraint(source, target, maintainOffset=False, influence=1.0, x=True, y=True, z=True):
constraint = createConstraint(source, target, CONSTRAINTS.scale, maintainOffset, influence)
constraint.use_x = x
constraint.use_y = y
constraint.use_z = z
return constraint
def createConstraint(source, target, type=CONSTRAINTS.parent, maintainOffset=False, influence=1.0):
source = asObject(source)
target = asObject(target)
constraint = source.constraints.new(type)
constraint.target = target
constraint.influence = influence
if maintainOffset:
constraint.target_space = "LOCAL"
constraint.owner_space = "LOCAL"
return constraint
def asObject(obj):
if issubclass(type(obj), str):
return bpy.data.objects[obj]
return obj
def asNode(obj, dataType=None):
"""
This will determine what type of node the input is and return it as a blender object
If the input is not a string, it is returned directly.
if dataType, it will look for the node in that particular area
"""
if not issubclass(type(obj), str):
return obj
if dataType in ["object"]:
return bpy.data.objects.get(obj)
if dataType in ["mesh"]:
return bpy.data.meshes.get(obj)
if dataType in ["camera"]:
return bpy.data.cameras.get(obj)
if dataType in ["text"]:
return bpy.data.texts.get(obj)
if dataType in ["speaker"]:
return bpy.data.speakers.get(obj)
if dataType in ["sound"]:
return bpy.data.sounds.get(obj)
if dataType in ["lamp", "light"]:
return bpy.data.lamps.get(obj)
if dataType in ["lattice"]:
return bpy.data.lattices.get(obj)
if dataType in ["library"]:
return bpy.data.libraries.get(obj)
if dataType in ["image"]:
return bpy.data.images.get(obj)
if dataType in ["curve"]:
return bpy.data.curves.get(obj)
if dataType in ["metaball"]:
return bpy.data.metaballs.get(obj)
if dataType in ["armature", "rig"]:
return bpy.data.armatures.get(obj)
for module in [bpy.data.objects, bpy.data.meshes, bpy.data.cameras, bpy.data.lamps,
bpy.data.curves, bpy.data.metaballs, bpy.data.armatures, bpy.data.lattices,
bpy.data.libraries, bpy.data.texts, bpy.data.speakers, bpy.data.sounds,
bpy.data.images]:
item = module.get(obj)
if item:
return item
return None
def objectType(obj, isa=None):
nodeType = "unknown"
if not issubclass(type(obj), str):
obj = asObject(obj)
for dataType, module in {"object": bpy.data.objects,
"mesh": bpy.data.meshes,
"camera": bpy.data.cameras,
"lamp": bpy.data.lamps,
"curve": bpy.data.curves,
"metaball": bpy.data.metaballs,
"armature": bpy.data.armatures,
"lattice": bpy.data.lattices,
"library": bpy.data.libraries,
"text": bpy.data.texts,
"speaker": bpy.data.speakers,
"sound": bpy.data.sounds,
"image": bpy.data.images}.items():
if obj in module.values():
nodeType = dataType
break
if isa is not None:
return bool(nodeType == isa)
return nodeType
def createLocator(name, parent=None, type="PLAIN_AXES"):
selection = ls(sl=1)
bpy.ops.object.empty_add(type=type)
locator = ls(sl=1)[0]
locator.name = name
if selection:
select(selection, replace=True)
return locator
def parent(parentObject, children, maintainOffset=True):
children = asList(children)
for child in children:
matrix = child.matrix_world
child.parent = parentObject
if maintainOffset:
child.matrix_world = matrix
def delete(obj, removeData=True):
obj = asObject(obj)
data = obj.data
if not data:
removeData = False
else:
if data.users > 1:
removeData = False
for scene in obj.users_scene:
scene.objects.unlink(obj)
bpy.data.objects.remove(obj)
if removeData:
deleteData(data)
def deleteData(data):
if data.users == 0:
data.user_clear()
#mesh
if type(data) == bpy.types.Mesh:
bpy.data.meshes.remove(data)
#lamp
if type(data) == bpy.types.PointLamp:
bpy.data.lamps.remove(data)
#camera
if type(data) == bpy.types.Camera:
bpy.data.cameras.remove(data)
#text, curve
if type(data) in [bpy.types.Curve, bpy.types.TextCurve]:
bpy.data.curves.remove(data)
#metaball
if type(data) == bpy.types.MetaBall:
bpy.data.metaballs.remove(data)
#lattice
if type(data) == bpy.types.Lattice:
bpy.data.lattices.remove(data)
#armature
if type(data) == bpy.types.Armature:
bpy.data.armatures.remove(data)
def clearLibraries():
for lib in bpy.data.libraries:
lib.user_clear()
lib.filepath = ""
def connect(source, sourceAttr, target, targetAttr=None, index=None):
source = asObject(source)
target = asObject(target)
targetAttr = targetAttr or sourceAttr
return addDriver(source, '["{0}"]'.format(sourceAttr), target.id_data, targetAttr, index)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment