Created
July 3, 2014 11:38
-
-
Save metalix00/f87baf3595e099b82136 to your computer and use it in GitHub Desktop.
Blender Utilities
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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