# Move an object on an irregular plane with python

At this moment I would like to move an object, suppose a "cube" along its y axis, with a slider from the UI panel with a FloatProperty. So far there is no problem. Now, suppose this object encounters a terrain (an irregular mesh with various polygons) is there a way to make it follow the normals of this hypothetical path? Normally I would have used a path with a bezier, but I would like to be able to do this with a simple control in the UI panel, I insert an image to understand better

I have no idea to do this, I suppose I probably have to register all the faces of that plan? Or something similar? It seems a bit complex to me.

Edit: I was kindly suggested by Leander, to use the raycasting method, obviously I did not know this function , I would also like to understand if it is possible to record the animation correctly using keyframes, I could put a kind of operator that cooks the keyframes, or something similar

• Possible duplicate of Script for getting Camera Look At co-ordinates – Leander Jul 28 '19 at 21:03
• I've voted to close this as a duplicate. Even if the wording is not the same, the answer also solves your quest. Just raycast a ray straight downwards at the specific (X, Y) location and position the cube at the "hit" position. – Leander Jul 28 '19 at 21:03
• @Leander Thank you very much for reporting, surely it's a similar question, but not too much, some people like me might find a solution to this specific question interesting, I really appreciate your script with the camera. The raycast method is very interesting. I should also take into account being able to animate everything with keyframes, which this seems a bit problematic – Noob Cat Jul 28 '19 at 21:19
• I thought you would be willing to do the additional coding and transfer yourself. I added an answer, don't feel like you need to accept it though. Good luck. – Leander Jul 29 '19 at 7:31

There's something wrong with the ray_cast, which messes up on a few casts. But I think this could clear up if placed in a modal operator.

I believe the script from this answer achieves what you want.

The result looks very similiar to your gif.

• Convert the collision geometry to a bmesh, apply the transformation matrix and get a bvhtree from the transformed bmesh.
• Cast a ray from above the Cube's location straight downwards (0, 0, -1) and check if it intersects with the bvhtree.
• Create a keyframe.
import bpy
import bmesh
from mathutils.bvhtree import BVHTree
import mathutils

# the epsilon value for the BVHTree calculations
EPSILON = 0.0000001

# maximum ray distance XY plane
MAXIMUM_Z = 1000

# make sure you have a Camera and an Empty named like this
landscape = bpy.data.objects["Landscape"]
cube = bpy.data.objects["Cube"]

# create the BVHTrees from a bmesh of the "sticky" object
# the bmesh conversion makes it easy to apply the individual objects transformation matrices
bm = bmesh.new()
bm.from_object(landscape, bpy.context.scene)
bmesh.ops.transform(bm, matrix=landscape.matrix_world, verts=bm.verts)
tree = BVHTree.FromBMesh(bm, epsilon=EPSILON)

# the main method for setting the new z position
def reposition_z(scene = bpy.context.scene):

# create a direction vector, which points downwards and
# a origin for the raycast
dir = mathutils.Vector((0, 0, -1))
origin = mathutils.Vector((*cube.location[:2], MAXIMUM_Z - EPSILON))

# if there is a hit, move the cube to that location
loc, no, i, d = tree.ray_cast(origin, dir)
if d is not None:
# assign the cube's location
cube.location = loc

# remove all handlers, then create a new one with the reposition_z function
post_handlers= bpy.app.handlers.scene_update_post
[post_handlers.remove(h) for h in post_handlers if h.__name__ == "reposition_z"]
post_handlers.append(reposition_z)


Setting a keyframe could look like.

for i in range(start, end):
bpy.data.scenes["Scene"].frame_set(i)
reposition_z()
cube.keyframe_insert(data_path = 'location')

• Why do you remove all handlers? – lemon Jul 29 '19 at 7:31
• @lemon Testing purposes... so I can run the script multiple times and "clean up " on the fly. Got anything more graceful? – Leander Jul 29 '19 at 7:32
• More graceful I don't know... I usually test to remove only the handler that I will append so that I don't remove handlers from other scripts. Like in this answer (Scene Handler part) blender.stackexchange.com/questions/143273/… – lemon Jul 29 '19 at 7:35
• @lemon Shouldn't have been lazy, updated. – Leander Jul 29 '19 at 7:38