这个例子主要涉及到两方面内容:
1. camera 的自动跟踪功能,它可以使得摄像机无论怎样移动总是对准一个物体。这里说的物体不是公告板技术中的平面物体,而是一个SceneNode。
2. 使用了动画相关的功能。这个例子中使得摄像头沿着预先定义的轨迹移动。
下面就来详细的分析这个DEMO:
下面三行代码定义了一个Ogre的头Entity,然后把它挂接到场景树中的一个SceneNode headNode上。
SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
ent = mSceneMgr->createEntity("head", "ogrehead.mesh");
headNode->attachObject(ent);
下面代码调用了Camera中的
void setAutoTracking(bool enabled, SceneNode* target = 0,
const Vector3& offset = Vector3::ZERO);
这个函数有三个参数,enabled表示是否开启Camere跟踪技术;target表示要跟踪的场景节点;offset表示视点的偏移量,例如:如果目标节点太大,你可以调节offset来更好的观察目标。
这样就使得Camera总是指向一个SceneNode,总是“盯”住了一个SceneNode,而无论照相机移动还是场景节点移动。
// Make sure the camera track this node
mCamera->setAutoTracking(true, headNode);
然后把这个摄像机也挂接到场景树中。
SceneNode* camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
camNode->attachObject(mCamera);
下面就是使用动画相关类来设置摄像机的移动路线。
首先通过SenceManager来创建一个Animation实例。一个Animation由很多AnimationTrack构成的。Animation可以构成是整个场景动画,而AnimationTrack代表这个场景中的一个SenceNode的运动轨迹。(这个例子中就代表Camera的运动路径)每个SenceNode的轨迹即AnimationTrack又由很多KeyFrame构成。这些KeyFrame之间的运动路径默认是直线到达,也可以通过
void Animation::setInterpolationMode(InterpolationMode im)
传递参数:IM_SPLINE ,来设置使用样条插值,这样KeyFrame之间的运动路径就会变得平滑。
// 10代表动画运行的时间,也可以理解为帧的数目
Animation* anim = mSceneMgr->createAnimation("CameraTrack", 10);
// 样条插值
anim->setInterpolationMode(Animation::IM_SPLINE);
// 设置Camera的运动轨迹
AnimationTrack* track = anim->createTrack(0, camNode);
// Setup keyframes
KeyFrame* key = track->createKeyFrame(0); // startposition
key = track->createKeyFrame(2.5);
key->setTranslate(Vector3(500,500,-1000));
key = track->createKeyFrame(5);
key->setTranslate(Vector3(-1500,1000,-600));
key = track->createKeyFrame(7.5);
key->setTranslate(Vector3(0,-100,0));
key = track->createKeyFrame(10);
key->setTranslate(Vector3(0,0,0));
最后通过SceneManager的CreateAnimationState方法来创建AnimationState实例。并开启动画。
// Create a new animation state to track this
mAnimState = mSceneMgr->createAnimationState("CameraTrack");
mAnimState->setEnabled(true);
这个实例用来控制动画。比如可以设置当前应该运动到哪一帧。比如这个Demo中的
bool frameStarted(const FrameEvent& evt)方法中有如下函数:
//每一帧前增加一帧的时间,从而可以定位到动画应该是什么样的场面。
mAnimState->addTime(evt.timeSinceLastFrame);它就根据timeSinceLastFrame来得到相应动画应该运动到什么时间位置。