1
$\begingroup$

I'm still a blender beginner, sorry in advance.

I have a python script that registers frame handlers (frame_change_post) that can update some custom properties of the objects in the scene. I can see these properties being updated when I run the animation, everything is fine so far.

Then, I have a few drivers (on shader nodes) that use these custom properties, i.e. have them as input variables. My problem is that these input variables are not updated: I can see the input values in the drivers editor as the animation runs and they do not change throughout the animation, unlike the actual custom properties. The animation itself visually confirms that the input values never change.

I have other drivers that read custom properties on the same object, but these properties are key-framed. And for those, everything works as expected.

Any help would be greatly appreciated :)

Edit: I saw somewhere that going through a Value node could help, except the driver is for the frame offset on an Image Texture node, and it is not an input so I can't plug the Value in.

Edit 2: never mind the value of the Value node with appropriate driver is not updated either :(

$\endgroup$

1 Answer 1

0
$\begingroup$

It seems your problem comes from the fact drivers won't reevaluate if they don't detect their sources to change. And it seems modifying the property in Python doesn't trigger this update, nor does view layer or depsgraph update(). What works, however, is changing any driver.

So I'm setting up a simple scene, with a left cube having a driver on Z location sin(frame/5) to just move vertically, a right cube having a driver on Z location last_z, where last_z points to a custom scene property scene["last_z"], and a cylinder, which is there just to show you don't need to modify a driver related to the animation you want to update:

Now the below code assigns updates the custom scene property, therefore animating the right cube, and updates any driver to force updating the dependency graph:

import bpy
from bpy import data as D


def frame_change_post(scene):
    scene['last_z'] = D.objects['Cube'].location.z 
    D.objects['Cylinder'].animation_data.drivers[0].driver.expression += ''
    

bpy.app.handlers.frame_change_post.clear()
bpy.app.handlers.frame_change_post.append(frame_change_post)

Result in 2 FPS to show the cubes are synchronized:

$\endgroup$
11
  • $\begingroup$ The reason I'm not using frame_change_pre is that I want the key frames to have been applied, because the result of the computation depends on that. Anyways, I thought about something along the lines of what you said, except if that's the case then the driver's input would be updated the frame after the python script performs the update, right? But it's not the case here, the driver's input stays constant throughout the animation which contains several updates to the custom property... $\endgroup$ Commented Apr 25, 2023 at 19:38
  • $\begingroup$ The thing is, I'm just trying to get back the delay/pre operator from synchronous dataflow languages like Simulink/Scade/Lustre which the shader nodes are a weak version of. I want to know which animation I'm in so that I can run it (current animation is key-framed), and I want to know when there's a switch (edge) to a different animation so that I can have the new animation start with the correct offset (0). So during _pre I memorize the previous animation (integer), then the frame updates and maybe the current animation was key-frame-changed. $\endgroup$ Commented Apr 25, 2023 at 19:46
  • $\begingroup$ Then during _post I want to check the previous and current animation, and if they're different I update my animStart custom property to be the current frame, which the offset driver will subtract to the current frame so that the animation starts on frame 0 when switched to. (And then divide and modulo for fps and cycles.) $\endgroup$ Commented Apr 25, 2023 at 19:48
  • $\begingroup$ @SystemikMondai "But it's not the case here" - could you create as simple as possible project reproducing this issue? Because your comment combined with your question seem to say that you modify the scene in a way, that is visible, and yet doesn't affect a driver. It's like making the script move a default cube up, a little more and more each frame, and yet have a driver of something else not react to that, I don't think that can be the case, since it's all within a single evaluation, unless the driver accesses some kind of original info, that isn't actually changed. $\endgroup$ Commented Apr 25, 2023 at 19:55
  • 1
    $\begingroup$ I see, thank you. I not going to use it though, I ended up handling things more manually. I decided to do that because what I really wanted to do was to have stateful shaders, which as you answered elsewhere (can't find that SO question right now) goes against blender's philosophy in that it makes it necessary to unroll all frames from the beginning to know what happens in any frame down the line. I actually could see this in my original attempt, as the stateful updates regularly yield inconsistent values depending on whether you play the animation from the beginning or not $\endgroup$ Commented Apr 26, 2023 at 11:49

You must log in to answer this question.

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