morphing between meshes

Hi,

Is there a straightforward way of morphing between two meshes? So essentially controlling a morph target. I found that it supports blending animations but I could not find any information about controlling morph targets.

thanks.

Yes, a morph target is treated as a joint for this purpose. You can manipulate a morph target in the same way you manipulate joints (see the “Eve” demo program that ships with Panda). When you expose a morph target, the X position of the resulting node controls the amount of the morph; X of 0.0 means not to apply any morph, while X of 1.0 means to apply the full target.

One caveat: it is necessary to convert your model as a character, with at least one joint (even if you are only using morph targets), and then to have an animation looping on that one joint (even if it is the same frame looping over and over again). The animation code requires that an animation is playing on the joints before it will consider the morph targets.

David

Hi,
I’m trying to get morph targets to work w/the ripple.egg model that comes w/panda. I’ve been trying to follow the information I found in the following posts:

https://discourse.panda3d.org/viewtopic.phpt=675&highlight=animation+blend

https://discourse.panda3d.org/viewtopic.phpt=1572&highlight=blend+shape

https://discourse.panda3d.org/viewtopic.phpt=1419&highlight=morph+targets

https://discourse.panda3d.org/viewtopic.phpt=1419&highlight=animation+blend

But I don’t seem to be making headway. Attached is my code, any advice would be appreciated. (Or maybe upgrading my Actor.py to the cvs version will fix this?)

##Output of egg-optchar ripple.egg -ls
#I assume each of these numbers is a blend target?
#Character: ripple
#RootJoint
#2
#5
#6
#7
#3
#4
#1
#1 joints.

base.disableMouse()     
camera.setPos(0,-15,0)              #Position the camera


ripple = Actor("ripple.egg")
 

ripple.reparentTo(render)          #Put it in the scene


rippleBlendShape1 = ripple.controlJoint(None, 'modelRoot', '1')
rippleBlendShape2 = ripple.controlJoint(None, 'modelRoot', '2')
rippleBlendShape3 = ripple.controlJoint(None, 'modelRoot', '3')
rippleBlendShape4 = ripple.controlJoint(None, 'modelRoot', '4')
rippleBlendShape5 = ripple.controlJoint(None, 'modelRoot', '5')
rippleBlendShape6 = ripple.controlJoint(None, 'modelRoot', '6')
rippleBlendShape7 = ripple.controlJoint(None, 'modelRoot', '7')


def doBlend(amount,shape):
    shape.setX(amount)

def startBlendShape(shape,shapeName):
    morphInterval= LerpFunc(doBlend,
                               fromData=0,
                               toData=1,
                               duration = 2.0,
                               blendType = 'noBlend',
                               extraArgs = [shape], name = shapeName)
    morphInterval.loop()

startBlendShape(rippleBlendShape1,'blend1')
startBlendShape(rippleBlendShape2,'blend2')
startBlendShape(rippleBlendShape3,'blend3')
startBlendShape(rippleBlendShape4,'blend4')
startBlendShape(rippleBlendShape5,'blend5')
startBlendShape(rippleBlendShape6,'blend6')
startBlendShape(rippleBlendShape7,'blend7')

run()

The key thing that you are missing is that in order for controlJoint() to work, you have to have an animation looping on the Actor–even if you have controlJointed away every single joint and slider in the animation.

Here’s an updated version of your example. I tilted the camera a bit to a better angle for viewing the ripple, which is hard to see what it’s doing unless you’ve viewing it edge-on. Also, I made each of your morph intervals a different duration, so they don’t run in lockstep sync with each other, since these particular blend targets are designed to run out of sync with each other to achieve a sinusoidal effect. And I made the intervals blend up-and-back, to avoid the popping at the end of the range on these particular blend targets.

base.disableMouse()     

#camera.setPos(0,-15,0)              #Position the camera
camera.setPos(0, -0.6, -2)
camera.setHpr(0, 73, 0)


ripple = Actor("ripple.egg", {'anim' : 'ripple.egg'})
 

ripple.reparentTo(render)          #Put it in the scene


rippleBlendShape1 = ripple.controlJoint(None, 'modelRoot', '1')
rippleBlendShape2 = ripple.controlJoint(None, 'modelRoot', '2')
rippleBlendShape3 = ripple.controlJoint(None, 'modelRoot', '3')
rippleBlendShape4 = ripple.controlJoint(None, 'modelRoot', '4')
rippleBlendShape5 = ripple.controlJoint(None, 'modelRoot', '5')
rippleBlendShape6 = ripple.controlJoint(None, 'modelRoot', '6')
rippleBlendShape7 = ripple.controlJoint(None, 'modelRoot', '7')

ripple.loop('anim')

def doBlend(amount,shape):
    shape.setX(amount)

def startBlendShape(shape,shapeName, duration):
    morphInterval= Sequence(
        LerpFunc(doBlend,
                 fromData=0,
                 toData=1,
                 duration = duration,
                 blendType = 'noBlend',
                 extraArgs = [shape]),
        LerpFunc(doBlend,
                 fromData=1,
                 toData=0,
                 duration = duration,
                 blendType = 'noBlend',
                 extraArgs = [shape]),
        name = shapeName)
    morphInterval.loop()

startBlendShape(rippleBlendShape1,'blend1', 1)
startBlendShape(rippleBlendShape2,'blend2', 1.1)
startBlendShape(rippleBlendShape3,'blend3', 1.2)
startBlendShape(rippleBlendShape4,'blend4', 1.3)
startBlendShape(rippleBlendShape5,'blend5', 1.4)
startBlendShape(rippleBlendShape6,'blend6', 1.5)
startBlendShape(rippleBlendShape7,'blend7', 1.6)

run() 

David

This works perfectly! Thanks so much