# Script not running as Handler or in Driver

I am running into a weird issue that I have solved in the past but can't seem to figure out now.

I have a material node keyframed in Blender Internal, and unfortunately blender does not show the transition in the GLSL textured viewport. So I have written a small script that will reinforce the value of a MixRGB factor to itself.

When I click on "Run Script" everything works fine and my material is updated. However assigning the function to a driver or even handler does need yield expected result, which is updating that MixRGB factor on every frame change.

import bpy

def refreshNow(val):
mat = bpy.data.materials['Skin_Gloss']
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():
refreshNow(0)

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

if __name__ == "__main__":
register()


Below is my driver setup. As you can see the debug info shows my current frame, which is 115. Meaning that refreshNow is actually called and has returned.

Here is my material setup, pay attention to the MixRGB being keyframed from 0 to 1, from frame 0 to 50:

Like I said, the script works fine when I click on "Run Script", and the driver shows that the function has returned. What could possibly be the issue?

• you need to add bpy.context.scene.update() at the end of the refreshNow() and the viewport will be updated Feb 9 '16 at 9:20
• @Chebhou please look at the code above. I still fail to append my_handler. On Run Script material and viewport updates, but on play nothing changes Feb 9 '16 at 10:17
• my_handler() should be my_handler(scene). ( looking at the error it should take one argument ) Feb 9 '16 at 10:34
• @Chebhou Wow! Lovely. That fixed everything. Handlers for the win.Thank you so so so much Feb 9 '16 at 10:40

Below is the code that resulted in proper solution to my problem. Thanks to @Chebhou who provided help and resolved the issues in my code. Refer to the comments in the first post for clarification.

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
#scene parameter was missing in original code
def my_handler(scene):
refreshNow(0)

def register():
bpy.app.handlers.frame_change_post.append(my_handler)
# this was also missing from the original code, I still don't know what it does, but it works!
if __name__ == "__main__":
register()


===Alternative Solution Using Modal Operators===

I managed to fix the issue by using a Modal Timer rather than utilizing handlers or drivers. This is not exactly a solution to why the driver or handler doesn't work but it is definitely a workaround to get what I wanted done.

Below is the code for anyone who might need it in future. This is simply the Modal Timer template, I just replaced the default functionality of changing theme color to reinforcing the MixRGB node's factor input to itself. I have also removed the functionality of cancelling the event.

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
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()