Sample_Character源码简析

来源:互联网 发布:医用三维解剖软件 编辑:程序博客网 时间:2024/05/27 16:43

Sample_Character例子中有如下的代码结构:

Sample_Character源码简析

官方例子中的cpp文件大多是负责调用,主要的功能实现在h文件中,即函数的定义基本在h文件中。

先来看SinbadCharacterController.h(CharacterSample.h主要负责功能调用)

里面主要是这段代码

Sample_Character源码简析

以及几个输入检测处理函数,例如injectKeyDown

上面第一个函数是类的初始化,第二个是update更新动画,相机,水手模型所用。

setupBody中:添加了

1 水手模型Sinbad.mesh

2 两把刀模型Sword.mesh

mBodyEnt->attachObjectToBone("Sheath.L", mSword1);

mBodyEnt->attachObjectToBone("Sheath.R", mSword2);

Sheath.L,Sheath.R是mesh上面的骨骼名称,可以通过OgreMax骨骼查看器查看。

当我把第一句改成

mBodyEnt->attachObjectToBone("Sheath.R", mSword1);

运行程序,发现两把刀都出现在右边的刀鞘中。

3 两条黄色火光

(注:在model文件夹中并不能找到Sinbad.mesh这些mesh文件,因为它是在pack的Sinbad.zip文件夹中)

setupCamera函数

创建了3个节点:

mCameraPivot 记录模型所在位置的节点

mCameraGoal 记录相机所在位置的节点

mCameraNode 挂接相机的节点

mCameraPivot (父节点)和mCameraGoal (子节点)是父子关系。所以当mCameraPivot 移动 旋转的时候mCameraGoal 后继承这些变换。

mCameraPivot->setFixedYawAxis(true);
mCameraGoal->setFixedYawAxis(true);
mCameraNode->setFixedYawAxis(true);

这些设置的作用请看

http://blog.csdn.net/l109383670/article/details/6792770已经讲的非常清楚了。

setupAnimations函数

这里的动画可以分为上半身动画,下半身动画,手的动画。具体的就是

String animNames[] =
{"IdleBase", "IdleTop", "RunBase", "RunTop", "HandsClosed", "HandsRelaxed", "DrawSwords",
"SliceVertical", "SliceHorizontal", "Dance", "JumpStart", "JumpLoop", "JumpEnd"};

中表示动画状态的字符串。这些字符串不是自定义的,是存在于动画中状态名称,而且区分大小写,例如把IdleBase改成Idlebase,就会报错,提示没有这样的动画状态。

mBodyEnt->getSkeleton()->setBlendMode(ANIMBLEND_CUMULATIVE);设置了动画的混合方式为累加。

真正控制具体动画播放是AnimationState* mAnims[NUM_ANIMS]; 对象。

setBaseAnimation(ANIM_IDLE_BASE);
setTopAnimation(ANIM_IDLE_TOP);

这两个函数是设置上身动画和下身动画的函数,例如下身动画可以填ANIM_IDLE_BASE(默认下身动画),ANIM_RUN_BASE等等。

mAnims[ANIM_HANDS_RELAXED]->setEnabled(true);开启“松手”动画。

updateBody函数处理键盘输入旋转移动模型

mGoalDirection.normalise();

mGoalDirection对象表示的键盘输入使水手旋转的变量,永远是单位长度,即没帧移动一个单位,同时他也表示了模型将有旋转至的方向。

if (yawToGoal < 0) yawToGoal = std::min<Real>(0, std::max<Real>(yawToGoal, yawAtSpeed));

else if (yawToGoal > 0) yawToGoal = std::max<Real>(0, std::min<Real>(yawToGoal, yawAtSpeed));

理论上是每帧旋转yawAtSpeed的量但是当需要旋转的总量yawToGoal不够yawAtSpeed时,那么就去yawToGoal为旋转量。

mBodyNode->translate(0, 0, deltaTime * RUN_SPEED * mAnims[mBaseAnimID]->getWeight(),
Node::TS_LOCAL);

从该条件判断语句mKeyDirection != Vector3::ZERO && mBaseAnimID != ANIM_DANCE中得知,模型正在奔跑,

所以上面的过程是:先将模型旋转到目标的方向,方向对了,只要移动本地z轴方向就可以了。

updateAnimations函数:利用一些动画标记(xxxID)更新变换动画。

例如if (mTopAnimID == ANIM_DRAW_SWORDS):如果上身动画是ANIM_DRAW_SWORDS(拔出刀动画)。

if (mTopAnimID == ANIM_SLICE_VERTICAL || mTopAnimID == ANIM_SLICE_HORIZONTAL):横砍或者竖砍。

如下代码:

if (mTimer >= mAnims[mTopAnimID]->getLength())
{
// animation is finished, so return to what we were doing before
if (mBaseAnimID == ANIM_IDLE_BASE) setTopAnimation(ANIM_IDLE_TOP);
else
{
setTopAnimation(ANIM_RUN_TOP);
mAnims[ANIM_RUN_TOP]->setTimePosition(mAnims[ANIM_RUN_BASE]->getTimePosition());

当上身拔刀动画完成后,上身动画不是默认动画就是奔跑动画。
}
mSwordsDrawn = !mSwordsDrawn;
}
}

fadeAnimations函数是动画淡入淡出效果,例如当松开方向键,人不会马上停止,会渐入默认动画。

updateCamera函数:移动鼠标时,调整摄像机方向。

mCameraPivot->setPosition(mBodyNode->getPosition() + Vector3::UNIT_Y * CAM_HEIGHT);
Vector3 goalOffset = mCameraGoal->_getDerivedPosition() - mCameraNode->getPosition();
mCameraNode->translate(goalOffset * deltaTime * 9.0f);
mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(), Node::TS_WORLD);

 

Sample_Character源码简析

因为mCameraGoal是mCameraPivot的子节点,所以当mCameraPivot旋转的时候,mCameraGoal会由一个从父节点继承而来的位置和旋转,这正是mCameraPivot->_getDerivedPosition()和mCameraGoal->_getDerivedPosition() 的作用,如果这里用mCameraGoal->getPosition(),得到的将是mCameraGoal原来的位置。

大致分析完了SinbadCharacterController.h

然后来分析

CharacterSample.h
这里面最值得注意的是

setupContent函数,相当于官方Tutorial中的createScene,用来创建场景。

void setupContent()
{
// set background and some fog
mViewport->setBackgroundColour(ColourValue(1.0f, 1.0f, 0.8f));
mSceneMgr->setFog(Ogre::FOG_LINEAR, ColourValue(1.0f, 1.0f, 0.8f), 0, 15, 100);

设置线性雾化,使用线性插值的方式计算,距离相机为15-100的地方会出现雾和场景的混合效果,100外将看不到场景,无论相机的远裁剪面是多大。

// set shadow properties
mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
mSceneMgr->setShadowColour(ColourValue(0.5, 0.5, 0.5));
mSceneMgr->setShadowTextureSize(1024);
mSceneMgr->setShadowTextureCount(1);

阴影技术。

// disable default camera control so the character can do its own
mCameraMan->setStyle(CS_MANUAL);

mCameraMan是相机控制脚本,支持3中模式,CS_MANUAL表示手动控制。

// use a small amount of ambient lighting
mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

// add a bright light above the scene
Light* light = mSceneMgr->createLight();
light->setType(Light::LT_POINT);
light->setPosition(-10, 40, 20);
light->setSpecularColour(ColourValue::White);

// create a floor mesh resource
MeshManager::getSingleton().createPlane("floor", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Plane(Vector3::UNIT_Y, 0), 100, 100, 10, 10, true, 1, 10, 10, Vector3::UNIT_Z);

// create a floor entity, give it a material, and place it at the origin
Entity* floor = mSceneMgr->createEntity("Floor", "floor");
floor->setMaterialName("Examples/Rockwall");
floor->setCastShadows(false);
mSceneMgr->getRootSceneNode()->attachObject(floor);

创建地板。

// create our character controller
mChara = new SinbadCharacterController(mCamera);

这里会调用SinbadCharacterController类的构造函数。

mTrayMgr->toggleAdvancedFrameStats();

StringVector items;
items.push_back("Help");
ParamsPanel* help = mTrayMgr->createParamsPanel(TL_TOPLEFT, "HelpMessage", 100, items);
help->setParamValue("Help", "H / F1");

mTragMgr内置GUI类,ParamsPanel面板显示帮助菜单,有下拉条。

}

该例子就讲到这,确实不能面面俱到的分析,简单易懂的就不做解释了。

转载自:http://blog.sina.com.cn/s/blog_660535430100xl7c.html