I need a Challenging 'Scripted Expression' problem solved

The general solution I am looking for is basically a Distance Input Variable. The reason why it doesn't work in my case, is because the value doesn't go past zero into the negative numbers like how a 'Transform Channel' behaves.

Quick note, not that much experience in drivers, and Python code for these scripted expression. I have read 'Workflow & Examples' and 'Drivers Panel' in Blender Manual, and it didn't help me.

I want a driver for a shape key on a torus. Whenever another object comes closer in a certain direction, let's say Z, it opens when it is close, and stays open when continuing in whatever direction it was advancing in.

I know one expression for a singular axis can behave the way I want, and that's (Cube_Z * -1) + Torus_Z, with an alteration of the F'urve. As you may guess this only applies to the Z axis, and anywhere in the 3D Viewport, along the X or Y axis (away from the Torus), the value will not change.

The only qualifications are:

• It has to be automatic, and I don't have to adjust anything for it to work
• I can translate it, and rotate it however I wish without breaking it
• The shape key cannot have a value higher than 0, unless the torus, and cube are close to each other.

If you have any other suggestions on how to make this possible. It doesn't have to be with drivers, it could be with Object Constraints or even Modifiers.

• Hi Jared, this is not a forum where you commission work, be it free or paid. You have to phrase your problem in a way, that is specific enough to have a definitive answer, but also general enough to be of use to future visitors. It's also perfectly fine to phrase your problem in a more general way, and then describe what you're trying to do specifically as a measure to avoid XY Problem - then it's up to answer authors on how far they will help you beyond solving the main issue. Start with adding some images better explaining your problem. Dec 4, 2021 at 17:56
• While I would agree with you, however there is little to no information on 'Scripted Expressions' for drivers. Either for YouTube, Udemy, the Blender Manual, or Lynda. That any information pertaining to this topic 'would' help in a tiny way when pertaining to this subject. While we could argue about semantics on how my question has to be presented in a certain way, or how anything can be for hire. I'm just gonna say that 'Blender Stack Exchange' is a great website that presents a solution to a problem. I tried to educate myself to solve this issue. So hear me, this was my last resort. Dec 5, 2021 at 13:23
• So, here I completely glossed over a implementation that has solved my problems. However the 'It has to be automatic, and I don't have to adjust anything for it to work' is slashed in this case. Which is fine, I can work with that. Apparently you can do a 'if' 'else' statement in the text box. Dec 7, 2021 at 7:54

If i understood you right, you want this:

here is the code:

import bpy
from mathutils import Vector

# distance
loc1 = (0,0,0)

def before(frame):
global loc1
ob = bpy.context.scene.objects["Cube"]
loc1 = (ob.matrix_world[0][3], ob.matrix_world[1][3], ob.matrix_world[2][3])
print("cube", loc1)

def changeShapeKey(frame):
global loc1

torus = bpy.context.scene.objects["Torus"]

ob = bpy.context.scene.objects["Cube"]

torusLoc = (torus.matrix_world[0][3], torus.matrix_world[1][3], torus.matrix_world[2][3])

loc2 = (ob.matrix_world[0][3], ob.matrix_world[1][3], ob.matrix_world[2][3])
print("before", loc1)
print("after ", loc2)

before = (Vector(torusLoc) - Vector(loc1)).length
after = (Vector(torusLoc) - Vector(loc2)).length

moving = "to torus"

if after > before:
moving = "away from torus"
bpy.data.shape_keys["Key.001"].key_blocks["Key 1"].value = 1
elif after == before:
moving = "not moving"
else:
if before < 5:
value = 1 - before / 5
else:
value = 0
bpy.data.shape_keys["Key.001"].key_blocks["Key 1"].value = value

print("frame:", frame, "moving:", moving, "distance:", before)

# open
#    bpy.data.shape_keys["Key.001"].key_blocks["Key 1"].value = 1

# closed
#    bpy.data.shape_keys["Key.001"].key_blocks["Key 1"].value = 0

bpy.app.driver_namespace['changeShapeKey'] = changeShapeKey

def my_handler(scene):
changeShapeKey(scene.frame_current)
print("myhandler")

def my_handlerBefore(scene):
before(scene.frame_current)
print("before")

def register():
bpy.app.handlers.frame_change_pre.append(my_handlerBefore)
bpy.app.handlers.frame_change_post.append(my_handler)

def unregister():
bpy.app.handlers.frame_change_pre.remove(my_handlerBefore)
bpy.app.handlers.frame_change_post.remove(my_handler)

if __name__ == "__main__":
register()


what it does:

it saves loc1 (the location of the cube) for the "old" frame then it compares loc2 (the location of the current frame) and checks, whether the cube animation moves to the torus or away from the torus.

If it moves away (distance increases), the torus will be set to open. If it move towards the torus (distance decreases), the torus will be opened if the distance is smaller than 5 and then it will gradually open.

Note: This does only look good, if the cube moves through the center of the torus. But of course the torus will open whenever the distance gets bigger.