官术网_书友最值得收藏!

Making the camera smoothly follow an object

In this recipe you will learn how to program a simple camera system that follows an object smoothly, without giving the impression of being glued to the back of the target.

Getting ready

See the recipe Setting up the game structure to create the basic application framework for the following steps.

How to do it...

Let's build a third person camera system:

  1. Add this code to Application.py:
    from direct.showbase.ShowBase import ShowBase
    from direct.actor.Actor import Actor
    from panda3d.core import Vec3
    from direct.interval.IntervalGlobal import *
    from FollowCam import FollowCam
    
    class Application(ShowBase):
        def __init__(self):
            ShowBase.__init__(self)
    
            self.world = loader.loadModel("environment")
            self.world.reparentTo(render)
            self.world.setScale(0.5)
            self.world.setPos(-8, 80, 0)
    
            self.panda = Actor("panda", {"walk": "panda-walk"})
            self.panda.reparentTo(render)
            self.panda.setHpr(270, 0, 0)
            self.panda.loop("walk")
    
            self.walkIval1 = self.panda.posInterval(2, Vec3(-8, -8, 0), startPos = Vec3(8, -8, 0))
            self.walkIval2 = self.panda.posInterval(2, Vec3(-8, 8, 0), startPos = Vec3(-8, -8, 0))
            self.walkIval3 = self.panda.posInterval(2, Vec3(8, 8, 0), startPos = Vec3(-8, 8, 0))
            self.walkIval4 = self.panda.posInterval(2, Vec3(8, -8, 0), startPos = Vec3(8, 8, 0))
    
            self.turnIval1 = self.panda.hprInterval(0.5, Vec3(180, 0, 0), startHpr = Vec3(270, 0, 0))
            self.turnIval2 = self.panda.hprInterval(0.5, Vec3(90, 0, 0), startHpr = Vec3(180, 0, 0))
            self.turnIval3 = self.panda.hprInterval(0.5, Vec3(0, 0, 0), startHpr = Vec3(90, 0, 0))
            self.turnIval4 = self.panda.hprInterval(0.5, Vec3(-90, 0, 0), startHpr = Vec3(0, 0, 0))
    
            self.pandaWalk = Sequence(self.walkIval1, self.turnIval1,
                                      self.walkIval2, self.turnIval2,
                                      self.walkIval3, self.turnIval3,
                                      self.walkIval4, self.turnIval4)
            self.pandaWalk.loop()
            self.followCam = FollowCam(self.cam, self.panda)
  2. Add a new file to the project. Call it FollowCam.py.
  3. Copy the following code to the file you just created:
    from direct.showbase.ShowBase import ShowBase
    from panda3d.core import Vec3
    
    class FollowCam():
        def __init__(self, camera, target):
            self.dummy = render.attachNewNode("cam" + target.getName())
            self.turnRate = 2.2
            self.camera = camera
            self.target = target
            taskMgr.add(self.updateCamera, "updateCamera" + target.getName())
    
        def updateCamera(self, task):
            self.dummy.setPos(self.target.getPos())
            heading = self.clampAngle(self.dummy.getH())
    
            turnDiff = self.target.getH() - heading
            turnDiff = self.clampAngle(turnDiff)
    
            dt = globalClock.getDt()
            turn = turnDiff * dt
            self.dummy.setH(heading + turn * self.turnRate)
    
            self.camera.setPos(self.dummy.getPos())
            self.camera.setY(self.dummy, 40)
            self.camera.setZ(self.dummy, 10)
            self.camera.lookAt(self.target.getPos() + Vec3(0, 0, 7))
    
            return task.cont
    
        def clampAngle(self, angle):
            while angle < -180:
                angle = angle + 360
    
            while angle > 180:
                angle = angle - 360
    
            return angle
  4. Press F6 to start the application. You should be able to see a panda walking in circles while the camera follows it:

How it works...

We use the constructor of our Application class to set up the scene containing the walking panda and the background scenery. In the last line we create a new instance of our FollowCam, which contains the camera tracking code that is the core of this recipe.

To make the FollowCam work correctly and to be able to have multiple cameras follow different objects, we have to pass the camera we want to be updated and its target to the constructor, where we set up a few things we need for updating the camera. For example, we add a task that will call the updateCamera() method each frame. Additionally, the target's name is appended to both the dummy object's and the task's names to avoid name clashes in the case where we need to use more than one FollowCam instance. The dummy object is an invisible helper object that will help us to position the camera, as you will see in the following paragraphs.

The updateCamera() method is where all the work is happening: We move the dummy to our target's current position and get its current heading. The heading angle (in degrees) is clamped to the range of values from 180 to 180. We do this to avoid the camera getting stuck or continuing to turn because of the ambiguous nature of angles.

In the next steps, we calculate the difference between the target's heading and that of our dummy object, which is also clamped to avoid the undesired results described in the previous paragraph. In the following lines we can find the explanation for the camera's smooth turning—every frame, the dummy object's heading converges towards the heading of the camera target just a little bit. This is intentional; as it is multiplied by the time it took to complete the last frame. Additionally, we can also influence how fast the camera turns by adjusting turnRate.

In the final steps, the camera is first moved to the position of the dummy and then pushed away again along the dummy's local axis to its final position. After setting the camera's lookAt() target, we are done!

There's more...

In this version, the camera only supports smooth turning for objects that only change their heading. Other rotation axes can be added rather easily, as they work exactly the same as the one presented in this recipe!

主站蜘蛛池模板: 梧州市| 哈巴河县| 合阳县| 当雄县| 上思县| 玛多县| 垦利县| 通江县| 沧州市| 永新县| 郑州市| 桐梓县| 徐水县| 石嘴山市| 子长县| 保山市| 内乡县| 南陵县| 神木县| 乐至县| 靖边县| 闻喜县| 柘城县| 宝鸡市| 留坝县| 依安县| 齐河县| 南丰县| 莆田市| 乌海市| 舒兰市| 行唐县| 独山县| 织金县| 沙洋县| 巨野县| 萝北县| 巩留县| 庆阳市| 鄂尔多斯市| 博爱县|