2
$\begingroup$

I've been looking for a way to calculate the speed of an object or bone. On this same site a couple of people have made this same question but any of the scripts I've tried in the current version of Blender don't seem to work (anymore).

What I'd like to have is a driver/drivers that says/say how much an object or bone has moved every frame, so a comparison of the location of the distance of the previous frame to the current frame. This can be a single value or in separate X, Y and Z values, either would work.

Among the scripts I've tried this one seems like a good solution but sadly it mostly returns zeroes for me:

gif

The numbers it pops out seem right but it doesn't seem to be updating at the right rate. I've added this file to the post.

Edit: After tetii's suggestion I did some more experimenting and did get the script to work, somewhat:

The file for this I've provided also, it's the second one. What I've done is simply copy over the driver to the Z-location of the cube. Now the driver for 'dx' is updating correctly, I just don't understand why. So it looks like the script from the linked post by Rich Sedman can work, there just seems to be some issue with the way it uses variables or I misunderstood something.

import bpy

attributes = {}

def drv_calc_change(frame, attr, value):
# Used to calculate the change of a property (eg, x-coord) between one frame and the next.

    # Determine whether we already have a value for this attribute
    if attr in attributes:
        attribute = attributes[attr]
    else:
        # Not found - create a new record for it and store it
        attribute = {'frame':frame, 'value':value}
        attributes[attr] = attribute

    # Calculate the difference
    difference = value - attribute['value']

    # If new frame then store the new value to use next time.
    if frame != attribute['frame']:
        attribute['frame'] = frame
        attribute['value'] = value
        attributes[attr] = attribute

    return difference

if 'drv_calc_change' in bpy.app.driver_namespace:
    del bpy.app.driver_namespace['drv_calc_change']
bpy.app.driver_namespace['drv_calc_change'] = drv_calc_change

First file: Second file:

$\endgroup$
7
  • 3
    $\begingroup$ I think more people may attempt to help if they knew what this all about. Could you maybe edit the question and add more context? What are you trying to do? $\endgroup$ Commented Dec 12, 2022 at 8:43
  • $\begingroup$ Thank you, I followed your advice and specified the question more. I thought keeping it short would be better somehow. $\endgroup$ Commented Dec 12, 2022 at 12:05
  • $\begingroup$ It's still not very clear to be honest. How do you imagine the output of it? What do you need it for? Do you only need to see it for the active object, or are you planning to use it somehow in a script or a driver or some other way? $\endgroup$ Commented Dec 12, 2022 at 13:42
  • $\begingroup$ if the script does return 0, please upload your blend file with script so we can run it and test it out and we see what you tried/have done. Thank you. $\endgroup$
    – Chris
    Commented Dec 12, 2022 at 14:27
  • 1
    $\begingroup$ It seems like the problem is that the object itself is the target of the variable. So please try the following: Enable the self attribute and change the expression to drv_calc_change(frame, "dx", self.location.x). $\endgroup$
    – tetii
    Commented Dec 14, 2022 at 10:46

4 Answers 4

1
+50
$\begingroup$

Here's a scriptless solution that doesn't require working with an alpha build, which is nonetheless dynamic, provided you are interested in the velocity only during a single action. Starting with the file provided:

  1. Duplicate Cube to Cube.002. Move this duplicate to a new collection.
  2. Open the NLA. Push down the Cube.002 action to a new NLA track. Set this action to reference the same action as Cube (CubeAction).
  3. Change the driver for Cube.001 to measure the distance between Cube and Cube.002.
  4. Move Cube.002's NLA strip one unit in the X (time) axis.
  5. Optionally, disable your new collection in viewports and renders.

enter image description here

Our duplicate uses the same action as our original, but lags by 1 frame, allowing us to measure exactly how much distance is traversed in a single frame. Because the strips reference the exact same action data, we can continue to edit this action, and our velocities will update with our edits.

If already using the NLA to combine multiple actions, or if interested in the velocity through multiple actions (perhaps for exporting a file containing multiple actions), this is not a good solution.

There will also be complications based on dependencies. They can be worked around, by duplicating parents/targets (and their parents/targets, and so on) and shifting NLA action strips in the same way, but that will rapidly become unworkable. However, the technique will work perfectly fine for, say, an armature with a baked animation.

$\endgroup$
1
  • $\begingroup$ This worked very well, thank you very much! I hadn't used the NLA editor before so I'm glad to discover it this way. $\endgroup$ Commented Dec 20, 2022 at 20:16
5
$\begingroup$

About the 1st .blend file

I think the problem is that the Cube object itself is the target of its own variables. The result of dumping the values of the variable from the function, drv_calc_change, is shown below. This gave the wrong result that var had values in other frames.

enter image description here

On the other hand, the API document has the following description.

use_self

Include a ‘self’ variable in the name-space, so drivers can easily reference the data being modified (object, bone, etc…)

I don't think this wording directly says the solution, but it seems to work fine when I try it.

enter image description here

I hope someone can provide a technical explanation.

Edit: Added an animated image
Notice how the smaller cube now moves smoothly? I printed the difference value to the console, but I seems it doesn't feel practical.

enter image description here

$\endgroup$
3
  • $\begingroup$ I did try your suggestion, but just like when I try your modified Blender file nothing happens after pressing play. The driver doesn't update and stays at 0 throughout... Could there be a difference in our settings? $\endgroup$ Commented Dec 15, 2022 at 7:40
  • $\begingroup$ don't press play, but use the arrow keys, then it will update. I think by pressing play UI won't get update so that fps doesn't go down too much. After you stepped a bit and press play again, you will see that the value seems to be constant then. $\endgroup$
    – Chris
    Commented Dec 15, 2022 at 9:58
  • $\begingroup$ @Zoukeau, sorry. If what you're looking for is to have the display of custom properties updated in real time, please ignore my answer. There was a problem with the original file that sometimes the internal "difference" value, not the display value, was incorrectly retrieved zero. I have fixed this. $\endgroup$
    – tetii
    Commented Dec 15, 2022 at 11:13
0
$\begingroup$

Have you tried translating your script into Simulation nodes? (Blender 3.5 build).You can do the same frame by frame calculations and attribute storage and then translate that into a set of drivers.

@celestialmaze on twitter has done some experimentations in this vain. Dissecting this thread should shed some light on his approach: https://twitter.com/cmzw_/status/1598349619058003970 (scroll for the node graph).

$\endgroup$
2
  • $\begingroup$ The way you describe it, it sounds like it would work. Is the build stable? $\endgroup$ Commented Dec 20, 2022 at 19:34
  • $\begingroup$ 3.5 is still an experimental build and simulation nodes can be temperamental if you tax it too much. That said, this kind node setup shouldn't stretch the feature too much as it's only updating attribute values. $\endgroup$
    – Callmepro
    Commented Dec 21, 2022 at 15:58
0
$\begingroup$

I tried to tackle this problem with Animation Nodes, I read in a different thread that it could be a potential solution. I've only started using them today but this is what I put together: Animation Nodes (I hope everything is clear enough, I squashed everything together to be able to make a .gif out of a it.)

What this does is subtract the cube's location data of the previous frame (Frame - 1.00) from the current frame, per axis. Then it feeds the results into the location data of another object, a sphere. I tried to feed the results into custom properties at first but when trying to use their value in other drivers they wouldn't update.

$\endgroup$

You must log in to answer this question.

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