Here’s the rename addon:
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "MultiRename_dom",
"author": "dom107",
"version": (1,0),
"blender": (2, 6, 3),
"location": "View3D > Toolbar",
"description": "Provides a find & replace function for renaming multiple objects and bones",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Object"}
# Adapted from a script by Maximilian Eham
# as found at http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Object/Object_Multi_Rename on 2012/08/16
import re, fnmatch
import bpy
from bpy.props import *
from bpy.app.handlers import persistent
def draw_rename_panel(self, context):
layout = self.layout
sce = context.scene
mode = context.mode
col = layout.column(align=True)
col.operator("object.multi_object_rename_dom")
layout.prop(sce, "erase_string_panel")
layout.prop(sce, "replace_panel")
layout.prop(sce, "trim_panel_start")
layout.prop(sce, "trim_panel_end")
layout.prop(sce, "prefix_panel")
layout.prop(sce, "suffix_panel")
layout.prop(sce, "rename_selected_panel")
if context.mode == 'OBJECT':
layout.prop(sce, "rename_object_data_panel")
col = layout.column(align=True)
col.operator("object.multi_object_rename_dom_reset")
class OBJECT_RENAME_tools_multiobjectrename(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_context = "objectmode"
bl_label = "Objects Renamer"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object is not None)
def draw_header(self, context):
layout = self.layout
def draw(self, context):
draw_rename_panel(self, context)
class OBJECT_RENAME_tools_multibonerename(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_context = "armature_edit"
bl_label = "Objects Renamer"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object is not None)
def draw_header(self, context):
layout = self.layout
def draw(self, context):
draw_rename_panel(self, context)
class OBJECT_RENAME_tools_multiposebonerename(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_context = "posemode"
bl_label = "Objects Renamer"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object is not None)
def draw_header(self, context):
layout = self.layout
def draw(self, context):
draw_rename_panel(self, context)
def doSingleObjectRename(object, eraseString, replacementString, trimStart, trimEnd, newPrefix, newSuffix, rename_object_data, mode):
temp = object.name[trimStart:]
if trimEnd > 0:
temp = temp[:-trimEnd]
temp = re.sub(eraseString, replacementString, temp)
temp = newPrefix + temp + newSuffix
object.name = temp[:]
if mode == 'OBJECT':
if object.data:
if rename_object_data:
object.data.name = object.name
def doMultiObjectRename(self, context, eraseString, replacementString, trimStart, trimEnd, newPrefix, newSuffix, rename_selected, rename_object_data):
eraseString = fnmatch.translate(eraseString)[:-7] #convert shell wildcards to regular expression and trunc the last 7 chars (why do they get generated by fnmatch???)
num_objects = 0
if context.mode == 'EDIT_ARMATURE':
if rename_selected:
bones_list = context.selected_bones
else:
bones_list = context.object.data.bones
for bone in bones_list:
doSingleObjectRename(bone, eraseString, replacementString, trimStart, trimEnd, newPrefix, newSuffix, rename_object_data, context.mode)
num_objects += 1
elif context.mode == 'OBJECT':
if rename_selected:
objects_list = context.selected_objects
else:
objects_list = context.scene.objects
for obj in objects_list:
doSingleObjectRename(obj, eraseString, replacementString, trimStart, trimEnd, newPrefix, newSuffix, rename_object_data, context.mode)
num_objects += 1
elif context.mode == 'POSE':
if rename_selected:
bones_list = context.selected_pose_bones
else:
bones_list = context.object.pose.bones
for bone in bones_list:
doSingleObjectRename(bone, eraseString, replacementString, trimStart, trimEnd, newPrefix, newSuffix, rename_object_data, context.mode)
num_objects += 1
if num_objects == 0:
self.report({'INFO'}, "No object processed")
else:
self.report({'INFO'}, str(num_objects) + " objects processed")
class MultiObjectRename(bpy.types.Operator):
'''Find & Replace-functionality for names'''
bl_idname = "object.multi_object_rename_dom"
bl_label = "Rename"
bl_description = "Find & Replace functionality for object and bone names"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
sce = context.scene
something_todo = True
if context.mode == 'OBJECT' and sce.rename_object_data_panel:
something_todo = True
else:
if sce.erase_string_panel == "" and sce.replace_panel == "" and \
sce.trim_panel_start == 0 and sce.trim_panel_end == 0 and \
sce.prefix_panel == "" and sce.suffix_panel == "":
something_todo = False
self.report({'INFO'}, "Nothing to process")
if something_todo:
doMultiObjectRename(self, context, sce.erase_string_panel, sce.replace_panel,
sce.trim_panel_start, sce.trim_panel_end,
sce.prefix_panel, sce.suffix_panel, sce.rename_selected_panel, sce.rename_object_data_panel)
return {'FINISHED'}
class OBJECT_RENAME_reset_button(bpy.types.Operator):
bl_label = "Reset fields"
bl_idname = "object.multi_object_rename_dom_reset"
bl_description = "Reset input fields"
bl_options = {'REGISTER'}
def invoke(self, context, event):
sce = context.scene
sce.erase_string_panel = ""
sce.replace_panel = ""
sce.trim_panel_start = 0
sce.trim_panel_end = 0
sce.prefix_panel = ""
sce.suffix_panel = ""
return {'FINISHED'}
# http://www.blender.org/documentation/blender_python_api_2_60_6/bpy.props.html
def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.erase_string_panel = bpy.props.StringProperty(name="Find String",
description = "The string to look for in the object names (shell wildcards supported)",
)
bpy.types.Scene.replace_panel = bpy.props.StringProperty(name = "Replace with",
description = "The replacement for the string given above",
)
bpy.types.Scene.trim_panel_start = bpy.props.IntProperty(name="Trim Start:",
description = "Erases the specified number of characters from the beginning of the object names",
min = 0,
max = 50,
default = 0,
)
bpy.types.Scene.trim_panel_end = bpy.props.IntProperty(name="Trim End:",
description = "Erases the specified number of characters from the end of the object names",
min = 0,
max = 50,
default = 0,
)
bpy.types.Scene.prefix_panel = bpy.props.StringProperty(name = "Prefix with",
description = "Adds the specified characters to the beginning of the object names",
)
bpy.types.Scene.suffix_panel = bpy.props.StringProperty(name = "Suffix with",
description = "Adds the specified characters to the end of the object names",
)
bpy.types.Scene.rename_selected_panel = bpy.props.BoolProperty(
name="Selected objects",
description="If checked, renaming will only affect selected objects",
default=0)
bpy.types.Scene.rename_object_data_panel = bpy.props.BoolProperty(
name="Object data",
description="If checked in object mode, the object data gets the object name whether a object name change is done or not",
default=0)
pass
def unregister():
bpy.utils.unregister_module(__name__)
# Remove properties
del bpy.types.Scene.erase_string_panel
del bpy.types.Scene.replace_panel
del bpy.types.Scene.trim_panel_start
del bpy.types.Scene.trim_panel_end
del bpy.types.Scene.prefix_panel
del bpy.types.Scene.suffix_panel
del bpy.types.Scene.rename_selected_panel
del bpy.types.Scene.rename_object_data_panel
pass
if __name__ == '__main__':
register()
if __name__ == "__main__":
register()
Also beware, rigify has stretch by default but you should turn it off for games, because if you want stretch to work correctly, you need to parent parts of the stretchy limbs to the root or else you get double transformations down the chains. If that works, it’s ok but this means that rag-doll physics and procedural animations fail.