0
# Animation and Characters
1
2
Panda3D provides comprehensive animation capabilities including character animation, procedural animation, and smooth interpolation systems for creating dynamic 3D content.
3
4
## Capabilities
5
6
### Actor - Animated Character System
7
8
The Actor class handles animated 3D characters with skeletal animation, multiple animation sets, and advanced playback control.
9
10
```python { .api }
11
class Actor:
12
def __init__(self,
13
model: str = None,
14
anims: dict = None,
15
copy: bool = True,
16
flattenable: bool = True,
17
setFinal: bool = False) -> None:
18
"""
19
Create animated character.
20
21
Args:
22
model: Path to character model file
23
anims: Dictionary mapping animation names to file paths
24
copy: Whether to copy geometry (True) or instance it (False)
25
flattenable: Whether model can be flattened for optimization
26
setFinal: Whether to finalize model structure
27
"""
28
29
def loadModel(self, modelPath: str) -> None:
30
"""Load character model from file."""
31
32
def loadAnims(self, anims: dict) -> None:
33
"""Load animation files. Dict maps names to file paths."""
34
35
def bindAnim(self, animName: str, animPath: str, partName: str = None) -> None:
36
"""Bind single animation to character or part."""
37
38
def unloadAnims(self, animNames: list = None, partNames: list = None) -> None:
39
"""Unload specified animations."""
40
41
def getAnimNames(self, partName: str = None) -> list:
42
"""Get list of loaded animation names."""
43
44
def hasAnim(self, animName: str) -> bool:
45
"""Check if animation is loaded."""
46
```
47
48
### Animation Playback Control
49
50
Control animation playback with various modes, blending, and timing options.
51
52
```python { .api }
53
class Actor:
54
def play(self, animName: str, partName: str = None, fromFrame: int = None, toFrame: int = None) -> None:
55
"""Play animation once from start to end."""
56
57
def loop(self, animName: str, partName: str = None, fromFrame: int = None, toFrame: int = None) -> None:
58
"""Loop animation continuously."""
59
60
def pingpong(self, animName: str, partName: str = None, fromFrame: int = None, toFrame: int = None) -> None:
61
"""Play animation back and forth."""
62
63
def stop(self, partName: str = None) -> None:
64
"""Stop animation playback."""
65
66
def pause(self, partName: str = None) -> None:
67
"""Pause animation at current frame."""
68
69
def resume(self, partName: str = None) -> None:
70
"""Resume paused animation."""
71
72
def pose(self, animName: str, frame: int, partName: str = None) -> None:
73
"""Set character to specific animation frame."""
74
75
def isPlaying(self, animName: str = None, partName: str = None) -> bool:
76
"""Check if animation is currently playing."""
77
78
def getCurrentAnim(self, partName: str = None) -> str:
79
"""Get name of currently playing animation."""
80
81
def getCurrentFrame(self, partName: str = None) -> int:
82
"""Get current animation frame number."""
83
84
def getNumFrames(self, animName: str = None, partName: str = None) -> int:
85
"""Get total frames in animation."""
86
87
def getDuration(self, animName: str = None, partName: str = None) -> float:
88
"""Get animation duration in seconds."""
89
90
def getFrameRate(self, animName: str = None, partName: str = None) -> float:
91
"""Get animation frame rate."""
92
93
def setPlayRate(self, rate: float, animName: str = None, partName: str = None) -> None:
94
"""Set animation playback speed multiplier."""
95
96
def getPlayRate(self, animName: str = None, partName: str = None) -> float:
97
"""Get current playback rate."""
98
```
99
100
### Animation Blending and Transitions
101
102
Advanced animation features for smooth transitions and blending between animations.
103
104
```python { .api }
105
class Actor:
106
def enableBlend(self, blendType: int = 0, partName: str = None) -> None:
107
"""Enable animation blending."""
108
109
def disableBlend(self, partName: str = None) -> None:
110
"""Disable animation blending."""
111
112
def setBlend(self,
113
animBlend: bool = True,
114
frameBlend: bool = True,
115
blendType: int = 0,
116
partName: str = None) -> None:
117
"""Configure blending options."""
118
119
def setControlEffect(self, animName: str, effect: float, partName: str = None) -> None:
120
"""Set animation influence/weight (0.0-1.0)."""
121
122
def getControlEffect(self, animName: str, partName: str = None) -> float:
123
"""Get animation influence/weight."""
124
```
125
126
### Multi-Part Characters
127
128
Support for characters with multiple independently animated parts.
129
130
```python { .api }
131
class Actor:
132
def makeSubpart(self, partName: str, includeJoints: list, excludeJoints: list = []) -> None:
133
"""Create animation subpart from specified joints."""
134
135
def getPartNames(self) -> list:
136
"""Get list of all part names."""
137
138
def removePart(self, partName: str) -> None:
139
"""Remove animation part."""
140
141
def hidePart(self, partName: str) -> None:
142
"""Hide part geometry."""
143
144
def showPart(self, partName: str) -> None:
145
"""Show part geometry."""
146
147
def showAllParts(self) -> None:
148
"""Show all parts."""
149
```
150
151
### Procedural Animation with Intervals
152
153
The interval system provides procedural animation through interpolation of object properties over time.
154
155
```python { .api }
156
class LerpPosInterval:
157
def __init__(self, nodePath: NodePath,
158
duration: float,
159
pos: Vec3,
160
startPos: Vec3 = None,
161
blendType: str = 'noBlend') -> None:
162
"""Animate object position over time."""
163
164
class LerpHprInterval:
165
def __init__(self, nodePath: NodePath,
166
duration: float,
167
hpr: Vec3,
168
startHpr: Vec3 = None,
169
blendType: str = 'noBlend') -> None:
170
"""Animate object rotation over time."""
171
172
class LerpScaleInterval:
173
def __init__(self, nodePath: NodePath,
174
duration: float,
175
scale: Vec3,
176
startScale: Vec3 = None,
177
blendType: str = 'noBlend') -> None:
178
"""Animate object scale over time."""
179
180
class LerpColorInterval:
181
def __init__(self, nodePath: NodePath,
182
duration: float,
183
color: Vec4,
184
startColor: Vec4 = None,
185
blendType: str = 'noBlend') -> None:
186
"""Animate object color over time."""
187
188
class LerpColorScaleInterval:
189
def __init__(self, nodePath: NodePath,
190
duration: float,
191
colorScale: Vec4,
192
startColorScale: Vec4 = None,
193
blendType: str = 'noBlend') -> None:
194
"""Animate color scale over time."""
195
```
196
197
### Composite Animation Sequences
198
199
Create complex animations by combining multiple intervals in sequences and parallel groups.
200
201
```python { .api }
202
class Sequence:
203
def __init__(self, *intervals) -> None:
204
"""Create sequence of intervals that play one after another."""
205
206
def start(self) -> None:
207
"""Start the sequence."""
208
209
def finish(self) -> None:
210
"""Jump to end of sequence."""
211
212
def pause(self) -> None:
213
"""Pause sequence playback."""
214
215
def resume(self) -> None:
216
"""Resume paused sequence."""
217
218
def loop(self) -> None:
219
"""Loop sequence continuously."""
220
221
def isPlaying(self) -> bool:
222
"""Check if sequence is playing."""
223
224
def getDuration(self) -> float:
225
"""Get total sequence duration."""
226
227
class Parallel:
228
def __init__(self, *intervals) -> None:
229
"""Create group of intervals that play simultaneously."""
230
231
def start(self) -> None: ...
232
def finish(self) -> None: ...
233
def pause(self) -> None: ...
234
def resume(self) -> None: ...
235
def loop(self) -> None: ...
236
def isPlaying(self) -> bool: ...
237
def getDuration(self) -> float: ...
238
239
def Wait(duration: float) -> WaitInterval:
240
"""Create pause/delay interval."""
241
242
def Func(function: callable, *args) -> FunctionInterval:
243
"""Create interval that calls function."""
244
```
245
246
### Animation Easing and Blending
247
248
Control animation curves and transitions for more natural motion.
249
250
```python { .api }
251
# Easing functions for smooth animation curves
252
def easeIn(t: float) -> float:
253
"""Ease-in curve (slow start)."""
254
255
def easeOut(t: float) -> float:
256
"""Ease-out curve (slow end)."""
257
258
def easeInOut(t: float) -> float:
259
"""Ease-in-out curve (slow start and end)."""
260
261
# Blend types for intervals
262
BLEND_EASE_IN = "easeIn"
263
BLEND_EASE_OUT = "easeOut"
264
BLEND_EASE_IN_OUT = "easeInOut"
265
BLEND_NO_BLEND = "noBlend"
266
```
267
268
## Usage Examples
269
270
### Basic Character Animation
271
272
```python
273
from direct.showbase.ShowBase import ShowBase
274
from direct.actor.Actor import Actor
275
from panda3d.core import Vec3
276
277
class CharacterDemo(ShowBase):
278
def __init__(self):
279
ShowBase.__init__(self)
280
281
# Load animated character
282
self.character = Actor(
283
"models/characters/panda",
284
{
285
"walk": "models/characters/panda-walk",
286
"run": "models/characters/panda-run",
287
"idle": "models/characters/panda-idle"
288
}
289
)
290
291
self.character.reparentTo(self.render)
292
self.character.setScale(0.5)
293
self.character.setPos(0, 10, 0)
294
295
# Start with idle animation
296
self.character.loop("idle")
297
298
# Setup input
299
self.accept("1", self.playIdle)
300
self.accept("2", self.playWalk)
301
self.accept("3", self.playRun)
302
303
def playIdle(self):
304
"""Switch to idle animation."""
305
self.character.loop("idle")
306
307
def playWalk(self):
308
"""Switch to walking animation."""
309
self.character.loop("walk")
310
311
def playRun(self):
312
"""Switch to running animation."""
313
self.character.loop("run")
314
315
app = CharacterDemo()
316
app.run()
317
```
318
319
### Procedural Animation with Intervals
320
321
```python
322
from direct.showbase.ShowBase import ShowBase
323
from direct.interval.IntervalGlobal import *
324
from panda3d.core import Vec3
325
326
class AnimationDemo(ShowBase):
327
def __init__(self):
328
ShowBase.__init__(self)
329
330
# Create object to animate
331
self.cube = self.loader.loadModel("models/cube")
332
self.cube.reparentTo(self.render)
333
self.cube.setPos(-5, 10, 0)
334
335
# Create complex animation sequence
336
self.createAnimation()
337
338
# Start animation
339
self.accept("space", self.startAnimation)
340
341
def createAnimation(self):
342
"""Create complex animation sequence."""
343
# Move right while growing
344
move_right = LerpPosInterval(
345
self.cube, 2.0, Vec3(5, 10, 0), blendType='easeInOut'
346
)
347
grow = LerpScaleInterval(
348
self.cube, 2.0, Vec3(2, 2, 2), blendType='easeInOut'
349
)
350
351
# Parallel movement and scaling
352
phase1 = Parallel(move_right, grow)
353
354
# Rotate and change color
355
rotate = LerpHprInterval(
356
self.cube, 1.5, Vec3(360, 0, 0)
357
)
358
color_change = LerpColorInterval(
359
self.cube, 1.5, (1, 0, 0, 1) # Red
360
)
361
362
phase2 = Parallel(rotate, color_change)
363
364
# Move up with pause
365
pause = Wait(0.5)
366
move_up = LerpPosInterval(
367
self.cube, 1.0, Vec3(5, 10, 3), blendType='easeOut'
368
)
369
370
# Final callback
371
finish_func = Func(self.onAnimationComplete)
372
373
# Combine into sequence
374
self.animation = Sequence(
375
phase1,
376
phase2,
377
pause,
378
move_up,
379
finish_func
380
)
381
382
def startAnimation(self):
383
"""Start the animation sequence."""
384
# Reset object state
385
self.cube.setPos(-5, 10, 0)
386
self.cube.setScale(1, 1, 1)
387
self.cube.setHpr(0, 0, 0)
388
self.cube.clearColor()
389
390
# Start animation
391
self.animation.start()
392
393
def onAnimationComplete(self):
394
"""Called when animation finishes."""
395
print("Animation completed!")
396
397
# Loop the animation
398
self.startAnimation()
399
400
app = AnimationDemo()
401
app.run()
402
```
403
404
### Multi-Part Character Animation
405
406
```python
407
from direct.showbase.ShowBase import ShowBase
408
from direct.actor.Actor import Actor
409
410
class MultiPartDemo(ShowBase):
411
def __init__(self):
412
ShowBase.__init__(self)
413
414
# Load character with multiple parts
415
self.character = Actor("models/characters/robot")
416
self.character.loadAnims({
417
"torso_idle": "models/anims/robot-torso-idle",
418
"torso_wave": "models/anims/robot-torso-wave",
419
"legs_walk": "models/anims/robot-legs-walk",
420
"legs_run": "models/anims/robot-legs-run"
421
})
422
423
self.character.reparentTo(self.render)
424
425
# Create animation parts
426
self.character.makeSubpart(
427
"torso",
428
["torso", "left_arm", "right_arm", "head"]
429
)
430
self.character.makeSubpart(
431
"legs",
432
["left_leg", "right_leg", "pelvis"]
433
)
434
435
# Start different animations on different parts
436
self.character.loop("torso_idle", partName="torso")
437
self.character.loop("legs_walk", partName="legs")
438
439
# Setup controls
440
self.accept("w", self.wave)
441
self.accept("r", self.run)
442
self.accept("s", self.stop)
443
444
def wave(self):
445
"""Play wave animation on torso."""
446
self.character.play("torso_wave", partName="torso")
447
448
# Return to idle after wave completes
449
duration = self.character.getDuration("torso_wave", "torso")
450
self.taskMgr.doMethodLater(
451
duration, self.returnToIdle, "return-idle"
452
)
453
454
def returnToIdle(self, task):
455
"""Return torso to idle animation."""
456
self.character.loop("torso_idle", partName="torso")
457
return task.done
458
459
def run(self):
460
"""Switch legs to running."""
461
self.character.loop("legs_run", partName="legs")
462
463
def stop(self):
464
"""Switch legs to walking."""
465
self.character.loop("legs_walk", partName="legs")
466
467
app = MultiPartDemo()
468
app.run()
469
```
470
471
## Types
472
473
```python { .api }
474
class AnimControl:
475
"""Animation control object for fine-tuned animation management."""
476
def play(self) -> None: ...
477
def stop(self) -> None: ...
478
def pose(self, frame: int) -> None: ...
479
480
class PartBundle:
481
"""Animation part bundle for multi-part characters."""
482
def getName(self) -> str: ...
483
def update(self) -> None: ...
484
485
# Animation blend types
486
BT_NO_BLEND = 0 # No blending
487
BT_NORMAL_BLEND = 1 # Normal animation blending
488
BT_ADDITIVE_BLEND = 2 # Additive blending
489
490
# Interval blend type constants
491
from direct.interval.IntervalGlobal import *
492
# Available blend types: 'noBlend', 'easeIn', 'easeOut', 'easeInOut'
493
```