8
$\begingroup$

I've made a scene with a car travelling along a path; is there a way that I can simply set the speed of the vehicle in m/s or km/h?

Manually calculating the distance my object has to travel in a certain time, or setting the correct slope in the graph editor seems like a hassle that shouldn't be necessary.

$\endgroup$
  • $\begingroup$ Please check my answer again, I derped and the speed wasn't right. $\endgroup$ – someonewithpc Apr 11 '15 at 18:04
4
$\begingroup$

I think I finally have a working solution:

    import bpy, mathutils
from mathutils import Vector

le = 0

#Speed in m/s
targetSpeed = 10
obj_name_original = bpy.context.active_object.name

def getLenght():
    ob = bpy.context.active_object        
    if ob and ob.select and ob.type == 'CURVE':  

        em = (ob.mode == 'EDIT')
        bpy.ops.object.duplicate_move()            
        bpy.ops.object.mode_set()
        bpy.ops.object.transform_apply(scale=True)                                  
        bpy.ops.object.convert(target='MESH', keep_original=False)
        ve = bpy.context.active_object.data.vertices
        global le
        dd = le = 0
        for i in bpy.context.active_object.data.edges:
            dd = ve[i.vertices[0]].co - ve[i.vertices[1]].co
            le += dd.length
        le = round(le,4)
        bpy.ops.object.delete()
        print(le)
        if em: bpy.ops.object.mode_set(mode='EDIT', toggle=False)

        global obj_name_original
        bpy.context.scene.objects.active = bpy.context.scene.objects[obj_name_original]
        bpy.context.object.select = True

    else:
        raise Exception("The selected object is not a curve")


targetC = 0

def findC():
    global obj_name_original
    for ob in bpy.data.objects:
        if ob and ob.type == 'MESH':
            for c in ob.constraints:
                if c.target.name == obj_name_original:
                    global targetC
                    targetC = c
                    #print(c)

def setO(scene):
    global targetSpeed
    global targetC
    global le #scene.render.fps    ((le/targetSpeed))*(scene.frame_current/(scene.frame_end*targetSpeed))
    targetC.offset_factor = scene.frame_current/((le/targetSpeed)*scene.render.fps)

getLenght()
findC()

def register():
    bpy.app.handlers.frame_change_pre.append(setO)


def unregister():
    bpy.app.handlers.frame_change_pre.remove(bpy.app.handlers.frame_change_pre[-1])


if __name__ == "__main__":
    register()

The way it works is that it approximates the length of the curve, and then changes the offset of the object following it every frame - essentially animating it. It does require that you select the curve before running the script, otherwise, it will purposely crash.

If you want to use km/h instead of m/s you just need to divide the speed by 3.6, which will convert it to m/s.

$\endgroup$
  • $\begingroup$ I gather Blender doesn't have the functionality built in, but this script will do. Thanks. $\endgroup$ – cybrbeast Apr 11 '15 at 8:28
  • $\begingroup$ No, not that I know of. $\endgroup$ – someonewithpc Apr 11 '15 at 9:25
1
$\begingroup$

you must know the total travel time

after that you must configure the parameters of frames per second (ftps) and the path animation parameters as frame and Evaluation time.

that is a simple rule of three

configuración path

also you can calc the length of a Bezier curve please check: http://blenderartists.org/forum/showthread.php?206790-Length-of-a-Bezier-curve-in-2-5 or you can try with my script that will print the lenght in console:

import bpy, bmesh

for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':    

        ob1 = bpy.context.active_object # this is the curve

        bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(0, 0, 0), "constraint_axis":(False, False, False), "constraint_orientation":'GLOBAL', "mirror":False, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "texture_space":False, "remove_on_cancel":False, "release_confirm":False})

        bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

        bpy.ops.object.convert(target='MESH')

        bpy.ops.object.editmode_toggle()

        obj = bpy.context.object
        me = obj.data
        bm = bmesh.from_edit_mesh(me)

        edges= [e for e in bm.edges]

        total = 0
        for edge in edges:

            total = (total + edge.calc_length())

        print("total: ",total)


        bmesh.update_edit_mesh(me, True)  
        bpy.ops.object.editmode_toggle()
        bpy.ops.object.delete(use_global=False)

        ob1.select = True
        bpy.context.scene.objects.active = ob1
$\endgroup$
  • 2
    $\begingroup$ And how does that give you the speed in kph or m/s, unless you know the exact length of the curve? For a bezier curve, like the one you've got (looks quadratic to me), the arc length is quite complicated. If you go up to a cubic one, you'll need elliptic integrals. I believe the OP wanted to avoid number crunching. $\endgroup$ – user7952 Apr 10 '15 at 18:51
  • $\begingroup$ @SixthOfFour I'm update the post.. please check $\endgroup$ – yhoyo Apr 10 '15 at 19:28
  • 1
    $\begingroup$ As far as I can tell, that sums the length of the straight lines between the vertices. A good approximation, as that is likely what and object with a Follow Curve constraint actually follows. +1, but I still feel that the OP has a point: it should be simpler. If you could just set the speed, you could even animate the shape of the curve, if it was properly implemented. $\endgroup$ – user7952 Apr 10 '15 at 19:38
  • $\begingroup$ @SixthOfFour please check the someonewithpc script.. that is a good aproximation to this solution too $\endgroup$ – yhoyo Apr 10 '15 at 19:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.