support blending animations
This commit is contained in:
parent
824df2dd87
commit
013c3cbc96
|
|
@ -1031,7 +1031,79 @@ class Actor(PandaObject, NodePath):
|
|||
thisLod)
|
||||
if (animControl != None):
|
||||
animControl.pose(frame)
|
||||
|
||||
|
||||
def enableBlend(self, partName = None):
|
||||
"""Enables blending of multiple animations simultaneously.
|
||||
After this is called, you may call play(), loop(), or pose()
|
||||
on multiple animations and have all of them contribute to the
|
||||
final pose each frame.
|
||||
|
||||
With blending in effect, starting a particular animation with
|
||||
play(), loop(), or pose() does not implicitly make the
|
||||
animation visible; you must also call setControlEffect() for
|
||||
each animation you wish to use to indicate how much each
|
||||
animation contributes to the final pose.
|
||||
"""
|
||||
for lodName, bundleDict in self.__partBundleDict.items():
|
||||
if partName == None:
|
||||
for partBundle in bundleDict.values():
|
||||
partBundle.node().getBundle().setBlendType(PartBundle.BTNormalizedLinear)
|
||||
else:
|
||||
partBundle = bundleDict.get(partName)
|
||||
if partBundle != None:
|
||||
partBundle.node().getBundle().setBlendType(PartBundle.BTNormalizedLinear)
|
||||
else:
|
||||
Actor.notify.warning("Couldn't find part: %s" % (partName))
|
||||
|
||||
def disableBlend(self, partName = None):
|
||||
""" Restores normal one-animation-at-a-time operation after a
|
||||
previous call to enableBlend().
|
||||
"""
|
||||
for lodName, bundleDict in self.__partBundleDict.items():
|
||||
if partName == None:
|
||||
for partBundle in bundleDict.values():
|
||||
partBundle.node().getBundle().setBlendType(PartBundle.BTSingle)
|
||||
else:
|
||||
partBundle = bundleDict.get(partName)
|
||||
if partBundle != None:
|
||||
partBundle.node().getBundle().setBlendType(PartBundle.BTSingle)
|
||||
else:
|
||||
Actor.notify.warning("Couldn't find part: %s" % (partName))
|
||||
|
||||
def setControlEffect(self, animName, effect,
|
||||
partName = None, lodName = None):
|
||||
""" Sets the amount by which the named animation contributes to
|
||||
the overall pose. This controls blending of multiple
|
||||
animations; it only makes sense to call this after a previous
|
||||
call to enableBlend().
|
||||
"""
|
||||
if lodName == None:
|
||||
for lodName, controlDict in self.__animControlDict.items():
|
||||
if partName == None:
|
||||
for part in controlDict.keys():
|
||||
ac = self.getAnimControl(animName, part, lodName)
|
||||
if ac != None:
|
||||
ac.getPart().setControlEffect(ac, effect)
|
||||
else:
|
||||
ac = self.getAnimControl(animName, partName, lodName)
|
||||
if ac != None:
|
||||
ac.getPart().setControlEffect(ac, effect)
|
||||
else:
|
||||
if partName == None:
|
||||
controlDict = self.__animControlDict.get(lodName)
|
||||
if controlDict != None:
|
||||
for part in controlDict.keys():
|
||||
ac = self.getAnimControl(animName, part, lodName)
|
||||
if ac != None:
|
||||
ac.getPart().setControlEffect(ac, effect)
|
||||
else:
|
||||
Actor.notify.warning("couldn't find lod: %s" % (lodName))
|
||||
else:
|
||||
ac = self.getAnimControl(animName, partName, lodName)
|
||||
if ac != None:
|
||||
ac.getPart().setControlEffect(ac, effect)
|
||||
|
||||
|
||||
def getAnimControl(self, animName, partName, lodName="lodRoot"):
|
||||
"""getAnimControl(self, string, string, string="lodRoot")
|
||||
Search the animControl dictionary indicated by lodName for
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
from PandaModules import *
|
||||
import Interval
|
||||
import math
|
||||
import LerpBlendHelpers
|
||||
|
||||
class ActorInterval(Interval.Interval):
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ class ActorInterval(Interval.Interval):
|
|||
# will play once and then nothing will happen for the remainder of the
|
||||
# interval
|
||||
def __init__(self, actor, animName, loop=0, duration=0.0,
|
||||
startTime=0.0, endTime=None, name=None):
|
||||
startTime=0.0, endTime=None, playRate=1.0, name=None):
|
||||
"""__init__(name)
|
||||
"""
|
||||
# Generate unique id
|
||||
|
|
@ -32,7 +33,7 @@ class ActorInterval(Interval.Interval):
|
|||
self.actor = actor
|
||||
self.animName = animName
|
||||
self.loopAnim = loop
|
||||
self.frameRate = self.actor.getFrameRate(self.animName)
|
||||
self.frameRate = self.actor.getFrameRate(self.animName) * playRate
|
||||
self.numFrames = self.actor.getNumFrames(self.animName)
|
||||
# Compute start time
|
||||
self.startTime = startTime
|
||||
|
|
@ -100,7 +101,7 @@ class ActorInterval(Interval.Interval):
|
|||
# Update animation based upon current time
|
||||
# Pose or stop anim
|
||||
if (t >= self.getDuration()):
|
||||
self.actor.stop()
|
||||
self.actor.stop(self.animName)
|
||||
frame = self.goToT(self.getDuration())
|
||||
if self.loopAnim:
|
||||
self.ignore(self.stopEvent)
|
||||
|
|
@ -123,3 +124,68 @@ class ActorInterval(Interval.Interval):
|
|||
# Pose anim
|
||||
self.goToT(t)
|
||||
|
||||
|
||||
class LerpAnimInterval(Interval.Interval):
|
||||
# Blends between two anims. Start both anims first (or use
|
||||
# parallel ActorIntervals), then invoke LerpAnimInterval to
|
||||
# smoothly blend the control effect from the first to the second.
|
||||
lerpAnimNum = 1
|
||||
|
||||
def __init__(self, actor, duration, startAnim, endAnim,
|
||||
startWeight = 0.0, endWeight = 1.0,
|
||||
blendType = 'noBlend', name = None):
|
||||
""" __init__(actor, duration, pos, startPos, other, blendType, name)
|
||||
"""
|
||||
# Generate unique name if necessary
|
||||
if (name == None):
|
||||
name = 'LerpAnimInterval-%d' % LerpAnimInterval.lerpAnimNum
|
||||
LerpAnimInterval.lerpAnimNum += 1
|
||||
|
||||
# Record class specific variables
|
||||
self.actor = actor
|
||||
self.startAnim = startAnim
|
||||
self.endAnim = endAnim
|
||||
self.startWeight = startWeight
|
||||
self.deltaWeight = endWeight - startWeight
|
||||
self.blendType = self.getBlend(blendType)
|
||||
|
||||
# Initialize superclass
|
||||
Interval.Interval.__init__(self, name, duration)
|
||||
|
||||
|
||||
def updateFunc(self, t, event=Interval.IVAL_NONE):
|
||||
""" updateFunc(t, event)
|
||||
Go to time t
|
||||
"""
|
||||
if (self.actor.isEmpty()):
|
||||
self.notify.warning('updateFunc() - %s empty actor!' % self.name)
|
||||
return
|
||||
|
||||
# First, normalize t into the range 0 .. 1, and apply the blendType.
|
||||
t = self.blendType(float(t) / self.getDuration())
|
||||
|
||||
# Then compute the current weight based on the time elapsed so far.
|
||||
w = self.startWeight + t * self.deltaWeight
|
||||
|
||||
print "t = %f, w = %f" % (t, w)
|
||||
|
||||
# Apply that weight to the two anims.
|
||||
self.actor.setControlEffect(self.endAnim, w)
|
||||
self.actor.setControlEffect(self.startAnim, 1.0 - w)
|
||||
|
||||
|
||||
def getBlend(self, blendType):
|
||||
"""__getBlend(self, string)
|
||||
Return the C++ blend class corresponding to blendType string
|
||||
"""
|
||||
if (blendType == "easeIn"):
|
||||
return LerpBlendHelpers.easeIn
|
||||
elif (blendType == "easeOut"):
|
||||
return LerpBlendHelpers.easeOut
|
||||
elif (blendType == "easeInOut"):
|
||||
return LerpBlendHelpers.easeInOut
|
||||
elif (blendType == "noBlend"):
|
||||
return LerpBlendHelpers.noBlend
|
||||
else:
|
||||
raise Exception(
|
||||
'Error: LerpAnimInterval.getBlend: Unknown blend type')
|
||||
|
|
|
|||
Loading…
Reference in New Issue