or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animation.mdapplication-framework.mdasset-loading.mdaudio.mdindex.mdinput.mdmathematics.mdscene-graph.mdtask-event.mduser-interface.md

asset-loading.mddocs/

0

# Asset Loading

1

2

Panda3D provides a comprehensive asset loading system that handles 3D models, textures, animations, audio files, and other resources with support for various file formats and flexible loading strategies.

3

4

## Capabilities

5

6

### Loader - Main Asset Loading Interface

7

8

The Loader class provides the primary interface for loading game assets with caching, format conversion, and error handling.

9

10

```python { .api }

11

class Loader:

12

def loadModel(self,

13

modelPath: str,

14

noCache: bool = False,

15

allowInstanceFromCache: bool = False,

16

callback: callable = None,

17

extraArgs: list = []) -> NodePath:

18

"""

19

Load 3D model from file.

20

21

Args:

22

modelPath: Path to model file

23

noCache: Skip caching system

24

allowInstanceFromCache: Allow instancing from cache

25

callback: Async loading callback

26

extraArgs: Extra arguments for callback

27

28

Returns:

29

NodePath containing loaded model

30

"""

31

32

def loadModelOnce(self, modelPath: str) -> NodePath:

33

"""Load model with guaranteed caching."""

34

35

def loadModelCopy(self, modelPath: str) -> NodePath:

36

"""Load unique copy of model (no instancing)."""

37

38

def unloadModel(self, model: NodePath) -> None:

39

"""Unload model and free resources."""

40

41

def loadTexture(self,

42

texturePath: str,

43

alphaPath: str = None,

44

readMipmaps: bool = False,

45

okMissing: bool = False,

46

minfilter: int = None,

47

magfilter: int = None) -> Texture:

48

"""

49

Load texture from file.

50

51

Args:

52

texturePath: Path to texture file

53

alphaPath: Optional separate alpha channel file

54

readMipmaps: Read mipmaps if available

55

okMissing: Don't error if file missing

56

minfilter: Minification filter mode

57

magfilter: Magnification filter mode

58

59

Returns:

60

Texture object

61

"""

62

63

def loadCubeMap(self, texturePath: str) -> Texture:

64

"""Load cube map texture for environment mapping."""

65

66

def load3DTexture(self, texturePath: str) -> Texture:

67

"""Load 3D volume texture."""

68

69

def loadFont(self, fontPath: str) -> TextFont:

70

"""Load font for text rendering."""

71

72

def loadSfx(self, soundPath: str) -> AudioSound:

73

"""Load sound effect file."""

74

75

def loadMusic(self, musicPath: str) -> AudioSound:

76

"""Load music file."""

77

78

def loadShader(self,

79

vertexPath: str = None,

80

fragmentPath: str = None,

81

geometryPath: str = None) -> Shader:

82

"""Load shader program from source files."""

83

```

84

85

### Supported File Formats

86

87

Panda3D supports a wide variety of asset file formats through built-in and plugin loaders.

88

89

```python { .api }

90

# 3D Model Formats

91

MODEL_FORMATS = [

92

".egg", # Panda3D native format

93

".bam", # Panda3D binary format (fastest loading)

94

".x", # DirectX format

95

".dae", # COLLADA format

96

".obj", # Wavefront OBJ

97

".ply", # Stanford PLY

98

".lwo", # LightWave Object

99

".3ds", # 3D Studio format

100

".gltf", # glTF 2.0 (if plugin available)

101

".fbx" # FBX (if plugin available)

102

]

103

104

# Texture Formats

105

TEXTURE_FORMATS = [

106

".png", # PNG (recommended)

107

".jpg", ".jpeg", # JPEG

108

".tga", # Targa

109

".bmp", # Bitmap

110

".pnm", # Portable Network Graphics

111

".sgi", # Silicon Graphics Image

112

".rgb", # RGB format

113

".tiff", ".tif", # TIFF

114

".exr", # OpenEXR (HDR)

115

".hdr", # Radiance HDR

116

".dds" # DirectDraw Surface

117

]

118

119

# Audio Formats

120

AUDIO_FORMATS = [

121

".wav", # WAV (uncompressed)

122

".ogg", # Ogg Vorbis

123

".mp3", # MP3 (if available)

124

".flac" # FLAC (if available)

125

]

126

127

# Animation Formats

128

ANIMATION_FORMATS = [

129

".egg", # Panda3D animation

130

".bam", # Panda3D binary animation

131

]

132

```

133

134

### Asset Path Resolution

135

136

Configure and manage asset loading paths and search directories.

137

138

```python { .api }

139

from panda3d.core import getModelPath, Filename, DSearchPath

140

141

# Get current model search path

142

def getAssetPath() -> DSearchPath:

143

"""Get current asset search path."""

144

return getModelPath()

145

146

# Add search directories

147

def addAssetPath(path: str) -> None:

148

"""Add directory to asset search path."""

149

getModelPath().appendDirectory(Filename(path))

150

151

def prependAssetPath(path: str) -> None:

152

"""Add directory to front of search path."""

153

getModelPath().prependDirectory(Filename(path))

154

155

# Search for assets

156

def findAsset(filename: str) -> str:

157

"""Find asset file in search path."""

158

path = getModelPath().findFile(filename)

159

return str(path) if path else None

160

```

161

162

### Asynchronous Loading

163

164

Load assets asynchronously to avoid blocking the main thread.

165

166

```python { .api }

167

class Loader:

168

def loadModelAsync(self,

169

modelPath: str,

170

callback: callable,

171

extraArgs: list = []) -> None:

172

"""Load model asynchronously with callback."""

173

174

def loadTextureAsync(self,

175

texturePath: str,

176

callback: callable,

177

extraArgs: list = []) -> None:

178

"""Load texture asynchronously with callback."""

179

180

def cancelAsyncRequest(self, request) -> None:

181

"""Cancel pending async loading request."""

182

```

183

184

### Resource Management and Caching

185

186

Manage loaded assets and control caching behavior.

187

188

```python { .api }

189

class Loader:

190

def flushCache(self) -> None:

191

"""Clear all cached assets."""

192

193

def clearCache(self, filename: str) -> None:

194

"""Clear specific file from cache."""

195

196

def setCacheLimit(self, limit: int) -> None:

197

"""Set maximum cache size in bytes."""

198

199

def getCacheSize(self) -> int:

200

"""Get current cache size in bytes."""

201

202

def listCachedFiles(self) -> list:

203

"""List all files currently in cache."""

204

```

205

206

### Virtual File System Integration

207

208

Load assets from virtual file systems, compressed archives, and network sources.

209

210

```python { .api }

211

from panda3d.core import VirtualFileSystem, Multifile

212

213

# Virtual file system access

214

vfs = VirtualFileSystem.getGlobalPtr()

215

216

# Mount archive files

217

def mountArchive(archive_path: str, mount_point: str = "/") -> bool:

218

"""Mount archive file as virtual directory."""

219

multifile = Multifile()

220

if multifile.openReadWrite(archive_path):

221

vfs.mount(multifile, mount_point, 0)

222

return True

223

return False

224

225

# Load from VFS

226

def loadFromVFS(vfs_path: str) -> NodePath:

227

"""Load model from virtual file system path."""

228

return loader.loadModel(vfs_path)

229

```

230

231

## Usage Examples

232

233

### Basic Asset Loading

234

235

```python

236

from direct.showbase.ShowBase import ShowBase

237

from panda3d.core import *

238

239

class AssetDemo(ShowBase):

240

def __init__(self):

241

ShowBase.__init__(self)

242

243

# Configure asset paths

244

self.setupAssetPaths()

245

246

# Load various assets

247

self.loadGameAssets()

248

249

# Setup scene

250

self.setupScene()

251

252

def setupAssetPaths(self):

253

"""Configure asset search paths."""

254

# Add custom asset directories

255

getModelPath().appendDirectory("assets/models")

256

getModelPath().appendDirectory("assets/textures")

257

getModelPath().appendDirectory("assets/sounds")

258

259

# Add archive files

260

multifile = Multifile()

261

if multifile.openRead("game_assets.mf"):

262

vfs = VirtualFileSystem.getGlobalPtr()

263

vfs.mount(multifile, "/game", 0)

264

print("Mounted game_assets.mf")

265

266

def loadGameAssets(self):

267

"""Load all game assets."""

268

# Load 3D models

269

self.environment = self.loader.loadModel("environment.egg")

270

self.player_model = self.loader.loadModel("characters/player.egg")

271

self.enemy_model = self.loader.loadModel("characters/enemy.egg")

272

273

# Load textures

274

self.grass_texture = self.loader.loadTexture("grass.png")

275

self.stone_texture = self.loader.loadTexture("stone.jpg")

276

self.metal_texture = self.loader.loadTexture("metal.tga")

277

278

# Load sounds

279

self.footstep_sound = self.loader.loadSfx("footstep.wav")

280

self.background_music = self.loader.loadMusic("background.ogg")

281

282

# Load fonts

283

self.ui_font = self.loader.loadFont("fonts/arial.ttf")

284

285

print("All assets loaded successfully")

286

287

def setupScene(self):

288

"""Setup the 3D scene with loaded assets."""

289

# Setup environment

290

if self.environment:

291

self.environment.reparentTo(self.render)

292

self.environment.setTexture(self.grass_texture)

293

294

# Setup player

295

if self.player_model:

296

self.player_model.reparentTo(self.render)

297

self.player_model.setPos(0, 10, 0)

298

299

# Setup camera

300

self.camera.setPos(0, -10, 5)

301

self.camera.lookAt(self.player_model)

302

303

app = AssetDemo()

304

app.run()

305

```

306

307

### Asynchronous Asset Loading

308

309

```python

310

from direct.showbase.ShowBase import ShowBase

311

from direct.gui.DirectGui import *

312

313

class AsyncLoadingDemo(ShowBase):

314

def __init__(self):

315

ShowBase.__init__(self)

316

317

# Create loading screen

318

self.createLoadingScreen()

319

320

# Asset loading queue

321

self.assets_to_load = [

322

("models/level1.egg", "level"),

323

("models/player.egg", "player"),

324

("models/enemies.egg", "enemies"),

325

("textures/environment.png", "env_texture"),

326

("sounds/music.ogg", "music")

327

]

328

329

self.loaded_assets = {}

330

self.loading_progress = 0

331

332

# Start async loading

333

self.startAsyncLoading()

334

335

def createLoadingScreen(self):

336

"""Create loading screen UI."""

337

# Background

338

self.loading_bg = DirectFrame(

339

frameColor=(0, 0, 0, 1),

340

frameSize=(-2, 2, -1, 1)

341

)

342

343

# Loading text

344

self.loading_text = OnscreenText(

345

text="Loading...",

346

pos=(0, 0.2),

347

scale=0.1,

348

fg=(1, 1, 1, 1)

349

)

350

351

# Progress bar background

352

self.progress_bg = DirectFrame(

353

frameColor=(0.3, 0.3, 0.3, 1),

354

frameSize=(-0.8, 0.8, -0.05, 0.05),

355

pos=(0, 0, -0.2)

356

)

357

358

# Progress bar

359

self.progress_bar = DirectFrame(

360

frameColor=(0, 1, 0, 1),

361

frameSize=(0, 0, -0.05, 0.05),

362

pos=(-0.8, 0, -0.2)

363

)

364

365

def startAsyncLoading(self):

366

"""Start asynchronous asset loading."""

367

if self.assets_to_load:

368

asset_path, asset_name = self.assets_to_load.pop(0)

369

370

# Determine asset type and load accordingly

371

if asset_path.endswith(('.egg', '.bam', '.x')):

372

self.loader.loadModel(

373

asset_path,

374

callback=self.onAssetLoaded,

375

extraArgs=[asset_name]

376

)

377

elif asset_path.endswith(('.png', '.jpg', '.tga')):

378

self.loader.loadTexture(

379

asset_path,

380

callback=self.onAssetLoaded,

381

extraArgs=[asset_name]

382

)

383

elif asset_path.endswith(('.wav', '.ogg', '.mp3')):

384

sound = self.loader.loadSfx(asset_path)

385

self.onAssetLoaded(sound, asset_name)

386

387

def onAssetLoaded(self, asset, asset_name):

388

"""Handle completed asset loading."""

389

self.loaded_assets[asset_name] = asset

390

self.loading_progress += 1

391

392

# Update progress

393

total_assets = len(self.assets_to_load) + self.loading_progress

394

progress = self.loading_progress / total_assets

395

396

# Update progress bar

397

bar_width = 1.6 * progress

398

self.progress_bar['frameSize'] = (0, bar_width, -0.05, 0.05)

399

400

# Update loading text

401

self.loading_text.setText(f"Loading... {int(progress * 100)}%")

402

403

# Continue loading or finish

404

if self.assets_to_load:

405

self.startAsyncLoading()

406

else:

407

self.onLoadingComplete()

408

409

def onLoadingComplete(self):

410

"""Handle loading completion."""

411

print("All assets loaded!")

412

413

# Hide loading screen

414

self.loading_bg.destroy()

415

self.loading_text.destroy()

416

self.progress_bg.destroy()

417

self.progress_bar.destroy()

418

419

# Setup game with loaded assets

420

self.setupGame()

421

422

def setupGame(self):

423

"""Setup game with loaded assets."""

424

# Use loaded assets

425

if "level" in self.loaded_assets:

426

level = self.loaded_assets["level"]

427

level.reparentTo(self.render)

428

429

if "player" in self.loaded_assets:

430

player = self.loaded_assets["player"]

431

player.reparentTo(self.render)

432

player.setPos(0, 10, 0)

433

434

print("Game setup complete!")

435

436

app = AsyncLoadingDemo()

437

app.run()

438

```

439

440

### Asset Management System

441

442

```python

443

from direct.showbase.DirectObject import DirectObject

444

import os

445

446

class AssetManager(DirectObject):

447

"""Centralized asset management system."""

448

449

def __init__(self):

450

DirectObject.__init__(self)

451

452

# Asset registries

453

self.models = {}

454

self.textures = {}

455

self.sounds = {}

456

self.fonts = {}

457

458

# Loading statistics

459

self.load_count = 0

460

self.cache_hits = 0

461

462

# Setup asset paths

463

self.setupPaths()

464

465

def setupPaths(self):

466

"""Setup asset search paths."""

467

paths = [

468

"assets/models",

469

"assets/textures",

470

"assets/sounds",

471

"assets/fonts",

472

"data"

473

]

474

475

for path in paths:

476

if os.path.exists(path):

477

getModelPath().appendDirectory(path)

478

479

def loadModel(self, name: str, path: str = None) -> NodePath:

480

"""Load and cache model."""

481

if name in self.models:

482

self.cache_hits += 1

483

return self.models[name]

484

485

model_path = path if path else name

486

model = loader.loadModel(model_path)

487

488

if model:

489

self.models[name] = model

490

self.load_count += 1

491

print(f"Loaded model: {name}")

492

else:

493

print(f"Failed to load model: {model_path}")

494

495

return model

496

497

def loadTexture(self, name: str, path: str = None) -> Texture:

498

"""Load and cache texture."""

499

if name in self.textures:

500

self.cache_hits += 1

501

return self.textures[name]

502

503

texture_path = path if path else name

504

texture = loader.loadTexture(texture_path)

505

506

if texture:

507

self.textures[name] = texture

508

self.load_count += 1

509

print(f"Loaded texture: {name}")

510

else:

511

print(f"Failed to load texture: {texture_path}")

512

513

return texture

514

515

def loadSound(self, name: str, path: str = None) -> AudioSound:

516

"""Load and cache sound."""

517

if name in self.sounds:

518

self.cache_hits += 1

519

return self.sounds[name]

520

521

sound_path = path if path else name

522

sound = loader.loadSfx(sound_path)

523

524

if sound:

525

self.sounds[name] = sound

526

self.load_count += 1

527

print(f"Loaded sound: {name}")

528

else:

529

print(f"Failed to load sound: {sound_path}")

530

531

return sound

532

533

def preloadAssets(self, asset_list: list):

534

"""Preload list of assets."""

535

for asset_type, name, path in asset_list:

536

if asset_type == "model":

537

self.loadModel(name, path)

538

elif asset_type == "texture":

539

self.loadTexture(name, path)

540

elif asset_type == "sound":

541

self.loadSound(name, path)

542

543

def getStats(self) -> dict:

544

"""Get loading statistics."""

545

return {

546

"models_loaded": len(self.models),

547

"textures_loaded": len(self.textures),

548

"sounds_loaded": len(self.sounds),

549

"total_loads": self.load_count,

550

"cache_hits": self.cache_hits

551

}

552

553

def cleanup(self):

554

"""Clean up all assets."""

555

# Models cleanup (NodePaths)

556

for model in self.models.values():

557

if model:

558

model.removeNode()

559

560

# Clear registries

561

self.models.clear()

562

self.textures.clear()

563

self.sounds.clear()

564

self.fonts.clear()

565

566

print("Asset manager cleaned up")

567

568

# Global asset manager instance

569

asset_manager = AssetManager()

570

```

571

572

## Types

573

574

```python { .api }

575

from panda3d.core import Texture, TextFont, AudioSound, Shader, NodePath

576

577

# Asset loading return types

578

NodePath # 3D models and scene graphs

579

Texture # Image textures and materials

580

AudioSound # Sound effects and music

581

TextFont # Fonts for text rendering

582

Shader # Vertex/fragment shader programs

583

584

# File format constants

585

class Texture:

586

# Texture formats

587

F_rgb = 1 # RGB format

588

F_rgba = 2 # RGBA format

589

F_alpha = 3 # Alpha only

590

F_luminance = 4 # Grayscale

591

592

# Filter modes

593

FT_nearest = 1 # Nearest neighbor

594

FT_linear = 2 # Linear filtering

595

FT_nearest_mipmap_nearest = 3

596

FT_linear_mipmap_nearest = 4

597

FT_nearest_mipmap_linear = 5

598

FT_linear_mipmap_linear = 6

599

```