Panda3D学习之路(二)

Intervals&Sequence

先来看一段代码

from math import pi,sin,cos

from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import Sequence
from panda3d.core import Point3


class MyApp(ShowBase):

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

        # Load the environment model.
        self.scene = self.loader.loadModel("/Developer/Panda3D/models/environment")
        # Reparent the model to render.
        self.scene.reparentTo(self.render)
        # Apply scale and position transforms on the model.
        self.scene.setScale(0.25, 0.25, 0.25)
        self.scene.setPos(-8, 42, 0)

        # Add the spinCameraTask procedure to the task manager.
        self.taskMgr.add(self.spinCameraTask,"SpinCameraTask")

        #load and transfrom the panda actor
        self.pandaActor = Actor("/Developer/Panda3D/models/panda-model",{"walk":"/Developer/Panda3D/models/panda-walk4"})
        self.pandaActor.setScale(0.005,0.005,0.005)
        self.pandaActor.reparentTo(self.render)
        # Loop its animation
        self.pandaActor.loop("walk")

        # create the four lerp intervals needed for the panda to
        # walk back and forth
        pandaPosInterval1 = self.pandaActor.posInterval(13,Point3(0,-10,0),startPos=Point3(0,10,0))
        pandaPosInterval2 = self.pandaActor.posInterval(13,Point3(0,-10,0),startPos=Point3(0,-10,0))
        pandaHprInterval1 = self.pandaActor.hprInterval(3,Point3(180,0,0),startHpr=Point3(0,0,0))
        pandaHprInterval2 = self.pandaActor.hprInterval(3,Point3(0,0,0),startHpr=Point3(180,0,0))

        # Create and play the sequence that coordinates the intervals.
        self.pandaPace = Sequence(pandaPosInterval1,pandaHprInterval1,pandaPosInterval2,pandaHprInterval2)
        self.pandaPace.loop()


    # Define a procedure to move the camera
    def spinCameraTask(self,task):
        angleDegrees = task.time * 6.0
        angleRadians = angleDegrees * (pi/180.0)
        self.camera.setPos(20 * sin(angleRadians),-20.0*cos(angleRadians),3)
        self.camera.setHpr(angleDegrees,0,0)
        return Task.cont

app = MyApp()
app.run()

pandaPosInterval1间隔开始,他将会逐步的将熊猫在13秒内从(0,10,0)转移到(0,-10,0)的位置。

pandaHprInterval1与上面的的累死,3秒旋转180度

而后面的Sequence则使panda按照一个顺序来执行这几个任务,即先直线走到那个位置,然后旋转180度之后回头直走,之后再转180度

The Scene Graph

场景图,是一个有节点的树

对于场景渲染来说,在panda3D中,只有当你把他插入render树中的时候,他才会可见。

render树由PandaNode节点构成,他是很多其他类的超类:ModelnodeGeoNodeLightNode等等。但是所有的节点的总根是render(注:已有特殊情况不一样,例如2D情况下根是render2D)

关于场景树的层级:

  1. 你可以控制书中的节点对象,随便深浅
  2. 对象的位置与它们在树中的父节点有关系
  3. 当模型被分配在树中,任何渲染属性都会遗传给子节点
  4. panda3D会给每个节点生成包围体,一个好的组织结构可以加速识见体和遮挡物的剔除处理。

如果没有很明显的要求,那就平行地插入树中(形成父子关系要谨慎)

NodePaths

又一个帮助类叫做NodePath,是一个非常小的包含了指向节点的指针的对象,他还有一些管理的信息。暂时,你可以不用了解那些管理的信息,在接下来我会介绍。Panda3D的设计者们把这个当作一个节点的句柄,任何的函数一旦create了一个节点则会生成这样一个句柄。

他不是一个指向节点的指针,他是一个句柄。概念上来说,这是两者最大的不同。但是有一些函数希望你传入的是NodePath,但是其他的一些函数希望你传入的是指针,因此要注意。

你可以通过nodePath.node()函数随时把一个nodePath转换成一个指针。但是,很清楚的是没有办法转换回来。因此,建议你用nodePath来存储,而不是指针。

NodePath的方法和Node的方法

我们看一些例子:

# NODEPATH METHODS:
myNodePath.setPos(x, y, z)
myNodePath.setColor(banana)

# LODNODE METHODS:
myNodePath.node().addSwitch(1000, 100)
myNodePath.node().setCenter(Point3(0, 5, 0))

# CAMERA NODE METHODS:
myNodePath.node().setLens(PerspectiveLens())
myNodePath.node().getCameraMask()

总之要记住的是,当你操作一个NodePath的时候就是在操作一个node。

在上面的例子中通过NodePath来调用Node是一个best practice

默认的场景图

默认有两种场景图(两种根节点):renderrender2d

正常的3d场景你需要把render作为第一个父亲。

而2d的GUI元素,例如text和buttons则需要render2d,所有的render2d都会在3d渲染场景的上部渲染,例如我们想将画面做成一个玻璃碎裂的效果

render2d的坐标系统被用来和鼠标输入来匹配:最左下角的边缘是(-1,0,-1)最右上角的坐标是(1,0,1)。既然这个是一个方形的坐标系统,但是屏幕通常不是放行的,有些对象可能是被压扁的,因此Panda3D海底泥来一个render2d的孩子叫做aspect2d,他有一个scale属性用来正确的控制非矩形的情况。更多的时候你的父亲GUI元素是aspect2d而不是render2d

尤其是,这个坐标系统中的aspect2d默认的scaled被置为[-ratio,ratio],而y被置为[-1,1]之间(因为一般情况下,长比宽要长)

还有一个更高一层的node叫做hidden,如果作为他的孩子则无法被渲染,老的Panda3D需要使用hidden来移除一个场景图中的节点,但是这对于现在的我们来说不需要了。对于新版本来说,建议的方式是调用nodePath.detachNode()函数。

Loading models

你可以通过一个文件路径名来载入图像,panda3D中大部分是.egg``.bam,如果没有后缀名则默认当做这两个去寻找。

Reparent nodes and models

如果要对节点和模型重定向父亲节点,则调用这个函数就可以了:
myModel.reparentTo(fooNode)fooNode是个占位符,表示场景树中的一个节点。
然后再移动一次:myModel.detachNode()

如果确定以后再也不用这个模型,并且决定释放资源,则调用这个函数:
myModel.removeNode()

还有一个常用的函数是:
myModel.wrtReparentTo(fooNode),这里的wrt表示的是”with repect to”,相对于,表示一个相对于的位置。

不过这个函数的使用要小心,因为wrt操作是一个浮点数的矩阵运算,他每次操作都会造成部分误差,如果很多次这样的操作会造成明显的偏差,因此要小心使用。小心overuse。

你可能感兴趣的:(Panda3D游戏)