So I am fairly new to belnder and I got myself into a problem. I want to rig that camshaft so that the cam pushes down the rocker arm beneath it. With blender pyhsics it does not really work so I tried an approximation using drivers and a sin-function.

Here comes the difficulty: With the expression (see picture) I achieved to let the rocker arm oscilliate. That works pretty neat. But it oscillates all over and I only want it to do that when the cam rotates by. Using an if-statement (e.g. if var > 2.6) it works but then the rocker arm jumps immediately to its end-position instead of smoothly rotating.

Does anyone have an idea of how to fix that? :/

Edit: That's the current expression: 0.1*sin(var-pi/2)+0.1 if var > 2.618 else 0




1 Answer 1


I don't feel like writing you an exact expression, but the philosophy is, smooth out your if.

Here's the simplified if statement:

y if x else z

There is an exactly equivalent statement that uses math instead of conditionals[*]:

((x==true) * y) + ((1-(x==true))*z)

Your current version, restated like that, is

((x>2.618) * (0.1*sin(var-pi/2)+0.1)) + ((1-(x>2.619))*0)

It's just a restatement of what you have. Same exact output.

==true evaluation, or >n evaluation, or redundant (x>n)==true evaluation, defaults to either 0 or 1. Since it's discontinuous, our output function is discontinuous-- not smooth. But what if we use

(x*y) + ((1-x)*z)


This is basically the same function, provided we clamp x to the 0,1 range, but now we can make a continuous function, by using a continuous x-- by using a floating point variable, "x", instead of a boolean variable, "x>n".

So when you do that, you don't have to do it exactly when var>2.618. You can lerp into it, starting at var = 2.5, finishing at 2.8.

Now, you can do this in a single line of code-- remapping a range, min() and max() on it to clamp to the range we want-- but it's easier to just make a new custom property somewhere and drive it from var. Then we can adjust the driver curve of that driver using f-curves to clamp it to whatever range we want, to tune the exact response to what we see on the screen, etc. We could even make it just as discontinuous as var>n, by using keyframes with constant interpolation, although of course that would defeat the purpose.

Once you've got that custom property, then you can implement the custom property in your original driver instead. Let's call this custom property "var2". Now, your driver is

((var2) * (0.1*sin(var-pi/2)+0.1)) + ((1-(var2))*0)

which simplifies to just

(var2) * (0.1*sin(var-pi/2)+0.1)

BTW, even though you didn't ask, this may be solvable with bones and bone constraints (IK), no coding, although I'm not sure. Alternatively, just keyframing it to eye and using an action constraint may be a faster solution than either constraints or drivers.

Edit: Here's what we're doing in GN nodes, for those less mathy. We're going from the top tree to the bottom tree:

enter image description here

The top tree is, mix on the basis of (greater than) * true. The bottom tree replaces that greater than with a map range, to smooth out the if.

[*] Personally, I got in the habit of doing this with some shader coding, to avoid expensive and unnecessary conditionals, and still do it in Blender just because I'm not very comfortable with Python syntax :)

  • $\begingroup$ Alright, thank you so so much! Let me study this and try to implement it :) Thanks! $\endgroup$
    – Philipp
    Mar 2 at 20:56
  • $\begingroup$ You maths people make me dizzy. B-s for me at Stanford, which is a flunking grade in grad school. $\endgroup$
    – james_t
    Mar 3 at 17:05
  • $\begingroup$ @james_t Maybe the GN metaphor I edited in makes sense instead? $\endgroup$
    – Nathan
    Mar 3 at 19:01
  • 1
    $\begingroup$ Just mess'n with ya! $\endgroup$
    – james_t
    Mar 3 at 21:11
  • $\begingroup$ How would you achieve it with bones and IK? $\endgroup$
    – Philipp
    Mar 8 at 15:16

You must log in to answer this question.

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