Skip to content

Instantly share code, notes, and snippets.

@Trass3r
Created July 23, 2022 11:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Trass3r/8c173faa05bc4bc070712e70f064f9a4 to your computer and use it in GitHub Desktop.
Save Trass3r/8c173faa05bc4bc070712e70f064f9a4 to your computer and use it in GitHub Desktop.
Blender addon to import .obj files containing morph targets, based on https://gist.github.com/Marcus-Zhu/6e397f6b5d295ab87602a26aef0673a0
bl_info = {
"name": "Import OBJ with morph targets",
"author": "Trass3r",
"version": (1, 0, 0),
"blender": (3, 2, 0),
"location": "File > Import/Export",
"description": "Import OBJ with morph targets",
"doc_url": "",
"support": "COMMUNITY",
"category": "Import-Export",
}
import bpy
from pathlib import Path
from bpy.props import (
BoolProperty,
CollectionProperty,
StringProperty,
)
from bpy_extras.io_utils import ImportHelper
class ImportObjSeq(bpy.types.Operator, ImportHelper):
bl_idname = "import_scene.objmeshseq"
bl_label = "Import OBJ with morph targets"
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".obj"
filter_glob: StringProperty(default="*.obj", options={"HIDDEN"})
useRelativeShapekeys: BoolProperty(
name="Import as relative Morph Targets",
description="Import frames as relative or absolute shapekeys.",
default=True,
)
def execute(self, context):
self.create_shapekeys(self.filepath)
return {"FINISHED"}
def create_shapekeys(self, filepath):
bpy.ops.import_scene.obj(filepath=filepath, use_split_objects=True, use_split_groups=False, use_groups_as_vgroups=False)
# all imported objects will be selected
baseObject = bpy.context.selected_objects[0]
bpy.context.view_layer.objects.active = baseObject
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.remove_doubles(threshold=1e-05)
bpy.ops.object.editmode_toggle()
bpy.ops.object.join_shapes()
# remove all but the base object
bpy.context.active_object.select_set(False)
bpy.ops.object.delete(use_global=True, confirm=False)
baseObject.active_shape_key_index = 0
for face in baseObject.data.polygons:
face.use_smooth = True
main_key = baseObject.data.shape_keys
if self.useRelativeShapekeys:
# set keyframes
main_key.use_relative = True
for i, key_block in enumerate(main_key.key_blocks[1:]):
key_block.value = 0.0
key_block.keyframe_insert("value", frame=i)
key_block.value = 1.0
key_block.keyframe_insert("value", frame=i+1)
key_block.value = 0.0
key_block.keyframe_insert("value", frame=i+2)
else:
# absolute shape keys
main_key.use_relative = False
bpy.ops.object.shape_key_retime()
fcurve = main_key.driver_add("eval_time")
fcurve.driver.expression = "frame*10"
assert(fcurve.driver.is_simple_expression)
# set start/end time
bpy.context.scene.frame_start = 0
bpy.context.scene.frame_end = len(main_key.key_blocks) - 1
def menu_func_import(self, context):
self.layout.operator(ImportObjSeq.bl_idname, text="OBJ with morph targets (.obj)")
def register():
bpy.utils.register_class(ImportObjSeq)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
def unregister():
bpy.utils.unregister_class(ImportObjSeq)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment