1
$\begingroup$

I wrote script that create a custom deformer to a mesh over time. Using python is very slow so I'd like to be able to bake the position of my vertices deformed over time and be able to play it back at a better frame rate.

So, I'm trying to find a good solution to bake the position of vertices of a mesh over time like the physics/rigid body system in Blender.

I guess there is no direct access to create my own internal point cache (but if somebody knows how to do that I'm interested) so what I plan to do is to have a list that store the position of my vertices for a range of frames. As I'd like to be able to cancel while baking (using 'ESC'), I guess using a modal operator is the best way to go but i can't get my head around how to set up the modal operator particularly with the return values.

Here is what I get so far:

import bpy

##some code##

##store global
class G:
    pass

## bake deformer
class JDEF_BAKE(bpy.types.Operator):
    bl_idname = "wm.bake_jdef"
    bl_label = "Bake deformer"
    bl_options = {'UNDO', 'REGISTER'}

    _frame = 1
    _bake_mat = []
    _index = 0
    obj = None
    _endframe = 0

    def __init__(self):
        self.obj = bpy.context.object
        G.baked=False
        G.baking=True
        self._frame = bpy.context.scene.frame_start
        G.ls_bake=[]
        self._bake_mat = [0.0,0.0,0.0]*len(self.obj.data.vertices)
        self._endframe = bpy.context.scene.frame_end

    def __del__(self):
        G.baked=True
        G.baking=False

    def execute(self,context):
        context.window_manager.modal_handler_add(self)
        context.scene.frame_current = self._frame
        JDEF(context) #execute some function to move the vertices
        self.obj.data.vertices.foreach_get('co',self._bake_mat)
        G.ls_bake.append([self._frame,self._bake_mat])
        self._frame += 1
        return {'RUNNING_MODAL'}

    ## bake deformer
    def modal(self,context,event):
        if (self._frame <= self._endframe):
            self.execute(context)

        elif (self._frame > self._endframe):
            return {'FINISHED'}

        elif event.type=='ESC':
            G.baked=True
            G.baking=False
            G.ls_bake.clear()
            return {'CANCELLED'}

        return {'PASS_THROUGH'}

So this doesn't seems to work and blender freezes each time I launch the operator. It doesn't come from the function JDEF because even if I comment it blender will still froze. I think I'm not handling the return values and execute/modal functions the right way.

Sorry if the bad code make you tear blood but I'm still a learning noob :D

Thank you for your help.

$\endgroup$
  • $\begingroup$ First try to rename your __init__(self) to invoke(self,context,event). Invoke is what is called when the modal is invoked. Inside that fce move the context.window_manager.modal_handler_add(self) - you want to run that only once. Erase the execute and move it under modal. Execute don't return Running modal and you are using it only there under modal. If this works for you I will post it as an answer, cant test your code. $\endgroup$ – Jaroslav Jerryno Novotny Dec 29 '14 at 19:11
  • $\begingroup$ Thx! I'll try that and let you know. I wonder what would be the use for the __init__(self) def then in comparison of the invoke()? $\endgroup$ – Stan Paillereau Dec 29 '14 at 19:47
1
$\begingroup$

Ok, unfortunately @Jerryno solution didn't work so I ended up trying something else. I successfully made it wok by triggering the animation with bpy.ops.screen.animation_play() in the __init__ function, then doing my action in the modal function and finally stop the animation when 'ESC' is entered or the action is finished (in the __del__ function).

The handler is added in an invoke function running modal.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.