Skip to content

Commit

Permalink
Auto export altered meshes (#157)
Browse files Browse the repository at this point in the history
* Initial commit of pseuodocode

* mesh hash to detect mesh changes

* recalculate the mesh hash on load, start of export logic

* Basic functionality working

Choose between overwriting and saving to different directory. Check for invalid directory

* Add other file types, some cleanup
  • Loading branch information
neverhood311 authored May 20, 2022
1 parent 9d77d95 commit 59a0e57
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 14 deletions.
12 changes: 11 additions & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"name": "Stop motion OBJ",
"description": "Import a sequence of OBJ (or STL or PLY or X3D) files and display them each as a single frame of animation. This add-on also supports the .STL, .PLY, and .X3D file formats.",
"author": "Justin Jensen",
"version": (2, 2, 0, "alpha.18"),
"version": (2, 2, 0, "alpha.19"),
"blender": (2, 83, 0),
"location": "File > Import > Mesh Sequence",
"warning": "",
Expand All @@ -37,7 +37,11 @@
SMOKeymaps = []

def register():
bpy.app.handlers.frame_change_pre.append(checkMeshChangesFrameChangePre)
bpy.app.handlers.frame_change_post.append(checkMeshChangesFrameChangePost)

bpy.types.Mesh.inMeshSequence = bpy.props.BoolProperty()
bpy.types.Mesh.meshHash = bpy.props.StringProperty()
bpy.utils.register_class(SequenceVersion)
bpy.utils.register_class(MeshImporter)
bpy.utils.register_class(MeshNameProp)
Expand All @@ -63,8 +67,10 @@ def register():
bpy.utils.register_class(ConvertToMeshSequence)
bpy.utils.register_class(DuplicateMeshFrame)
bpy.utils.register_class(SMO_PT_MeshSequencePanel)
# note: the order of the next few panels is the order they appear in the UI
bpy.utils.register_class(SMO_PT_MeshSequencePlaybackPanel)
bpy.utils.register_class(SMO_PT_MeshSequenceStreamingPanel)
bpy.utils.register_class(SMO_PT_MeshSequenceExportPanel)
bpy.utils.register_class(SMO_PT_MeshSequenceAdvancedPanel)
bpy.app.handlers.render_init.append(renderInitHandler)
bpy.app.handlers.render_complete.append(renderCompleteHandler)
Expand Down Expand Up @@ -92,6 +98,9 @@ def register():
SMOKeymaps.append((keyMap, keyMapItem))

def unregister():
bpy.app.handlers.frame_change_pre.remove(checkMeshChangesFrameChangePre)
bpy.app.handlers.frame_change_post.remove(checkMeshChangesFrameChangePost)

bpy.app.handlers.load_post.remove(initializeSequences)
bpy.app.handlers.frame_change_pre.remove(updateFrame)
bpy.app.handlers.frame_change_pre.remove(updateFrameSingleMesh)
Expand All @@ -111,6 +120,7 @@ def unregister():
bpy.utils.unregister_class(SMO_PT_MeshSequencePanel)
bpy.utils.unregister_class(SMO_PT_MeshSequencePlaybackPanel)
bpy.utils.unregister_class(SMO_PT_MeshSequenceStreamingPanel)
bpy.utils.unregister_class(SMO_PT_MeshSequenceExportPanel)
bpy.utils.unregister_class(SMO_PT_MeshSequenceAdvancedPanel)
bpy.utils.unregister_class(MeshSequenceSettings)
bpy.utils.unregister_class(MeshNameProp)
Expand Down
53 changes: 44 additions & 9 deletions src/panels.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ def draw(self, context):
# keyframed playback
if objSettings.frameMode == '4':
row = col.row()
if objSettings.curMeshIdx <= 0 or objSettings.curMeshIdx > objSettings.numMeshes - 1:
if objSettings.curKeyframeMeshIdx <= 0 or objSettings.curKeyframeMeshIdx > objSettings.numMeshes - 1:
row.alert = True
row.prop(objSettings, "curMeshIdx")
row.prop(objSettings, "curKeyframeMeshIdx")
# all other playback modes
else:
col.prop(objSettings, "startFrame")
Expand Down Expand Up @@ -97,6 +97,39 @@ def draw(self, context):
col.prop(objSettings, "streamDuringPlayback")


class SMO_PT_MeshSequenceExportPanel(bpy.types.Panel):
bl_label = 'Export'
bl_parent_id = "OBJ_SEQUENCE_PT_properties"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_options = {'DEFAULT_CLOSED'}

@classmethod
def poll(cls, context):
return context.object.mesh_sequence_settings.initialized == True

def draw(self, context):
layout = self.layout
objSettings = context.object.mesh_sequence_settings
inObjectMode = context.mode == 'OBJECT'
inSculptMode = context.mode == 'SCULPT'

if objSettings.isImported is True:
# non-imported sequences won't have a fileName or dirPath and cannot be exported (for now)
row = layout.row()
row.enabled = inObjectMode or inSculptMode
row.prop(objSettings, "autoExportChanges")

row = layout.row()
row.enabled = inObjectMode or inSculptMode
row.prop(objSettings, "overwriteSrcDir")

row = layout.row()
row.enabled = (inObjectMode or inSculptMode) and objSettings.overwriteSrcDir is False
row.alert = objSettings.exportDir == '' and objSettings.overwriteSrcDir is False

row.prop(objSettings, "exportDir")

class SMO_PT_MeshSequenceAdvancedPanel(bpy.types.Panel):
bl_label = 'Advanced'
bl_parent_id = "OBJ_SEQUENCE_PT_properties"
Expand Down Expand Up @@ -139,6 +172,8 @@ def draw(self, context):
row = layout.row()
row.enabled = inObjectMode
row.operator("ms.bake_sequence")



row = layout.row()
row.enabled = inObjectMode
Expand Down Expand Up @@ -455,11 +490,11 @@ def execute(self, context):
msObj.mesh_sequence_settings.frameMode = '4'

# create a keyframe for this mesh at the current frame
msObj.mesh_sequence_settings.curMeshIdx = 1
msObj.keyframe_insert(data_path='mesh_sequence_settings.curMeshIdx', frame=context.scene.frame_current)
msObj.mesh_sequence_settings.curKeyframeMeshIdx = 1
msObj.keyframe_insert(data_path='mesh_sequence_settings.curKeyframeMeshIdx', frame=context.scene.frame_current)

# make the interpolation constant for the first keyframe
meshIdxCurve = next((curve for curve in msObj.animation_data.action.fcurves if 'curMeshIdx' in curve.data_path), None)
meshIdxCurve = next((curve for curve in msObj.animation_data.action.fcurves if 'curKeyframeMeshIdx' in curve.data_path), None)
keyAtFrame = next((keyframe for keyframe in meshIdxCurve.keyframe_points if keyframe.co.x == context.scene.frame_current), None)
keyAtFrame.interpolation = 'CONSTANT'

Expand Down Expand Up @@ -489,8 +524,8 @@ def execute(self, context):
self.report({'ERROR'}, "The selected object is not a mesh sequence")
return {'CANCELLED'}

# if the object doesn't have a 'curMeshIdx' fcurve, we can't add a mesh to it
meshIdxCurve = next((curve for curve in obj.animation_data.action.fcurves if 'curMeshIdx' in curve.data_path), None)
# if the object doesn't have a 'curKeyframeMeshIdx' fcurve, we can't add a mesh to it
meshIdxCurve = next((curve for curve in obj.animation_data.action.fcurves if 'curKeyframeMeshIdx' in curve.data_path), None)
if meshIdxCurve is None:
self.report({'ERROR'}, "The selected mesh sequence has no keyframe curve")
return {'CANCELLED'}
Expand All @@ -510,8 +545,8 @@ def execute(self, context):
meshIdx = addMeshToSequence(obj, newMesh)

# add a new keyframe at this frame number for the new mesh
obj.mesh_sequence_settings.curMeshIdx = meshIdx
obj.keyframe_insert(data_path='mesh_sequence_settings.curMeshIdx', frame=context.scene.frame_current)
obj.mesh_sequence_settings.curKeyframeMeshIdx = meshIdx
obj.keyframe_insert(data_path='mesh_sequence_settings.curKeyframeMeshIdx', frame=context.scene.frame_current)

# make the interpolation constant for this keyframe
newKeyAtFrame = next((keyframe for keyframe in meshIdxCurve.keyframe_points if keyframe.co.x == context.scene.frame_current), None)
Expand Down
Loading

0 comments on commit 59a0e57

Please sign in to comment.