浙江省建设安监站网站,成都附近旅游景区哪里好玩,ysl千色t9t9t9,沈阳优化网站公司Panda3d 相机控制 文章目录 Panda3d 相机控制Panda3d中的透视镜头和垂直镜头透视镜头垂直镜头 Panda3d 中用代码控制相机的移动用键盘控制相机的移动用鼠标控制相机的移动 Panda3d 把相机也当做是一个
PandaNode#xff0c;因此可以向操作其他节点对其进行操作。 真正的相机是…Panda3d 相机控制 文章目录 Panda3d 相机控制Panda3d中的透视镜头和垂直镜头透视镜头垂直镜头 Panda3d 中用代码控制相机的移动用键盘控制相机的移动用鼠标控制相机的移动 Panda3d 把相机也当做是一个
PandaNode因此可以向操作其他节点对其进行操作。 真正的相机是在ShowBase类中的一个叫做base.cam的NodePath在这个上面还有一个更简单的叫做base.camera的NodePath一般对相机进行控制的话是在代码中进行控制。
默认情况下panda运行一个task使我们可以通过鼠标来移动相机。用户自己写的移动相机的代码将和这个task产生冲突。该task根据鼠标当前的每一帧输入来更新相机的位置。这意味着直接控制相机的代码将不能工作因为它会跟默认的相机控制任务相冲突。为了处理这种冲突那么用户可以通过调用以下函数进行
base.disableMouse()ShowBase类为用户准备了一些控制相机的方法。useDrive()命令打开键盘和鼠标控制这两种控制系统都只能在X和Y轴上移动不能在Z轴上移动。
键盘系统使用方向键“上”向前移动相机“下”向后移动。“左”“右”键左右移动相机镜头。 鼠标系统对按下的任何一个键都有反应。若光标向屏幕上方移动相机向前若光标向屏幕下方移动相机向后。如果光标在屏幕两边相机向那个方向进行旋转。相机的移动速度取决于光标距离中心的远近。另外Panda还提供一个命令允许使用跟踪球trackball鼠标
base.useDrive()
base.useTrackball()ShowBase还提供了oobe()方法当你的代码在移动相机节点base.camera时你可以用鼠标/跟踪球来控制基相机节点base.cam。这对debug非常有用。oobe代表“out-of-body experience”灵魂出窍即开发时你可以对程序进行全方位的观察God’s-eye view。该方法是一个开关你要打开oobe模式时调用它然后再调用一次关闭它
base.oobe()oobeCull()是oobe()的一个变形它们的作用相近oobeCull()的不同在于当从新的相机位置重绘场景时场景仍然会以原先的相机位置进行剔除cull。因此你可以从你“灵魂飞出”地方来观察场景你可以四处游走看到物体进入和弹出视区就像你的视棱台view frustum也在移动一样。
Panda3d中的透视镜头和垂直镜头
透视镜头
每个相机都有一个镜头决定它的成像参数。对于简单的应用程序你无需考虑镜头问题默认的镜头参数已经很好了。但是有时候你想调整一些镜头的参数如视域。根据对镜头的不同需求我们提供了几种接口来修改参数。 Panda3d 启动时它自动为你创建了一个默认的相机和镜头。这个默认相机对象保持在base.cam从方便的角度我们应该使用base.camera来移动相机默认镜头是base.camLens。 默认镜头几乎总是一个透视镜头——即 PerspectiveLens 类的一个实例——除非你换成另一种镜头。到目前为止透视镜头是一种使用最广泛的镜头它就像一台真实的相机的镜头功能与人眼晶状体相同。 上图展示一个常规透镜相机的成像。相机只能看到黑线框里面的物体这个区域被称为镜头棱台frustum。 图中可以看到镜头拍摄的图像图像是颠倒的跟真实的物理镜头成像一样。颠倒的图像只是起到说明作用它并不是Panda3D相机的一部分它帮助我们理解Panda3D镜头和真实镜头的关系。 PerspectiveLens有很多参数可以设置这些参数不都是独立的设置某些参数将改变另外一些参数的值。
垂直镜头
前面介绍了PerspectiveLens类以及透视镜头3D渲染常用的另外一种镜头就是垂直镜头它没有视域的概念, 如下图所示 在垂直镜头里没有透视——穿过镜头的平行光不汇聚而是保持平行。透视镜头模拟了真实的物理镜头但现实中不存在垂直镜头。它主要用于特殊效果比如非自然的景观、模拟即时战略游戏的2.5D场景或绘制不需要透视的2D物体。事实上对于 render2d scene graph默认的相机就是一个OrthographicLens用于绘制屏幕GUI。
既然垂直镜头没有视域角度lens.setFov()方法就不起作用。为了调节垂直镜头的范围你需要调整它的胶片规格。与PerspectiveLens不同对OrthographicLens来说胶片规格的单位不是任意的应该用空间单位与场景建模时使用的单位一致。例如上图OrthographicLens的胶片规格被设为lens.setFilmSize(20, 15) 20 英尺 x 15 英尺 ——因为场景建模以英尺为单位一只大熊猫大概有 12 英尺 高。
垂直镜头的另一个方便的参数是近距离它的值不必一定是正数。实际上可以是负数——可以把近平面放在相机平面之后也就是说相机可以看到它身后的物体。为render2d准备的OrthographicLens被设成setNearFar(-1000, 1000)将绘制所有Z值在-1000到1000之间的物体。当然在render2d中几乎全部物体的Z值都为0因此不会有什么问题 如果需要你可以把默认的相机换成一个垂直镜头
lens OrthographicLens()
lens.setFilmSize(20, 15) # 根据你的场景来选取适当的值
base.cam.node().setLens(lens)注意使用垂直镜头可能让人失去空间感——比如物体不因为你靠近它而变大也不因为你远离它而变小——因此你可能不知道相机在移动。
Panda3d 中用代码控制相机的移动
下面两个代码就需要禁用Panda3d中默认的鼠标控制相机任务否则不能达到用户预期的目的。
用键盘控制相机的移动
最终的代码如下所示
from direct.actor.Actor import Actor
from panda3d.core import loadPrcFileData
from direct.showbase.ShowBase import ShowBase #基本显示模块# 画面显示配置设置窗口大小窗口名称、显示帧率
confVar
win-size 1280 720
window-title example
show-frame-rate-meter True
loadPrcFileData(, confVar)class MyApp(ShowBase):def __init__(self):#场景初始化super(MyApp, self).__init__()base.disableMouse()self.person base.loader.loadModel(smiley)self.person.reparentTo(self.render)# 循环一个动作# self.person.loop(run)self.cam.setPos(0, -10, 0)self.keyMap {up:False,down:False,left:False,right:False,go:False,back:False,rotate:False,}self.speed 4self.angle 0# self.accept(event-name,function name)# self.accept(event-name,function name, parameters-list)self.accept(arrow_up, self.updateKeyMap, [up, True])self.accept(arrow_up-up, self.updateKeyMap, [up, False])self.accept(arrow_down, self.updateKeyMap, [down, True])self.accept(arrow_down-up, self.updateKeyMap, [down, False])self.accept(arrow_left, self.updateKeyMap, [left, True])self.accept(arrow_left-up, self.updateKeyMap, [left, False])self.accept(arrow_right, self.updateKeyMap, [right, True])self.accept(arrow_right-up, self.updateKeyMap, [right, False])self.accept(w, self.updateKeyMap, [go, True])self.accept(w-up, self.updateKeyMap, [go, False])self.accept(s, self.updateKeyMap, [back, True])self.accept(s-up, self.updateKeyMap, [back, False])self.accept(space-up, self.updateKeyMap, [rotate, True])self.accept(apace-up-up, self.updateKeyMap, [rotate, False])self.taskMgr.add(self.update,update)def updateKeyMap(self, key, state):self.keyMap[key] statedef update(self, task):# 或者这个函数的运行时间或者说是更新的帧率dt globalClock.getDt()pos self.person.getPos()if self.keyMap[up]:pos.z self.speed * dtif self.keyMap[down]:pos.z - self.speed * dtif self.keyMap[left]:pos.x - self.speed * dtif self.keyMap[right]:pos.x self.speed * dtif self.keyMap[go]:pos.y - self.speed * dtif self.keyMap[back]:pos.y self.speed * dtif self.keyMap[rotate]:self.angle 1if self.angle 360:self.angle 0self.person.setH(self.angle)self.person.setPos(pos)return task.contapp MyApp()
app.run()
run()用鼠标控制相机的移动
Panda3d 中默认的鼠标操作定义如下
鼠标左键按住左键再移动光标可以控制画面左右旋摆。鼠标右键按住右键键再移动光标可以控制画面的远近。鼠标滚轮按住滚轮键键再移动光标可以控制角度上下左右的角度旋转盘旋。鼠标右键滚轮按住右键滚轮键键再移动光标绕垂直电脑屏幕的轴旋转。
下面代码中的鼠标操作定义如下 鼠标左键按住左键再移动光标可以控制画面左右上下移动。 鼠标右键按住右键键再移动光标可以控制画面的左右上下旋转。 鼠标滚轮按住滚轮键可以控制画面的前后移动也就是画面的放大和缩小。 mouse1 是鼠标左键mouse2 是鼠标中键mouse3 是鼠标右键
代码如下 from direct.actor.Actor import Actor
from panda3d.core import loadPrcFileData
from direct.showbase.ShowBase import ShowBase #基本显示模块
from direct.showbase.ShowBase import (Filename, LVecBase3f, NodePath, Task)
from direct.interval.IntervalGlobal import LerpPosInterval
from IPython import embed# 画面显示配置设置窗口大小窗口名称、显示帧率
confVar
win-size 1280 720
window-title example
show-frame-rate-meter True
loadPrcFileData(, confVar)class MyApp(ShowBase):def __init__(self):#场景初始化super(MyApp, self).__init__()base.disableMouse()self.person base.loader.loadModel(smiley)self.person.reparentTo(self.render)# 循环一个动作# self.person.loop(run)self.cam.setPos(0, -10, 0)self.keyMap {up:False,down:False,left:False,right:False,go:False,back:False,rotate:False,}self.speed 4self.angle 0self.mouse_map {}self.Cursor2D_X 0.0self.Cursor2D_Y 0.0self.Cursor2D_X_pre 0.0self.Cursor2D_Y_pre 0.0self.Cursor2D_X_direction 0.0self.Cursor2D_Y_direction 0.0# 可以取消原来默认的鼠标点击事件可以用户自定义鼠标控制事件self.accept(mouse1, self.SetMouse, [mouse1_event, True])self.accept(mouse1-up, self.SetMouse, [mouse1_event, False])# mouse2 是鼠标中键# 鼠标的右键self.accept(mouse3, self.SetMouse, [mouse3_event, True])self.accept(mouse3-up, self.SetMouse, [mouse3_event, False])# self.mouseWatcherNode.set_modifier_buttons(ModifierButtons())# self.buttonThrowers[0].node().set_modifier_buttons(ModifierButtons())self.accept(mouse3-up_mouse1-up, self.SetMouse, [mouse31_event, False])# 鼠标中键向上滚动self.accept(wheel_up, self.cameraZoom,[-1])# 鼠标中键向下滚动self.accept(wheel_down, self.cameraZoom,[1])self.taskMgr.add(self.UpdateMouseCameraTask, UpdateMouseCameraTask)def SetMouse(self, mouse, val):self.mouse_map[mouse] valdef UpdateMouseCameraTask(self, task):# time since last framedt globalClock.getDt()step 90if base.mouseWatcherNode.hasMouse():# 两条指令值等价的都是得到当前鼠标的位置self.Cursor2D_X base.mouseWatcherNode.getMouseX()self.Cursor2D_Y base.mouseWatcherNode.getMouseY()if(self.Cursor2D_X - self.Cursor2D_X_pre 1e-4):self.Cursor2D_X_direction 0.1elif (self.Cursor2D_X - self.Cursor2D_X_pre -1e-4):self.Cursor2D_X_direction -0.1else:self.Cursor2D_X_direction 0.0if(self.Cursor2D_Y - self.Cursor2D_Y_pre 1e-4):self.Cursor2D_Y_direction 0.1elif (self.Cursor2D_Y - self.Cursor2D_Y_pre -1e-4):self.Cursor2D_Y_direction -0.1else:self.Cursor2D_Y_direction 0.0if self.mouse_map.get(mouse1_event) True and (self.mouse_map.get(mouse3_event) False or self.mouse_map.get(mouse3_event) None):self.camera.setPos(LVecBase3f(self.camera.getX()-(2*self.Cursor2D_X_direction), self.camera.getY(), self.camera.getZ()-2*self.Cursor2D_Y_direction))if self.mouse_map.get(mouse3_event) True and (self.mouse_map.get(mouse1_event) False or self.mouse_map.get(mouse1_event) None):self.camera.setHpr(self.camera.getH()(2*self.Cursor2D_X_direction), self.camera.getP()(2*self.Cursor2D_Y_direction), self.camera.getR())# # 以下两个指令用来获取得到当前窗口的大小# print(base.win.getProperties().getXSize())# print(base.win.getProperties().getYSize())self.Cursor2D_X_pre self.Cursor2D_Xself.Cursor2D_Y_pre self.Cursor2D_Yreturn Task.cont# 进行相机视野的放大和缩小def cameraZoom(self,dir):self.camera.setPos(LVecBase3f(self.camera.getX(), self.camera.getY()-(2*dir), self.camera.getZ()(2*dir)))# self.camZoom LerpPosInterval(self.camera, self.speed, LVecBase3f(self.camera.getX(), self.camera.getY()-(2*dir), self.camera.getZ()(2*dir)))# self.camZoom.start()app MyApp()
app.run()
run()上述UpdateMouseCameraTask 主要是通过不断的比较当前鼠标光标的位置来调整相机的位置按下鼠标的左键主要是控制相机的位置移动 而按下右键主要是控制相机的姿态旋转。