3

Heavily Edited

I want to make a procedural animation loop seamlessly and, while iterating, I'd like to vary the total frame count for length (& varied fps renders) without having to manually update all properties every time I experiment with this. Simply: I want to plug in a value once into the playback editor or properties panel and have all involved properties reference this to run each experiment.

I can foresee a frustrating experience with the housekeeping because of the number of properties (not only those in the following example) referencing total frame length / end frame.

Is it possible to reference this w/ an expression / driver?

When I create a driver via expression on a Musgrave Texture "W" socket or Mix "Factor" socket it returns an "Invalid Python Expression" error because of 'frame_end' in the following B texture W socket:

A MusTexture W: #frame/60
B MusTexture W: #(frame-frame_end)/60

Mix Factor: frame/frame_end

The first image below shows the end frame expression which works (600 is the end frame), however I have to input this manually into every expression which is becoming cumbersome and frustrating (from distraction). Can I automate this?

Thank you for your time and understanding.

Please reference both Markus von Broady's and Quellenform's answers for full understanding of the answer

Edit: Added detail of current Texture B socket code, 600 is current end frame.

Detail of Socket Code

sevens
  • 126
  • 8
  • Hello and welcome to Blender.SE! Take a look at the nodes Scene Time and Math. These two nodes in combination should do what you want. – quellenform May 10 '23 at 23:15
  • Thank you for the comment, but I'm not sure if I was clear about what I'm looking for. I'd like to find a way to code the input value of the total frame count to streamline input. Since we can use FRAME, I'd like to know the name of the string for the end frame as endFrame returns an error and disables the driver for that socket when used. Neither Scene Time nor Math nodes pages in the manual expound on what strings can be used for frames in node sockets. Perhaps I can add another image to clarify. – sevens May 11 '23 at 00:36
  • These two questions together answer yours I think: https://blender.stackexchange.com/questions/27889/how-to-find-number-of-animated-frames-in-a-scene-via-python, https://blender.stackexchange.com/questions/51530/can-we-execute-custom-python-functions-from-driver-expressions – Valalala May 11 '23 at 05:07
  • Thank you for the comment. This feels like it is getting me closer, but I'm struggling to understand exactly what to do. I'm not familiar with the language. I've tried to run this script to add an expression to the driver, but line 3 fails syntax: 1import bpy 2 3def frame_end: 4 """returns total frames""" 5 return bpy.context.scene.frame.end 6 7# Add function to driver_namespace. 8bpy.app.driver_namespace['frame_end'] = frame_end but I'm just guessing at what to plug in where. – sevens May 11 '23 at 07:07

3 Answers3

3

Just use

bpy.context.scene.frame_end

instead of frame_end

Further explanation here: https://docs.blender.org/manual/en/latest/animation/drivers/drivers_panel.html#expressions

that's how my driver looks like: enter image description here

Chris
  • 59,454
  • 6
  • 30
  • 84
  • I am pretty sure that won't work on its own. Unless I am missing something, you have to add a function to the driver namespace which then calls bpy.context.scene.frame_end. The link does explain how to do that, but I think that information should be in the answer itself. – Valalala May 11 '23 at 04:58
  • @Valalala: just try it out instead of writing wrong comments - and little hint from me: i tried it out - then i wrote the answer. – Chris May 11 '23 at 07:08
  • i am not sure what you mean with "list". But you can simply delete your driver and add a new one and use the command i used in my answer as scripted expression. I can provide a blend file if that helps you – Chris May 11 '23 at 07:14
  • of course you could also user driver_namespace as Valalala pointed out, but it isn't necessary. And since you said you have less experience with python, my solution might be easier to understand and use for you – Chris May 11 '23 at 07:16
  • Thanks for the comment, Chris. Is there a way to get only the frame_end value as an expression that can drive (i.e. as @Valalala suggests via namespace)? I'd like to use it for a few different operations and I'm not sure this will save time vs manual input as I'll have to set up multiple drivers for each operation. OTOH I'm hitting a wall so after sleep I might be fresh to understand drivers better. This must be the answer, but I think I need a new question/direction. Will update in the morning after trial. (Am 100% blank slate w/ coding/Python if not apparent, but willing to learn.) – sevens May 11 '23 at 07:32
  • also with using the namespace variant, you have to duplicate the driver anyway. But for performance reasons the namespace variant might be preferable. In my case i just tried out with one driver - there were no performance issues at all. But of course there might raise some, if you are using the same driver a lot of times. But anyway - you have to copy your drivers in both cases. So the working effort is the same. – Chris May 11 '23 at 07:36
  • Thank you, Chris. I've edited/refined the original question with some of the insight that you and @Valalala have imparted. I'm getting a "Invalid Python Expression" error, however (see new image), however the Warning and Tip are the same. (The additional workload is manually updating every property with the end frame -- and mentally logging every socket can be frustrating as I am easily distracted, which is why I think the two of you may have the solution.) – sevens May 11 '23 at 18:33
  • Accessing bpy module involves using Python (hence "slow expression"). Moreover, it's outside a whitelist of safe Python, which requires to enable "Script autoexecution" in order to make it work. More reading: driver not working – Markus von Broady May 11 '23 at 19:41
  • Thank you, @Markus von Broady, you and quellenform have given me the eureka moment with your answers and broken down the wall for me. I'd like to use both of your answers as the correct answer, so I will reference that in the edit to my question. – sevens May 12 '23 at 17:03
3

As a general rule, you can right-click your source of choice, and from menu pick "Copy as a New Driver". Then you can right-click the value to be controlled by the driver, and choose "Paste Driver". Now editing the driver will allow you to inspect how to target the source, or just modify the driver to be a scripted expression and modify the expression to your needs.

Markus von Broady
  • 36,563
  • 3
  • 30
  • 99
  • True, thank you for the response and info, however these instances of “end frame” occur almost exclusively in different equations, so copying would not solve the problem in this case. – sevens May 11 '23 at 22:41
  • @sevens how so? I don't understand. – Markus von Broady May 11 '23 at 22:49
  • In the code in the problem posted, Musgrave texture node B must subtract from frame to return a negative, the mixer node it feeds must divides frame by it. This is just an example from many instances of requiring this value: I’m looking for a specific solution to reference frame_end through expression/driver/code. Neither frame-end nor bpy.context… (@Chris solution) work in a driver for this value for me. Errors (see above). Manually punching in end frame values for all these properties is onerous and prone to data entry errors. – sevens May 12 '23 at 02:19
  • @sevens in the GIF I posted, you don't have to modify the driver, you can have a simple value node be set to the frame_end. Then you can pass this value further to use in math nodes. If the problem is modifying all your existing drivers, then the only solution would be some Python script that iterates over all drivers and automatizes adding a new variable and modifying the expressions. – Markus von Broady May 12 '23 at 08:35
  • I agree, don't do calculations inside of drivers. They're awfully slow. Use the driver to drive a Value node, and do your maths with math nodes – Gorgious May 12 '23 at 16:30
  • @Markus von Broady, Thank you again: I see it now. I missed the critical first frames of the gif every time. Thanks for your patience. I'm sorry for my impatience, I completely misunderstood your reply. – sevens May 12 '23 at 16:42
  • @Gorgious Thank you for the streamlining principle. – sevens May 12 '23 at 16:42
3

As I mentioned in the comments at the beginning, you can solve this with a few nodes.

At least I don't see any reason why an (unsafe & slow) Python expression should be used here.

As Markus from Broady correctly showed, you just copy "Frame End" as a driver into an input field.

To stay flexible, and that's what he meant in his comment, you do the rest with a few nodes.

If that's too much trouble for you, just put the nodes into a node group.

And if you want to make certain parameters flexible, put them on the Group Input of your node group so that they can be set individually at any time and you can use the node group as many times as you want in your setup.

Like this:

enter image description here


(Blender 3.2+)

quellenform
  • 35,177
  • 10
  • 50
  • 133
  • Thank you for your answer/patience. Tested without execution, but the value is updating! I'm sorry for my impatience: this--in combination with the insight from @Markus von Broady--was the answer. While it was not the answer I was initially looking for, it appears to be a much superior alternative, if I understand the warnings from Blender and all of your comments about avoiding unnecessary Python expressions correctly. I was looking for the wrong answer. I'll update this one answered. Thank you, this stretched the limits of my knowledge a little and that's the greatest gift. – sevens May 12 '23 at 17:00
  • 1
    @sevens You're welcome! The rule of thumb in the case of geometry nodes is actually always: Do what you can do with nodes, and use Python/Drivers ONLY where it cannot be avoided or where the nodes are really not sufficient. – quellenform May 12 '23 at 17:22