Panda3D实战:从入门到精通

发布于:2025-07-04 ⋅ 阅读:(16) ⋅ 点赞:(0)

Panda3D基础实例

创建一个简单的Panda3D场景,加载一个模型并显示:

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.scene = self.loader.loadModel("models/environment")
        self.scene.reparentTo(self.render)
        self.scene.setScale(0.25, 0.25, 0.25)
        self.scene.setPos(-8, 42, 0)

app = MyApp()
app.run()

键盘控制实例

实现键盘控制模型移动:

from direct.showbase.ShowBase import ShowBase
from direct.actor.Actor import Actor

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.panda = Actor("models/panda-model", {"walk": "models/panda-walk"})
        self.panda.reparentTo(self.render)
        self.panda.loop("walk")
        
        self.accept("arrow_left", self.turnLeft)
        self.accept("arrow_right", self.turnRight)
        self.accept("arrow_up", self.moveForward)
        self.accept("arrow_down", self.moveBackward)
    
    def turnLeft(self):
        self.panda.setH(self.panda.getH() + 5)
    
    def turnRight(self):
        self.panda.setH(self.panda.getH() - 5)
    
    def moveForward(self):
        self.panda.setY(self.panda, -0.5)
    
    def moveBackward(self):
        self.panda.setY(self.panda, 0.5)

app = MyApp()
app.run()

碰撞检测实例

实现简单的碰撞检测系统:

from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionTraverser, CollisionNode
from panda3d.core import CollisionHandlerQueue, CollisionRay

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.cTrav = CollisionTraverser()
        self.picker = CollisionRay()
        
        pickerNode = CollisionNode('mouseRay')
        pickerNode.addSolid(self.picker)
        self.pickerNP = self.camera.attachNewNode(pickerNode)
        self.pickerQueue = CollisionHandlerQueue()
        
        self.cTrav.addCollider(self.pickerNP, self.pickerQueue)
        
        self.accept("mouse1", self.handleClick)
    
    def handleClick(self):
        if self.pickerQueue.getNumEntries() > 0:
            self.pickerQueue.sortEntries()
            pickedObj = self.pickerQueue.getEntry(0).getIntoNodePath()
            print("Clicked on:", pickedObj.getName())

app = MyApp()
app.run()

光照效果实例

添加多种光源到场景中:

from direct.showbase.ShowBase import ShowBase
from panda3d.core import AmbientLight, DirectionalLight, PointLight

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.scene = self.loader.loadModel("models/environment")
        self.scene.reparentTo(self.render)
        
        # 环境光
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((0.2, 0.2, 0.2, 1))
        self.render.setLight(self.render.attachNewNode(ambientLight))
        
        # 方向光
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setColor((0.8, 0.8, 0.5, 1))
        directionalLight.setShadowCaster(True, 512, 512)
        dlnp = self.render.attachNewNode(directionalLight)
        dlnp.setHpr(45, -45, 0)
        self.render.setLight(dlnp)
        
        # 点光源
        pointLight = PointLight("pointLight")
        pointLight.setColor((1, 0.5, 0.5, 1))
        plnp = self.render.attachNewNode(pointLight)
        plnp.setPos(10, 10, 10)
        self.render.setLight(plnp)

app = MyApp()
app.run()

粒子系统实例

创建简单的粒子效果:

from direct.showbase.ShowBase import ShowBase
from panda3d.core import ParticlePool, ParticleSystem
from panda3d.core import PointParticles, SpriteParticleRenderer
from panda3d.core import BaseParticleEmitter, RingEmitter

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.particles = ParticleSystem()
        self.particles.setPoolSize(100)
        
        renderer = SpriteParticleRenderer("particle.png")
        self.particles.addRenderer(renderer)
        
        emitter = RingEmitter()
        emitter.setAngle(10)
        emitter.setRadius(1)
        emitter.setEmissionRate(20)
        emitter.setLitterSize(5)
        self.particles.addEmitter(emitter)
        
        self.particles.reparentTo(self.render)
        self.particles.setPos(0, 10, 0)
        self.particles.enable()

app = MyApp()
app.run()

物理引擎实例

使用Bullet物理引擎创建物理场景:

from direct.showbase.ShowBase import ShowBase
from panda3d.bullet import BulletWorld, BulletPlaneShape
from panda3d.bullet import BulletBoxShape, BulletRigidBodyNode
from panda3d.core import Vec3

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0, 0, -9.81))
        
        # 创建地面
        shape = BulletPlaneShape(Vec3(0, 0, 1), 0)
        node = BulletRigidBodyNode('Ground')
        node.addShape(shape)
        np = self.render.attachNewNode(node)
        np.setPos(0, 0, 0)
        self.world.attachRigidBody(node)
        
        # 创建盒子
        shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
        node = BulletRigidBodyNode('Box')
        node.addShape(shape)
        node.setMass(1.0)
        np = self.render.attachNewNode(node)
        np.setPos(0, 0, 10)
        self.world.attachRigidBody(node)
        
        self.taskMgr.add(self.updatePhysics, 'updatePhysics')
    
    def updatePhysics(self, task):
        dt = globalClock.getDt()
        self.world.doPhysics(dt)
        return task.cont

app = MyApp()
app.run()

GUI界面实例

创建简单的GUI界面:

from direct.showbase.ShowBase import ShowBase
from direct.gui.DirectGui import DirectButton, DirectLabel

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.label = DirectLabel(text="Panda3D GUI Demo", 
                               scale=0.1,
                               pos=(0, 0, 0.8))
        
        self.button = DirectButton(text="Click Me",
                                 scale=0.1,
                                 pos=(0, 0, 0),
                                 command=self.buttonPressed)
    
    def buttonPressed(self):
        self.label["text"] = "Button was clicked!"

app = MyApp()
app.run()

动画混合实例

混合多个动画序列:

from direct.showbase.ShowBase import ShowBase
from direct.actor.Actor import Actor

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.panda = Actor("models/panda-model", 
                          {"walk": "models/panda-walk",
                           "dance": "models/panda-dance"})
        self.panda.reparentTo(self.render)
        self.panda.setPos(0, 0, 0)
        
        # 混合动画
        self.panda.enableBlend()
        self.panda.setBlend(frameBlend=True)
        self.panda.setControlEffect("walk", 0.5)
        self.panda.setControlEffect("dance", 0.5)
        self.panda.loop("walk")
        self.panda.loop("dance")
        
        self.accept("w", self.setWalkWeight, [1.0])
        self.accept("d", self.setDanceWeight, [1.0])
        self.accept("s", self.setBothWeight, [0.5])