Merging multiple OBJ files into one file with shape keys

So, right now I have about a dozen different meshes that are all modified versions of a default head mesh. One for example is the same head but fatter, one with more pronounce eyebrows, one is smiling etc.

I am slightly new to blender, and I did not make these models. What I'm trying to do is find a way to merge these multiple files into one file as different shape keys. I can find information about how to make shape keys by editing a mesh but can't for the life of me find a way to blend two meshes into one and use one as the "target" of a blend key. If this is making sense.

The ultimate goal I have in mind is that I would like to have a single file with multiple sliders that I can ultimately export into Unity. I've learned how to export shape keys but I can't figure out how to get from where I am now with multiple meshes to where I want to be with multiple sliders. Thanks in advance for any help you can give a somewhat new user.

You can use this script to accomplish an obj sequence import to shapekeys. Paste the script into the text editor in blender, and click the Run Script button.

This will add a new command in the file menu called File>Import>OBJ as Shapekey. Select your target object, and then run the new command.

bl_info = {
'name': 'Load Obj Sequence as Shape Keys',
'author': 'cmomoney',
'version': (0, 2),
'blender': (2, 6, 7),
'category': 'Import-Export',
'location': 'File > Import/Export',
'wiki_url': ''}

# ##### 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
#
#  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 #####

import bpy, os
from bpy.props import *

bl_label = 'Import OBJ as Shape Keys'
bl_options = {'REGISTER', 'UNDO'}
bl_description = "Import Obj sequence as shape key(s)"

filepath = StringProperty(name="File path", description="File filepath of Obj", maxlen=4096, default="")
filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
filter_glob = StringProperty(default="*.obj", options={'HIDDEN'})
files = CollectionProperty(name='File path', type=bpy.types.OperatorFileListElement)
filename_ext = '.obj'

@classmethod
def poll(cls, context):
return context.active_object is not None and context.active_object.type == 'MESH'

def execute(self, context):
#get file names, sort, and set target mesh
spath = os.path.split(self.filepath)
files = [file.name for file in self.files]
files.sort()
target = bpy.context.scene.objects.active
#add all ojs in sequence as shape  keys
for f in files:
fp = os.path.join(spath[0], f)
#now delete objs
sknames = [sk.name for sk in target.data.shape_keys.key_blocks]
bpy.ops.object.select_all(action='DESELECT')
for obj in sknames:
if obj != 'Basis':
target.data.shape_keys.key_blocks[obj].interpolation = 'KEY_LINEAR'
bpy.context.scene.objects.active = bpy.data.objects[obj]
bpy.data.objects[obj].select = True
bpy.ops.object.delete()
bpy.ops.object.select_all(action='DESELECT')
#reselect target mesh and make active
bpy.context.scene.objects.active = target
target.select = True
return{'FINISHED'}

def invoke(self, context, event):
return {'RUNNING_MODAL'}

bpy.ops.import_scene.obj(filepath=fp,split_mode='OFF')
bpy.ops.object.join_shapes()
return

def register():

def unregister():

if __name__ == "__main__":
register()


Please note this is not my script, I'm just posting it here for convenience.

• I'm sorry but I'm just not understanding this still. I click the "load script" button but nothing seems to happen. I'm not getting any feedback about errors, it's just nothing happens. No shape keys created, no files merged, nothing. I've tried with everything loaded in the scene, and without that. If I need to modify the code with filenames or locations please tell me where. – Andrew Jensen Jul 20 '16 at 20:53
• You have to select the object and the click the "Run Script" button, which then should open the file window to select the OBJ files. Is that what you are doing? – Todd McIntosh Jul 21 '16 at 1:49
• No window pops up. I select the object and click run script but nothing happens. No menu pops up, no error happens, there is simply no response of any kind. Do I need another plugin turned on that isn't by default maybe? – Andrew Jensen Jul 22 '16 at 2:23
• Sorry, that's my fault. Running the script just adds a new "Import > Obj as Shapekey" command to the file menu. The proper instructions are run the script, select the object, then run that command from the file menu. I'll update my answer to be more clear. – Todd McIntosh Jul 22 '16 at 2:34
• Ok, I think I've figured it out. You'll have to excuse me as this was not a script I wrote, but one I found online. The line that does the file import does not show the import options in the UI, therefore you can't choose Keep Vertex Order as you do with single OBJ imports. I've updated the import line to force the Keep Vertex Order setting. It's the line: bpy.ops.import_scene.obj(filepath=fp,split_mode='OFF') – Todd McIntosh Jul 28 '16 at 1:28

Updated script to work on 2.8 guys:

bl_info = {
'name': 'Load Obj Sequence as Shape Keys',
'author': 'cmomoney',
'version': (0, 2),
'blender': (2, 6, 7),
'category': 'Import-Export',
'location': 'File > Import/Export',
'wiki_url': ''}

# ##### 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
#
#  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 #####

import bpy, os
from bpy.props import *

bl_label = 'Import OBJ as Shape Keys'
bl_options = {'REGISTER', 'UNDO'}
bl_description = "Import Obj sequence as shape key(s)"

filepath = StringProperty(name="File path", description="File filepath of Obj", maxlen=4096, default="")
filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
filter_glob = StringProperty(default="*.obj", options={'HIDDEN'})
files = CollectionProperty(name='File path', type=bpy.types.OperatorFileListElement)
filename_ext = '.obj'

@classmethod
def poll(cls, context):
return context.active_object is not None and context.active_object.type == 'MESH'

def execute(self, context):
#get file names, sort, and set target mesh
spath = os.path.split(self.filepath)
files = [file.name for file in self.files]
files.sort()
target = bpy.context.view_layer.objects.active
#add all ojs in sequence as shape  keys
for f in files:
fp = os.path.join(spath[0], f)
#now delete objs
sknames = [sk.name for sk in target.data.shape_keys.key_blocks]
bpy.ops.object.select_all(action='DESELECT')
for obj in sknames:
if obj != 'Basis':
target.data.shape_keys.key_blocks[obj].interpolation = 'KEY_LINEAR'
bpy.context.view_layer.objects.active = bpy.data.objects[obj]
bpy.data.objects[obj].select_set(state=True)
bpy.ops.object.delete()
bpy.ops.object.select_all(action='DESELECT')
#reselect target mesh and make active
bpy.context.view_layer.objects.active = target
target.select_set(state=True)
return{'FINISHED'}

def invoke(self, context, event):
return {'RUNNING_MODAL'}

bpy.ops.import_scene.obj(filepath=fp,split_mode='OFF')
bpy.ops.object.join_shapes()
return