Sviluppare un gioco in Python: Panda3D – importare modelli

Introduzione

In questo articolo vedremo come inserire i nostri modelli all’interno della scena gestita da Panda3D. Utilizzeremo delle funzioni base per il movimento della telecamera, così da permetterci di ammirare le nostre creazioni senza scrivere una riga di codice.

Per realizzare i modelli 3d da caricare all’interno di Panda ho scelto di utilizzare il famoso programma di modellazione e rendering Blender. Questo perché dispone di un semplice script per convertire le nostre creazioni in un formato riconoscibile da Panda.

Panda3D lavora con modelli in formato .egg, che contengono tutto quello che c’è da sapere sul nostro oggetto tridimensionale. Questi file sono anche editabili manualmente, quindi potete sbirciare al loro interno per vedere come sono costruiti.

Un altro tipo di file utilizzabile è .bam, che differisce da .egg in quanto è in forma binaria e leggibile solo da Panda3D. I file .bam contengono quindi le stesse informazioni dei .egg, ma sono stati pensati per un caricamento più veloce ed una migliore esecuzione del programma e per questo motivo non sono editabili dall’utente. Il loro utilizzo è consigliato per una release del gioco, mentre durante lo sviluppo può essere utile lavorare con i .egg .

Per utilizzare questi due tipi di file abbiamo bisogno di un covertitore:

Chicken Exporter

Potete scaricare Chicken da qui. Una volta scaricato, mettete il contenuto nella cartella che contiene gli script di Blender. Una volta aperto il programma, noterete che sotto la voce File->Export ora esiste anche il formato “Chicken Rxx”. Chicken vi richiederà di collegare al programma la cartella bin di Panda3D, questo perché gli eseguibili per convertire i modelli si trovano proprio in questa cartella. Purtroppo lo script non funziona ancora con l’ultima versione online di Blender, ma potete utilizzarlo con la 2.49 e precedenti.

Per le versioni superiori di Blender è disponibile questo script (sicuramente sarà completato a breve, ma già offre le funzionalità basilari), che dovete aprire con il Text Editor di Blender. Una volta aperto, editate il percorso dove volete che il file sia salvato : “FILE_PATH = “. Poi eseguite lo script.

Per ora non importa quale versione scegliate, visto che nell’esempio utilizzo due semplici cubi senza texture.

Codice

Nell’esempio che vi propongo, ho inserito un modello dei Samples presenti in Panda3D (Carousel) più due cubi creati con Blender, quello .egg con la versione 2.58a (con lo script corrispondente) e il .bam con la versione 2.49b.

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.oggetto0 = self.loader.loadModel("models/test.egg")
        self.oggetto0.reparentTo(self.render)
        self.oggetto0.setPos(-3,7,5)

        self.oggetto1 = self.loader.loadModel("models/test2.bam")
        self.oggetto1.reparentTo(self.render)
        self.oggetto1.setPos(3,7,4)

        self.oggetto2 = self.loader.loadModel("models/carousel_base.egg.pz")
        self.oggetto2.reparentTo(self.render)
        self.oggetto2.setPos(0,7,2)

        self.setBackgroundColor(0,0,255)
        self.disableMouse()
        self.useDrive()

app = MyApp()
app.run()

Di seguito riporto anche la versione che utilizza le variabili globali ‘base’,’load’ e ‘render’, che necessita solo l’import di “direct.directbase.DirectStart”. Quest’ultimo inizializza una finestra di Panda3D con tutti i moduli necessari. Utilizzando le variabili globali prima citate, questo script necessita solo del metodo run() per le interazioni con l’untente. Le funzionalità sono le stesse di quello precedente, lo metto solo per farvi vedere un confronto tra i due approcci.

import direct.directbase.DirectStart

class World:
    def __init__(self):

        self.oggetto0 = loader.loadModel("models/test.egg")
        self.oggetto0.reparentTo(render)
        self.oggetto0.setPos(-3,7,5)

        self.oggetto1 = loader.loadModel("models/test2.bam")
        self.oggetto1.reparentTo(render)
        self.oggetto1.setPos(3,7,4)

        self.oggetto2 = loader.loadModel("models/carousel_base.egg.pz")
        self.oggetto2.reparentTo(render)
        self.oggetto2.setPos(0,7,2)

        base.setBackgroundColor(0,0,0.9)
        base.disableMouse()
        base.useDrive()

w = World()
run()

Analisi

In MyApp creiamo i tre oggetti che compongono la nostra scena utilizzando loader.LoadModel. Una volta caricati bisogna associarli al nodo principale di rendering, ovvero self.render. Se non lo facciamo, i nostri modelli non saranno visualizzati. Aggiustiamo le coordinate degli oggetti con il metodo setPos.

Per finire, settiamo un colore di sfondo e disabilitiamo il movimento standard del mouse per rimpiazzarlo con quello simile alla guida di una macchina. Possiamo così utilizzare le frecce direzionali per spostarci all’interno della scena.

Come avrete notato, le differenze sostanziali dei due script sono che su uno implementiamo direttamente ShowBase nella classe da noi creata, mentre nell’altro viene inizializzato in automatico l’engine e abbiamo disponibili delle variabili globali (come ‘base’, ‘loader’ e ‘render’) per interagire con il motore di Panda3D. Alcuni esempi che vi proporrò verranno scritti in entrambi i modi, per permettervi di giostrarvi meglio nell’SDK e negli esempi che potete trovare online, sul manuale ufficiale o sui samples che trovate scaricando Panda3D.

Conclusioni

Questo esempio fa capire come è facile caricare modelli all’interno della nostra scena, utilizzando le varie configurazioni possibili in Panda3D. Per ora non soffermatevi troppo sul Carosello caricato (completo di texture), ci ritorneremo più avanti. Prestate invece molta attenzione al fatto che tutti gli oggetti sono stati associati ad un nodo comune per essere renderizzati (self.render o render). Analizzeremo questo tema nelle prossime puntate, per capire la struttura di rendering di Panda3D.

Di seguito riporto il download sell’esempio:

Panda3D – LoadModel

Press ESC to close