Skip to content

Instantly share code, notes, and snippets.

@maxkagamine
Last active March 23, 2022 07:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxkagamine/a8315bf3a3c2d36892c5ca2c1761c85c to your computer and use it in GitHub Desktop.
Save maxkagamine/a8315bf3a3c2d36892c5ca2c1761c85c to your computer and use it in GitHub Desktop.
Blender addon to rename selected MMD models' armature, mesh, and materials to match the name of the empty. https://twitter.com/maxkagamine/status/1380531111906869248
# MIT License
#
# Copyright (c) 2021 Max Kagamine
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import bpy
import re
bl_info = {
'name': 'Batch Rename MMD Models',
'author': 'Max Kagamine',
'version': (1, 0),
'blender': (2, 91, 0),
'location': 'F3 > Batch Rename MMD Models',
'description': "Renames selected MMD models' armature, mesh, and materials to match the name of the empty.",
'category': 'Object',
'wiki_url': 'https://gist.github.com/maxkagamine/a8315bf3a3c2d36892c5ca2c1761c85c',
}
ARMATURE_SUFFIX = '_arm'
MESH_SUFFIX = '_mesh'
class OBJECT_OT_BatchRenameMmdModels(bpy.types.Operator):
"""
Renames selected MMD models' armature, mesh, and materials to match the name of the empty.
"""
bl_idname = 'object.batch_rename_mmd_models'
bl_label = 'Batch Rename MMD Models'
bl_options = {'UNDO'}
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
def execute(self, context):
changes_made = False
for model in context.selected_objects:
try:
self.batch_rename(model)
changes_made = True
except ValueError as err:
self.report({'ERROR'}, str(err))
# This determines whether an undo entry should be created
return {'FINISHED'} if changes_made else {'CANCELLED'}
def batch_rename(self, model):
# Check that the right thing is selected
if model is None or model.type != 'EMPTY':
raise ValueError(f'{model.name} is not an empty')
# Get the armature and mesh
armature = self.get_child(model, 'ARMATURE', ARMATURE_SUFFIX)
mesh = self.get_child(armature, 'MESH', MESH_SUFFIX)
# Armature should have the old name, in case materials are already prefixed
old_model_name = armature.name[:-len(ARMATURE_SUFFIX)]
# Rename objects
armature.name = f'{model.name}{ARMATURE_SUFFIX}'
armature.data.name = model.name
mesh.name = f'{model.name}{MESH_SUFFIX}'
mesh.data.name = model.name
# Get unique materials
materials = [slot.material for slot in mesh.material_slots if
slot.material is not None and slot.material.users == 1]
# Rename materials
for material in materials:
material_name = material.name
# Remove old name if present
if material_name.startswith(old_model_name):
# Tfw there's a len() function but no rin()
material_name = material_name[len(old_model_name) + 1:]
# In case multiple models were imported with conflicting material names
material_name = re.sub('\.\d+$', '', material_name)
# Prefix with new model name
material.name = f'{model.name} {material_name}'
def get_child(self, obj, type, suffix):
children = [x for x in obj.children if x.type == type and x.name.endswith(suffix)]
if len(children) != 1:
raise ValueError(f'{obj.name} does not contain a single {type} that ends in {suffix}')
return children[0]
def menu_func(self, context):
self.layout.operator('object.batch_rename_mmd_models')
def register():
bpy.utils.register_class(OBJECT_OT_BatchRenameMmdModels)
bpy.types.TOPBAR_MT_edit.append(menu_func)
def unregister():
bpy.utils.unregister_class(OBJECT_OT_BatchRenameMmdModels)
bpy.types.TOPBAR_MT_edit.remove(menu_func)
if __name__ == '__main__':
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment