1
$\begingroup$

Edit: DOWNLOAD DEMO BLEND FILE

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.

Driver Setup

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

enter image description here

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?

Thank you in advance.

Edit: DOWNLOAD DEMO BLEND FILE

$\endgroup$
  • 1
    $\begingroup$ you need to add bpy.context.scene.update() at the end of the refreshNow() and the viewport will be updated $\endgroup$ – Chebhou Feb 9 '16 at 9:20
  • $\begingroup$ @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 $\endgroup$ – JungleJeem Feb 9 '16 at 10:17
  • 1
    $\begingroup$ my_handler() should be my_handler(scene). ( looking at the error it should take one argument ) $\endgroup$ – Chebhou Feb 9 '16 at 10:34
  • $\begingroup$ @Chebhou Wow! Lovely. That fixed everything. Handlers for the win.Thank you so so so much $\endgroup$ – JungleJeem Feb 9 '16 at 10:40
1
$\begingroup$

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
        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()
$\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.