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 '16 at 8:14
  • 1
    $\begingroup$ I have commented on the other question try it out please $\endgroup$
    – Chebhou
    Feb 9 '16 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 '16 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 '16 at 10:28
  • 1
    $\begingroup$ now you have all the ingredients, I'll get back to you later $\endgroup$
    – Chebhou
    Feb 9 '16 at 10:49
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$

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.