evalTangent

Moving here from Pipeline.
I experimented with the new NURBS curve system, that enabled by “egg-load-old-curves 0” and try to make Mopath class to it. The problem is that I can’t interpolate the tangent through the evalTangent(), although the evalPoint() works fine. It seems that the tangent changing only on the control points.
My code (look at “goto()”):

from pandac.PandaModules import *
loadPrcFileData("", "egg-load-old-curves 0")
from direct.directbase import DirectStart

class NURBSMopath():
    
    def __init__(self, curve, name = None):
        if (name == None):
            name = 'nurbsmopath'
        self.name = name
        self.duration = 1.0
        self.node = None
        self.loop = False
        self.cnpRef = None
        self.rope = None
        self.evaluator = None
        self.nurbs = None
        self.tDisplace = 0
        self.tCurrent = 0
        self.loopNum = 0
        if curve:
            if isinstance(curve, str):
                self.loadCurves(curve)
            elif isinstance(curve, NodePath):
                self.cnpRef = curve
                self.__extractCurves(curve)
            elif isinctance(curve, RopeNode):
                self.setCurve(curve)
        print self.name
        
    def loadCurves(self, fname, parent = render):
        if self.cnpRef:
            self.cnpRef.detachNode()
        self.cnpRef = loader.loadModel(fname, noCache=True)
        self.cnpRef.reparentTo(parent)
        if self.cnpRef:
            if not self.__extractCurves(self.cnpRef):
                print 'NURBSMopath: can\'t find any curves in file: %s' % fname
        else:
            print 'NURBSMopath: no data in file: %s' % fname
            
    def setCurve(self, curve):
            self.rope = NodePath(curve)
            self.evaluator = curve.getCurve()
            self.nurbs = self.evaluator.evaluate()
            
    def __extractCurves(self, np):
        node = np.node()
        if isinstance(node, RopeNode):
            self.setCurve(node)
            return True
        else:
            for ch in np.getChildren():
               if self.__extractCurves(ch):
                   return True
                   
    def __playTask(self, task):
        start, stop = self.getRange()
        delta = stop - start
        scaled_duration = delta * self.duration
        self.loopNum = int(task.time / scaled_duration)
        if (not self.loop) and (self.loopNum > 0):
            self.finish()
            messenger.send(self.name + '-done')
            self.node = None
            return task.done
        t = self.nurbs.getStartT() + (task.time - \
            (self.loopNum * scaled_duration)) / self.duration + \
            self.tDisplace
        self.tCurrent = t
        self.goto(t)
        return task.cont
        
    def getRange(self):
        if self.nurbs:
            return (self.nurbs.getStartT(), self.nurbs.getEndT())
        else:
            return (0, 0)
        
    def goto(self, t):
        if self.node:
            p = Point3()
            v = Vec3()
            self.nurbs.evalPoint(t, p)
            self.node.setPos(self.rope, p)
            self.nurbs.evalTangent(t, v)
            v = render.getRelativeVector(self.rope, v)
            self.node.lookAt(self.node.getPos() + v)
        
    def play(self, node, duration = 1.0, resume = False, loop = False):
        if self.nurbs:
            if not resume:
                self.lastTime = 0
            self.node = node
            self.duration = duration
            self.loop = loop
            self.stop()
            t = taskMgr.add(self.__playTask, self.name + '-play')
        else:
            print 'NURBSMopath: has no curve.'
        
    def stop(self):
        self.tDisplace = self.tCurrent
        taskMgr.remove(self.name + '-play')
        
    def finish(self):
        start,stop = self.getRange()
        self.tDisplace = 0
        taskMgr.remove(self.name + '-play')


if __name__ == "__main__":    
    b = loader.loadModel('zup-axis')
    b.reparentTo(render)
    b.setScale(0.2)
    nmp = NURBSMopath('curve.egg')
    nmp.cnpRef.setH(45)
    nmp.cnpRef.setPos(-10,0,-5)
    nmp.cnpRef.setScale(1.5)
    nmp.play(b, 10)

    base.disableMouse()
    base.camera.setPos(15,15,15)
    base.camera.lookAt(0,0,0)
    run()

and my Curve

<CoordinateSystem> { Z-up } 
  <Group> NurbsCurve {
    <Transform> {
      <Matrix4> {
        1.000000 0.000000 0.000000 0.000000
        0.000000 1.000000 0.000000 0.000000
        0.000000 0.000000 1.000000 0.000000
        -0.989243 -2.149168 0.000000 1.000000
      }
    }
    <VertexPool> NurbsCurve {
      <Vertex> 0 {
        -2.489244 -2.149168 0.000000 1.000000
      }
      <Vertex> 1 {
        -1.989243 -1.149168 0.000000 1.000000
      }
      <Vertex> 2 {
        0.010757 -1.149168 0.000000 1.000000
      }
      <Vertex> 3 {
        0.510757 -2.149168 0.000000 1.000000
      }
      <Vertex> 4 {
        2.027631 -3.067276 0.000000 1.000000
      }
      <Vertex> 5 {
        4.243067 -2.288880 0.000000 1.000000
      }
      <Vertex> 6 {
        3.604383 0.465445 0.000000 1.000000
      }
      <Vertex> 7 {
        0.091620 1.742813 0.000000 1.000000
      }
    }
    <NURBSCurve> {
      <Scalar> subdiv { 56 }
      <Order> { 4 }
      <Knots> { 0.00 0.09 0.18 0.27 0.36 0.45 0.55 0.64 0.73 0.82 0.91 1.00 }
      <VertexRef> {
        0 1 2 3 4 5 6 7
        <Ref> { NurbsCurve } 
      }
    }
  }

I can get smoothing, like this, but it’s bit ugly, imho

    def goto(self, t):
        if self.node:
            start, stop = self.getRange()
            delta = stop - start
            p = Point3()
            p0 = Point3()
            self.nurbs.evalPoint(t, p)
            self.nurbs.evalPoint(t + delta*0.001, p0)
            if p == p0:
                self.nurbs.evalPoint(t - delta*0.001, p0)
                v = Vec3(p - p0)
            else:
                v = Vec3(p0 - p)
            #v.normalize()
            self.node.setPos(self.rope, p)
            self.node.lookAt(self.node.getPos() + v)

Ah, thanks for the excellent sample program! I tracked the problem down to a cut-and-paste error within the NurbsCurveResult code, and have committed a fix.

David

Ok, i’ll finish Mopath with temporary using workaround.