Motion path & line classes

one more snippset on mopath and simple line drawing.
toss in a few points, call the getNodepath() function and you can use it right away.

please note: motion path with several thousand points will take AGES to load. it’s fine up to a fewhundret but it starts to slow down a lot. i worked around that in the line-class by splitting it into single segments but i wasnt able to get a continous motion path this way. so keep the number of points down. below 500 is usualy fine.
seems like number of points exponentially slow it. using 9000 points you can wait several minuts, while 1000 still load within a few seconds.
it’s based on the person’s code who onec wrote the “river-by-spline” thing unfortunatley his name was nowhere to be found.
anyway. here it is for future generations:

from panda3d.egg import EggData, EggVertexPool, EggVertex, EggGroup, EggLine , loadEggData , EggNurbsCurve
from panda3d.core import Point3D, NodePath


class createNurbsCurve():
    def __init__(self):
        self.data = EggData()
        self.vtxPool = EggVertexPool('mopath')
        self.data.addChild(self.vtxPool)
        self.eggGroup = EggGroup('group')
        self.data.addChild(self.eggGroup)
        self.myverts=[]
    
    def addPoint(self,pos): 
        eggVtx = EggVertex()
        eggVtx.setPos(Point3D(pos[0],pos[1],pos[2]))
        self.myverts.append(eggVtx)
        self.vtxPool.addVertex(eggVtx)

    def getNodepath(self):        
        myCurve=EggNurbsCurve()
        myCurve.setup(3, len(self.myverts) +3)
        myCurve.setCurveType(1)
        for i in self.myverts:
            myCurve.addVertex(i)
        self.eggGroup.addChild(myCurve)
        #self.data.writeEgg(Filename('test.egg'))
        return NodePath(loadEggData(self.data))



class createLine():
    def __init__(self):    
        self.data = EggData()
        self.vtxPool = EggVertexPool('line')
        self.data.addChild(self.vtxPool)
        self.eggGroup = EggGroup('group')
        self.data.addChild(self.eggGroup)
        self.myverts=[]
    
    def addPoint(self,pos): 
        eggVtx = EggVertex()
        eggVtx.setPos(Point3D(pos[0],pos[1],pos[2])) 
        self.myverts.append(eggVtx)
        self.vtxPool.addVertex(eggVtx)

    def getNodepath(self):
        for i in range(len(self.myverts)):
            if not i%500:
                if i:
                    myline.addVertex(self.myverts[i])
                print i,len(self.myverts)
                myline=EggLine()
                self.eggGroup.addChild(myline)
            myline.addVertex(self.myverts[i])
        #self.data.writeEgg(Filename('test.egg'))
        return NodePath(loadEggData(self.data))


##testing
if __name__ == '__main__':
    from direct.directbase import DirectStart
    from math import sin,cos
    from direct.directutil.Mopath import Mopath
    from direct.interval.MopathInterval import *
    from panda3d.core import NodePath

    myCurve=createNurbsCurve()
    myLine = createLine()
    for i in range(100):
        myCurve.addPoint((cos(i/3.),i,sin(i/3.)))
        myLine.addPoint((cos(i/3.),i,sin(i/3.)) )
    lineNode = myLine.getNodepath()
    curveNode = myCurve.getNodepath()
    lineNode.reparentTo(render)

    myMopath = Mopath()
    myMopath.loadNodePath(curveNode)
    myMopath.fFaceForward = True
    myCube = loader.loadModel("yup-axis")
    myCube.reparentTo(render)
    myInterval = MopathInterval(myMopath, myCube, duration=10 ,name = "Name")
    myInterval.start()
    
    run()

[edit] fixed silly mistake

small update to support rotations,too.

from panda3d.egg import EggData, EggVertexPool, EggVertex, EggGroup, EggLine , loadEggData , EggNurbsCurve
from panda3d.core import Point3D, NodePath

class createNurbsCurve():
    def __init__(self):
        self.data = EggData()
        self.vtxPool = EggVertexPool('mopath')
        self.data.addChild(self.vtxPool)
        self.eggGroup = EggGroup('group')
        self.data.addChild(self.eggGroup)
        self.myverts=[]
        self.myrotverts=[]
    
    def addPoint(self,pos,hpr=None):
        if hpr:
            eggVtx = EggVertex()
            eggVtx.setPos(Point3D(hpr[0],hpr[1],hpr[2]))
            self.myrotverts.append(eggVtx)
            self.vtxPool.addVertex(eggVtx)
        if self.myrotverts and not hpr:
            print "you started to add rotations.. you better see it through now!"
         
        eggVtx = EggVertex()
        eggVtx.setPos(Point3D(pos[0],pos[1],pos[2]))
        self.myverts.append(eggVtx)
        self.vtxPool.addVertex(eggVtx)

    def getNodepath(self,order=3): 
        myCurve=EggNurbsCurve()
        myCurve.setup(order, len(self.myverts) +order)
        myCurve.setCurveType(1)
        for i in self.myverts:
            myCurve.addVertex(i)
        self.eggGroup.addChild(myCurve)
        
        if self.myrotverts:
            myCurve=EggNurbsCurve()
            myCurve.setup(order, len(self.myverts) +order)
            myCurve.setCurveType(2)
            for i in self.myrotverts:
                myCurve.addVertex(i)
            self.eggGroup.addChild(myCurve)
        
        out=NodePath(loadEggData(self.data))
        #self.data.writeEgg(Filename('test.egg'))
        return out

I’m having some irritations with the rotations.

When the one point’s H is -157 and the next point’s H is 167, the camera does a full rotation increasing from -157 up to 167 rather than going from -157 to -180 and then 0 to 167, which is the shorter way.

Is there any way to get around this?

of course there is a fix for that :slight_smile: and as always, panda provides you a magical-function which does the trick

for line the line: eggVtx.setPos(Point3D(hpr[0],hpr[1],hpr[2]))
you need to fitDestAngle2Src for each angle.
you need to know your last rotation value for that and the new one.

basic usage of fitDestAngle2Src:

from direct.showbase.PythonUtil import fitDestAngle2Src
newCorrectAngle = fitDestAngle2Src(oldAngle,NewAngle)

If anyone needs this class with the fitDestAngle2Src update, I’m using an updated version of it here:

github.com/sirikata/progressive … p.py#L6-67

Thanks, ThomasEgi!

Sorry for necroposting, but I’ve found this topic, and it looks appropriate for my case. I have only one question: the resulting curves are monotonic? I mean, are there easeIn and easeOut for the object speed? It looks like no at the first gaze, but still…

P.S. why am I asking - I wasn’t able to paint a correct monotonic curve with a 3D modeler - it always adds speed up and slow down on the edges, while I’d like to have a completely constant movement speed along the whole path.