2
$\begingroup$

I have the following script. It updates a MixRGB node's factor input to itself to solve some issues with GLSL viewport in textured mode. Anyways, I was wondering if there is a way to attach this script, so that it runs automatically when I click on the "Play" button or press Alt-A and stop automatically as well when the playback is suspended? What would be the easiest way to go about doing this? Is creating an addon a feasible solution?

import bpy


class ModalTimerOperator(bpy.types.Operator):
    """Operator which runs its self from a timer"""
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"

    _timer = None

    def modal(self, context, event):
#        if event.type in {'RIGHTMOUSE', 'ESC'}:
#            self.cancel(context)
#            return {'CANCELLED'}

        if event.type == 'TIMER':
            mat = bpy.data.materials['Material']
            nodes = mat.node_tree.nodes
            mix = nodes["Mix"].inputs[0]
            mix.default_value = mix.default_value
            print('Current Frame:')

        return {'PASS_THROUGH'}

    def execute(self, context):
        wm = context.window_manager
        self._timer = wm.event_timer_add(0.1, context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)


def register():
    bpy.utils.register_class(ModalTimerOperator)


def unregister():
    bpy.utils.unregister_class(ModalTimerOperator)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.wm.modal_timer_operator()

I'm aware of Handlers in Blender. However I tried the below script with no luck:

import bpy

def refreshNow(val):
    mat = bpy.data.materials['Material']
    nodes = mat.node_tree.nodes
    nodes["Mix"].inputs[0].default_value = nodes["Mix"].inputs[0].default_value
    return val

refreshNow(0)

bpy.app.driver_namespace['refresh'] = refreshNow

def my_handler():
    refreshNow(0)

def register():
    bpy.app.handlers.frame_change_post.append(my_handler)
$\endgroup$
9
  • 3
    $\begingroup$ instead of the timer attach the main function to the handler bpy.app.handlers.frame_change_pre and it will run before the frame change. see handlers $\endgroup$
    – Chebhou
    Feb 9, 2016 at 8:14
  • 1
    $\begingroup$ I have commented on the other question try it out please $\endgroup$
    – Chebhou
    Feb 9, 2016 at 10:15
  • 1
    $\begingroup$ if not working you can : attach the modal Op to the handler ( just to trigger it at the start ) and inside the handler detach the Op from the handler ( so it won't be called while running ) , have a counter inside the Op and check if frame don't change for long time stop the Op $\endgroup$
    – Chebhou
    Feb 9, 2016 at 10:18
  • 1
    $\begingroup$ just call it inside a function ( appended to handler ) and to detach remove this function from the handler $\endgroup$
    – Chebhou
    Feb 9, 2016 at 10:28
  • 1
    $\begingroup$ now you have all the ingredients, I'll get back to you later $\endgroup$
    – Chebhou
    Feb 9, 2016 at 10:49

1 Answer 1

1
$\begingroup$

Solution to the above problem is to use Handler rather than a Modal Operator. Thanks to @Chebhou for his help in this thread and here.

Below is a working solution to execute on playback using handlers:

import bpy

def refreshNow(val):
    mat = bpy.data.materials['Material']
    nodes = mat.node_tree.nodes
    nodes["Mix"].inputs[0].default_value = nodes["Mix"].inputs[0].default_value
    bpy.context.scene.update()
    return val

refreshNow(0)

bpy.app.driver_namespace['refresh'] = refreshNow
def my_handler(scene):
    refreshNow(0)

def register():
    bpy.app.handlers.frame_change_post.append(my_handler)

if __name__ == "__main__":
    register()
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .