0
$\begingroup$

I am making an add-on for Blender. You can find it here: https://github.com/rubeste/Blender_f-curve_select

I need to support the normalization of the curve as well. So, I need to calculate the f-curves position. I currently do this by getting the minimum and maximum value of the curve and creating a range between 1 and -1. My problem is that I do this calculation by looking through the whole animation. This takes time, and I only tested it with 3 curves.

I was wondering if there is a better way to obtain the minimum and maximum. Or if I can get the value I want via a different method.

def calculateValeOfNormalizedCurve(self, context, fCurve, frame):
        start = context.scene.frame_start
        end = context.scene.frame_end
        values = []
        value = fCurve.evaluate(frame)
        i = start
        while i <= end:
            values.append(fCurve.evaluate(i))
            i += 0.1
        max = np.max(values)
        min = np.min(values)
        return ((value-min)/(max-min)*2)-1
$\endgroup$

2 Answers 2

2
$\begingroup$

Vectorize evaluate with numpy

Having done similar via What's the range of values on a sound-baked f-curve?

Can vectorize the fcurve evaluate method and pass in an numpy array of frames, then using methods available get the minimum maximum etc.

Will find this much quicker than looping as in question code above.

Test script finds the minimum of each fcurve of each action from frames 1 to 250 using 0.01 subframe increments.

import bpy
import numpy as np

frames = np.arange(1, 250, 0.01)

for action in bpy.data.actions:
    print(f"{action.name}")
    
    for fc in action.fcurves:
        print(f"{fc.data_path}[{fc.array_index}]")
        points = np.vectorize(fc.evaluate)(frames)


        print(f"min {points.min()} at {frames[np.argmin(points)]}")
$\endgroup$
3
  • $\begingroup$ It works but it is slow just like mine solution. $\endgroup$
    – rubeste
    Commented Aug 13, 2020 at 15:01
  • $\begingroup$ To time them against each other change 0.01 above to 0.1. Your posted solution will find the only the first local minimum / maximum. There are a number of numerical methods to find the minima / maxima of a function. $\endgroup$
    – batFINGER
    Commented Aug 13, 2020 at 16:41
  • $\begingroup$ I don't get what you are saying. I think I found a better solution (blender.stackexchange.com/a/190888/77168) in the end. If you see a problem there please comment on it. Would like feedback :) $\endgroup$
    – rubeste
    Commented Aug 13, 2020 at 19:57
0
$\begingroup$

After some thinking, I came up with a solution. What I did was first getting the max/min key-frame on the F-Curve. From this point, I will look to the left or right and wait until the value stops going higher/lower. Once it starts getting lower/higher I can take the previous value as it is the max or min value of that curve. Here is the code of the min calc function:

minFrame = None
min = None
for k in fCurve.keyframe_points:
    if min is None or min > k.co.y:
        minFrame = k.co.x
        min = k.co.y
if min > fCurve.evaluate(minFrame - 0.1):
    i = minFrame
    while True:
        if min > fCurve.evaluate(i):
            min = fCurve.evaluate(i)
        elif min <= fCurve.evaluate(i):
            break
        i -= 0.1
elif min > fCurve.evaluate(minFrame + 0.1):
    i = minFrame
    while True:
        if min > fCurve.evaluate(i):
            min = fCurve.evaluate(i)
        elif min <= fCurve.evaluate(i):
            break
        i += 0.1
return min
$\endgroup$

You must log in to answer this question.

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