Problem with 2x MopathIntervals


#1

Hello there.

I’ve just started experimenting with motion paths and I’ve got the code below.

“waterfall” and “w3” are NURBS curves (identical curves, but each with unique names i.e. w3.egg is just a copy of waterfall.egg with the names changed) created in Blender.

“female2” and “kayslacks” are two different human models (different models, both with unique mesh/armature names). (I applied a random brick texture just for the sake of testing)

You can also see I’ve assigned everything to different variables, created 2 motion paths and 2 intervals, etc.

I’d expect each model to follow the motion path relative to their respective positions. This is what happens when there’s just 1 model, 1 path and 1 interval. However, when I have both models/paths/intervals, the two models will follow one motion path relative to the 2nd model (e.g. it doesn’t matter what position I set on the 1st model; it gets repositioned to where the 2nd model is and follows the same motion path in the same place).

(I should perhaps also mention that this problem only occurs when the intervals are involved; if I comment out those last 4 lines, both models will be positioned as/where expected by setPos)

Am I missing something about how motion paths/intervals work?

Thanks in advance for any input.

    path = Mopath.Mopath()
    path.loadFile("waterfall.egg")
    
    path2 = Mopath.Mopath()
    path2.loadFile("w3.egg")
    
    myTexture = loader.loadTexture("tex/brick1.png")
    
    m = loader.loadModel("female2.egg")
    m.setTexture(myTexture)
    m.setTransparency(TransparencyAttrib.MAlpha)
    
    m2 = loader.loadModel("kayslacks.egg")
    m2.setTexture(myTexture)
    m2.setTransparency(TransparencyAttrib.MAlpha)
    
    m.setPos(220, 220, 220) # this should move the first model off-screen, but it doesn't; it stays at 0, 0, 0
    m2.setPos(0, 0, 0) # changing this moves both models
    
    m.reparentTo(render)
    m2.reparentTo(render)
    
    myInterval = MopathInterval(path, m, duration=1, name = "Name")
    myInterval.loop()
    
    myInterval2 = MopathInterval(path2, m2, duration=1, name = "xName2")
    myInterval2.loop()

#2

And you did not try to set the position for each path? for example, path.setPos (8, 0, 0) in this case, you need to act in reverse order, first set where your path will be.


#3

I’m not at a PC atm, but I’m fairly sure I tried this and got an error that there is no setPos for paths.


#4

Actually it does not work. Which is pretty weird.

from panda3d.core import *
from direct.directbase import DirectStart
from direct.directutil.Mopath import Mopath
from direct.interval.MopathInterval import *


myModel = loader.loadModel('nurbs')

curveNode = myModel.find("**/+NurbsCurve")
curveNode.setPos(30, 0, 0)

myMopath = Mopath()
myMopath.loadNodePath(curveNode)

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

base.run()

#5

Don’t hold me to this, but I think I’ve partly figured out what’s causing me some confusion.

It seems lookAt(m2) was looking at the point specified in the call to m2.setPos, even though the model itself was being repositioned to the curve (roughly the origin) by the interval - which gave the illusion of the model moving around the scene whenever I changed the values passed to m2.setPos, when in fact it was always being positioned at (~) 0, 0, 0. So it seems the model really is moved to where ever the path is and not that the path takes effect relative to the model.

I guess the question now would be… how do you reposition the path? Is there something that you can call setPos on? Ideally, is there some way you can parent the path/curve to a dummy node and then position the dummy node? This last one would be most useful because eventually I’ll need to move a group of related paths together. (I did experiment with several variations of serega-kkz’s code, but couldn’t get any of them to move the path/model either)


#6

The most annoying thing is that when exporting, the location of the model in space is not taken into account, I think need to ask this question when the developer YABEE.

I found a way how to do it, but I need to write logic. While an example is short.

from panda3d.core import *
from direct.directbase import DirectStart
from direct.directutil.Mopath import Mopath
from direct.interval.MopathInterval import *


myModel = loader.loadModel('nurbs1')

curveNode = myModel.find("**/+NurbsCurve")

myMopath = Mopath()
myMopath.loadNodePath(curveNode)

num_knots = myMopath.xyzNurbsCurve
num_knots.setCvPoint(3, (0, 0, 1))
num_knots.recompute()

lin = myMopath.draw()
lin.reparentTo(render)

myCube = loader.loadModel("yup-axis")
myCube.setScale(0.1)
myCube.reparentTo(render)

myInterval = MopathInterval(myMopath, myCube, duration=10 ,name = "Name")
myInterval.start()

base.run()

#7

Funnily enough, I was just working on a very similar solution (although I had no idea recompute was a thing and that solved a problem I was having getting it to reflect the changes - so thanks for that)

Here’s a very hacky example that seems to work:

translate = LVecBase3f(30, 30, 0)
    
i = path.xyzNurbsCurve.getNumCvs() - 1
    
while i >= 0:
    point = path.xyzNurbsCurve.getCvPoint(i)
        
    point.x += translate.x
    point.y += translate.y
    point.z += translate.z
    
    path.xyzNurbsCurve.setCvPoint(i, point.x, point.y, point.z)
        
    i -= 1
    
path.xyzNurbsCurve.recompute()

I still wonder if there’s a better way to do it. (I also worry that I’ll eventually find some reason why even this solution doesn’t work properly.)


#8

It seems that the class Mopath does not provide anything like that. So you can safely expand it.