Path to Ipo

Hi.
I am trying to create a script that will traslate the motion of the object from Path to Ipo.
One solution that I found was to create a duplicated new Object and make a key at every frame from the motion of the original here is the script.


#Bake the animation in a way.
 
# f1 is the start frame f2 is the end
# change them to suit your needs
f1 = 0
f2 = 60
import Blender
#The selected Object
ob = Blender.Object.GetSelected()[0]
#The duplicant
Blender.Object.Duplicate()
ob2 = Blender.Object.GetSelected()[0]
ob2.clrParent()
ob2.clearIpo()
 
for i in range(f1 , f2):
  Blender.Set('curframe' , i)
 ob2.setMatrix( ob.getMatrix() )
  ob2.insertIpoKey(0)
 ob2.insertIpoKey(1)

For an anknown reason the insertIpoKey(3) that is the LOCROT was not working so I made separated the insert of keys for LOC and ROT.
After seeing the result I thought that this is the simplest way. But it is very costly as it is create too many keys. But the result was looking as a Curve. So this must be possible to be created with fewer keys with well made Curves.

So here comes my limitations. I readed sometime before an explanation and a code for Splines. The mathimatics was way over my knowledge so I the only thing that I was able to do was to copy paste the code. This is not good.

Another thing that confused me was that Blender Api handles paths like curves and in curves you can change only the U and V coords , but paths have three parameters. Also I was not able to get the BezTriples.

What this can give as. A better handle for exporters. Also the abillity to use paths in Blender Game Engine.

Thanks.

It may be kind of messy, but it beats the heck out of doing it by hand. You’re my hero!

You’re my hero, haramanai. I was trying to no avail to use Doc Holiday’s path to IPO solution (which was much more complicated, by the way). I’ve tried your script, and I’m very happy with the results. May I use this in a tutorial and make it available from my website? I will certainly give you all credit as the author of the script.

Thanks Haramanai
That is perfect for my train project it saves me so much time. i made a slight mdodification though so you can control how many frames per ipo keys.
[LEFT]#Bake the animation in a way.

f1 is the start frame f2 is the end

change them to suit your needs

f1 = 0
f2 = 60
#sets the number of frames per ipo keys
step =5
import Blender
#The selected Object
ob = Blender.Object.GetSelected()[0]
#The duplicant
Blender.Object.Duplicate()
ob2 = Blender.Object.GetSelected()[0]
ob2.clrParent()
ob2.clearIpo()

for i in range(f1 , f2 , step):
Blender.Set(‘curframe’ , i)
ob2.setMatrix( ob.getMatrix() )
ob2.insertIpoKey(0)
ob2.insertIpoKey(1)

Thanks Again
Dr S
[/LEFT]

How do you set how many frames the path translates into IPO frams as? I thought it was the PathLen: number but that doesn’t work.

E.g. if you make a path and you want it to last for 500 IPO frames, how do you do that?

Thank you very much…the script is perfect!!

I’ve actually been working on a similar script, that takes in a b-spline curve as the path and generates the IPO curves directly from that, the script works somewhat because I am in the process of implementing rotations.

The script I am working on is called curve2ipo, there is links here in this forum as well as here in my journal
http://forum.guildofwriters.com/viewtopic.php?f=60&p=26750&sid=bf76910a434ae5252c53fde323582276#p26750

I’ve been using the BezTriple quite heavily and I know that it does indeed allow for a roll vector if you wish, its called tilt.
You are more than welcome to open up the blend file as when i’m finished i’ll be submitting it to the Blender group, as its a NEEDED feature
I’ll give your script a whirl as we are needing a script quite urgently for our group where we build 3d worlds for a video game called, Myst Complete chronicles

It also uses a lot of neat tricks that are familiar to programmers, but I havn’t yet delved too deep into python to use it at its full potential

Path2IPO.Blend
Path2IPO.zip
I’ve cleaned up your code even further and made it so that it will appear in the scripts menu.

All that is needed before executing is the select the curve and in the Buttons window enter a value for the path length, this is the length the animation will be, not the length of the path

You can also add a few more bits to it to make it the way you want, but i’d suggest that once the script is done, that it shifts the IPO curves to the original and delete the duplicate

The outcome in your script is messy, and is a heck of a lot simpler than mine, where as i’m doing it the hard way, and doing some extra things.

I’ll adapt mine when I finished and polished to handle NURBS Splines too

Edit 1: But I do want to know though where in the API will I find the getMatrix, setMatrix and InsertIPOKey?
Edit 2: I suggest using an Empty to anyone that wants to make a tutorial out of it, as all objects can be parented to the duplicant, it also allows for someone to do a mock up path with banks and turns and so forth before doing anything radical

Hi, Grogyan.

I’ve been thinking about this problem a little again recently, and have a concept I would like to try that will calculate the point on the dLoc ipo curves in such a way that the tangent to the curve at that point will be calculated in the process (edit: this tangent should correspond to the orientation of the object facing along the curve at that point on the curve). I’ll let you know in your thread if I can get it working.

But the reason I posted here is:

The methods that you’re looking for (getMatrix, setMatrix and InsertIPOKey) are part of the Object.Object class in Blender.

Details can be found on this page. Select “Object.Object” in the lower frame on the left hand side, and a list of all the methods and properties available to that class will appear in the large frame to the right. Scroll down the frame on the right to find details of the methods that you’re interested in.

Hope this helps.

Doh.
I found a problem when using this script, it has a wobbly with curve circles at 270 degrees

I found out a couple of things today,
The first is that

[quote]
ob2.insertIpoKey(0)
ob2.insertIpoKey(1)[/quote
Can be made into
ob2.insertIpoKey(3)

The second thing is to get over the problem of the 270 degree glitch, and the only viable way to do that is to use math, ie the AnglebetweenVecs() and normalise(), and add that value that is +/_ to the last rotation

Coincidentally, i’m going to try and do the same, probable tomorrow or after the weekend on my script as well on this one, though i’ll be using this script as an experimental platform, cause well, my script is complicated

Hey folks, nice thread here.

I have been testing haramanai’s script and found it is not very accurate for complex
paths. Here is the blend file that describes the problem:

http://www.blendernyc.org/haramanaiScriptError.blend

How to demonstrate the problem (from the above blend file):

  • Create a path like crossover. Make sure it lies in the X-Y plane and
    crosses itself once.

  • Create a UV sphere, give it a material and color it red

  • Position the center of the UV sphere at the start of the path
    (select the first point in the path, then snap cursor to selection,
    then select the sphere, and do snap selection to cursor)

  • Select the UV sphere, then shift-click on the path, selecting both

  • Hit Control P (to make the curve the parent of the uv sphere)
    the select Follow Path.

  • Now animate. The UV sphere will follow the path correctly.

  • Now select the UV sphere, and switch to the script
    bakeIposForGameEngine (I just renamed this, it’s haramanai’s script)

  • Execute the script.

  • You will now have another sphere, make it’s material independent and
    color it blue.

  • Animate. You will see the red and blue ball are not exactly coincident.

  • This is no big deal for a small example perhaps, but if you make
    a complex path, for example by using the spirals.py script I have
    included here, the error becomes intolerable.

  • Notice that with a more complex path, like spiral, the error is far
    greater

Ideas?

  • Nick

Hi again peeps,

I also tried Grogyan’s script. It works a bit better than Haramanai’s but there
are still problems. Perhaps this is another manifestation of the 270 degree problem
you mention above?

Here’s the link:

http://www.blendernyc.org/grogyanScriptError.blend

I just discovered the problem I was having with haramanai’s script had to do with
the value of step.

Specifically, if step is too large, the resulting IPOs will not track the path very well.
To get a nearly perfect tracking use step=1

  • Nick

Hi, I modified the script a bit to make it more foolproof and useable, hope you don’t mind, haramanai. I have an idea that may convert the Ipo curves into the bezier format for more easier editing (move the points and handles rather than every point on the line), and the way I built the script should help with integrating this functionality.

It’s still very much a work in progress, but I’ve uploaded a cleaned up version to my Googlepages site, only available from this direct link:
ShortScript_haramanai.py

Simply create a Bezier curve and an object, select both (doesn’t matter which first) then run the script. The curve needs Curve Path selected in the edit buttons for some reason, and it has to be run in object mode, but everything else should work fine. The generated Ipo block has a name in the format “IpoFrom<name of curve>” in order to distinguish quickly between Ipo blocks created from different curves. The Ipo block will be attached to the object. If the script is run on more objects using the same curve then they will all use the same Ipo block.

I’d like the finished result to be in DRot and DLoc rather than Rot and Loc Ipos, but can sort this out when I’m converting to Bezier Ipo curves so haven’t coded it yet.

I’ve used an empty rather than a duplicate object, but i’m not happy with the code… doesn’t seem very elegant, but the empty is removed when it’s work following the curve is done leaving just the curve and the mesh object.

Wow the differences in code have changed when I started to tackle this problem of creating IPOs from a path

I like yours FunkyWurm, just a couple of suggestions though

elif object.getType() == “Mesh”:
Mesh = object

Add underneath that
elif object.getType() == “Empty”:
Mesh = object

Because otherwise it will throw up an error when there is an Empty selected as an object

It should clear the parenting of the object after the IPOs have been created

Lastly, there is still that nagging problem of when the animation hits 270 degrees

To see what I mean, insert a bezier Curve Circle as a path, then look at the generated IPO’s

#!BPY

“”"
Name: ‘FunkyWurm Path 2 IPO’
Blender: 248
Group: ‘Wizards’
Tooltip: ‘Bezier curve to IPO’
“”"

Cause I just like it that way

last but not least, something that I had planned on when I did my script.
IPOCurve time.append([0][0])
IPOCurve time.append([getPathLen()][getPathLen()])

This will allow the user to adjust the IPO’s time factor easily, so that if they want the object to move faster at one point or slower at another they can, just like in a roller coaster
Which by the way is how I am envisioning this script to be used (I don’t work for amusement parks)

Can anyone please suggest a way to implement into this script,
assigning the name of the IPO curve the same name as the object
appending a time curve

I have so far
myIPOCurveSet = Blender.Ipo.New(‘Object’, myCurveName) # Attmpting to get the Curve name same as IPO curve set
myIPOCurveSpeed = myIPOCurveSet.addCurve(‘Time’)
ipo = Ipo.Get(myIPOCurveSet.name) # retrieves an Ipo object
ipo.name = myCurveName

But this isn’t working in this script

Grogyan, when you talk about problems at 270 degrees, do you mean Blender’s z curve twist problem?

http://freefactory.org/posts/stupid-blender-tricks-1

I dunno.
But i’m giving up on trying to improve on my script, so all I am trying to do now is to get it to work the way I need it to, no frills

One being assigning the object name to the IPO curves
The other, I need to be able to append a tuple to a specific block, more specifically the
Time block,
I have the append function waiting, Blender is just asking for the name of the curves, which are created automatically in the script in this thread, I know what they are called, but no way of accessing them in the datablock.

I have tried using my old code to do it but its incompatible due to the nature of using the insertIpo () for objects, and no way that I can see of addressing the datablock

Hi all,

I modified the script from post no 15 a bit for my purposes and thought it might be useful for others, so here it is.

Changes:

  • put it in “Object” menu for easy access from the 3D menu header, acces via Object-> Script -> Path 2 IPO.
  • added a GUI with a Step value for not recording keys every frame. Value 10 for example means: record every 10th frame. First and last frames get recorded in any case.
  • also in GUI, “Speed IPO Name”. If the path has a speed ipo, set the name here, default is “speed”. The script then uses the speed ipo for path length, otherwise it uses the PathLen setting in curve edit buttons.
  • made IPO clearing work better
  • some small general cleanups and fixes

I hope I listed all authors. If not, please tell me. Thanks very much for your work on the script. Btw, it might be good to add a GPL header, would the other authors agree?

Here’s my version, object-path-to-ipo.py

#!BPY

"""
Name: 'Path 2 IPO'
Blender: 248
Group: 'Object'
Tooltip: 'Bezier curve to IPO'
"""

# By haramanai, FunkyWurm, Sanne
# http://blenderartists.org/forum/showthread.php?t=83942&highlight=path+to+ipo

# Changes by Sanne, 29. Nov 2008:
# - put it in "Object" menu for easy access from the 3D menu header, acces via Object-&gt; Script -&gt; Path 2 IPO.
# - added a GUI with a Step value for not recording keys every frame. Value 10 for example means: record every 10th frame. First and last frames get recorded in any case.
# - also in GUI, "Speed IPO Name". If the path has a speed ipo, set the name here. The script then uses the speed ipo for path length, otherwise it uses the PathLen setting in curve edit buttons.
# - made IPO clearing work better
# - some small general cleanups

import Blender
from Blender import *

def GetObjects():
    """ Get selected objects
    
    Make sure that a curve and a mesh have been selected
    Return the curve and mesh objects
    """    
    
    # Initialise the variables
    Curve = None
    Mesh = None
    
    ObjList = Blender.Object.GetSelected()
    
    # Abort if too many objects are selected
    if len(ObjList) &gt; 2:
        retval = Blender.Draw.PupMenu("Select 1 curve and 1 object only")
        return
    
    # Assign objects to their variables
    for object in ObjList:
        if object.type == "Curve":
            Curve = object
        elif object.type == "Mesh":
            Mesh = object
        elif object.type == "Empty":
            Mesh = object
    
    # Abort if required objects are not selected
    if Curve == None or Mesh == None:
        retval = Blender.Draw.PupMenu("You must select 1 curve and 1 object")
        return
    
    # Abort if curve not set to curve path
    bitMask = 0x08 #the flag for curve path in Curve.data
    if not Curve.data.getFlag() & bitMask:
        retval = Blender.Draw.PupMenu("Curve must be set to a curve path")
        return
    
    # Return objects if all is well
    return Curve, Mesh


def getEndFrame(Curve, speediponame):
    """ Get the end frame of the path animation
    
        If the curve has a speed IPO, get the speed IPO's last frame
        number (truncted to int), else use the curve's PathLen value.
        
        Appearantly Curve.getIpo() doesn't return a present speed ipo,
        so we need to pass the name of the speed ipo in order to access it.
    """
    speedipolist = [ipo for ipo in Ipo.Get() if ipo.name == speediponame]
    if speedipolist:
        speedipo = speedipolist[0]
        speedcu = speedipo[Ipo.CU_SPEED]
        if speedcu:
          lastbeztr = speedcu.bezierPoints[-1]
          end = int(lastbeztr.pt[0])
          print 'Using endframe %d of speed ipo "%s".' % (end, speediponame)
        else:
          end = Curve.data.pathlen
          print 'No speed curve in speed ipo "%s" found, using pathlen %d of curve.' % (speediponame, end)
    else:
        end = Curve.data.pathlen
        print 'No speed ipo "%s" found, using pathlen %d of curve.' % (speediponame, end)
    return end
    
  
def BakeIpoCurves(Curve, Mesh, step, speediponame):
    """ Bake path animation to IPO curves
    
        Thanks to haramanai for the concept of this function.
        It seems to be necessary to copy the LocRot matrix from
        one object to another in order to add the Ipo keys to a
        second object. In this instance, I created an empty.
    """
    
    # Check for existing Ipo block that could be used
    # in order to avoid unnecessary duplication
    try:
        ipo = Ipo.Get("IpoFrom"+Curve.data.name)
    except:
        ipo = Ipo.New("Object","IpoFrom"+Curve.data.name)
    
    # Delete IPO curves if present (Mesh.clearIpo() just unlinks,
    # gets relinked later, so doesn't delete anything)
    if Mesh.ipo and Mesh.ipo.name == ipo.name:
        cc = dict(ipo.curveConsts.items())
        for icu in ipo.curves:
            ipo[cc["OB_"+icu.name.upper()]] = None
    
    if not Mesh.ipo:
        Mesh.ipo = ipo
    
    # Create an empty and make it follow the curve path
    empty = None
    empty = Object.New('Empty','tempEmpty')
    empty = Scene.GetCurrent().objects.new('Empty')
    empty.constraints.append(Constraint.Type.FOLLOWPATH)
    empty.constraints[0][Constraint.Settings.TARGET] = Curve
    empty.constraints[0][Constraint.Settings.FOLLOW]  = True
    
    # Animate the empty along the curve path, copying loc/rot at 
    # each frame to the object and inserting Ipo keys for the object
    start = 1
    end = getEndFrame(Curve, speediponame)
    
    hasendkey = False
    
    for i in xrange(start, end+1, step):
        Blender.Set("curframe", i)
        Mesh.setMatrix(empty.matrix)
        Mesh.insertIpoKey(Object.IpoKeyTypes.LOCROT)
        if i == end:
            hasendkey = True
        
    if not hasendkey:
        Blender.Set("curframe", end)
        Mesh.insertIpoKey(Object.IpoKeyTypes.LOCROT)
        
    Blender.Set("curframe", 1) # Change current frame to 1 again to be tidy
    
    # Clear up the empty. Nice and tidy ;-)
    #Scene.GetCurrent().unlink(empty)
    Scene.GetCurrent().objects.unlink(empty)
    
    return ipo


def main():
    """ The main function """
    try:
        Curve, Mesh = GetObjects()
    except:
        retval = Blender.Draw.PupMenu("Script aborting")
        return
    
    PREF_STEP = Blender.Draw.Create(1)
    PREF_SPEEDIPO = Blender.Draw.Create("speed")
    block = []
    # inputs: title, button, min/max values, tooltip
    block.append(("Step ", PREF_STEP, 1, 10000, "Insert key step value"))
    block.append(("Speed IPO name: ", PREF_SPEEDIPO, 0, 21, "Name of the path's speed IPO, if present"))
    
    if not Blender.Draw.PupBlock("Path 2 IPO", block):
        return
    
    bakedIpo = BakeIpoCurves(Curve, Mesh, PREF_STEP.val, PREF_SPEEDIPO.val)


# ------------------------
if __name__ == "__main__":
    main()