|
|
我改了一个例子,就是Demo_Crowd.exe我让那一堆在山坡上原定踏步的机器人,改成向前走。
但是发现用例子里面的所使用的保持在地面上的方法,在上坡的地方就走不动了。变成原地走了。为什么?
源码如下,要放在OGRE的目录里面,这样就不用设置了。比如:E:\OgreSDK\MyOGREPrj\ExampleOGRE\ExampleOGRE.sln
#include "ExampleApplication.h"
// Event handler to add ability to alter curvature
class MyOGREFrameListener : public ExampleFrameListener
{
protected:
size_t numMesh;//机器人网格数量
size_t objectCount;//机器人物体数量
size_t numRender;//渲染的实体序列标号
//可移动的3D物体,AnimationState可动画状态
std::vector <Entity *> renderEntity;//实体队列集合区别于批处理机器人
std::vector <AnimationState*> animations;
//c场景节点
std::vector <SceneNode *> nodes; //实体队列集合方法所使用的
public:
MyOGREFrameListener(RenderWindow* win, Camera* cam)
: ExampleFrameListener(win, cam)
{
numMesh =70;//机器人网格数量
createEntityGeom();
}
//-----------------------------------------------------------------------
MyOGREFrameListener::~MyOGREFrameListener()
{
destroyEntityGeom();
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
bool frameStarted(const FrameEvent& evt)
{
std::vector <AnimationState*>::iterator it;
for(it=animations.begin();it!=animations.end();it++)
{
(*it)->addTime(evt.timeSinceLastFrame);
}
//create a RayQuery to get the terrain height
//创建一个RayQuery对象去获得地形的高度,RaySceneQuery射线访问方法 //NEGATIVE_UNIT_Y表示标准的2D向量,之间的区别不是很理解
RaySceneQuery* raySceneQuery=mCamera->getSceneManager()->createRayQuery(Ray(Vector3(0,0,0), Vector3::NEGATIVE_UNIT_Y));
//RaySceneQueryResult查询结果迭代器
RaySceneQueryResult::iterator itmove;
RaySceneQueryResult& qryResult=raySceneQuery->execute();//execute()返回查询结果
for (size_t i = 0; i < numMesh; i++)
{
Vector3 position;
position=nodes->getPosition();
position.x+=0.2;
// clamp to terrain
static Ray updateRay;
updateRay.setOrigin(position);
updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y);
raySceneQuery->setRay(updateRay);
RaySceneQueryResult& qryResult = raySceneQuery->execute();
RaySceneQueryResult::iterator k = qryResult.begin();
if (k != qryResult.end() && k->worldFragment)
{
position.y=k->worldFragment->singleIntersection.y+1;//必须最少抬高一个单位的,免得走不了,但是机器人就不在地面上了。
nodes->setPosition(position);
}
}
if( ExampleFrameListener::frameStarted(evt) == false )
return false;
return true;
}
//-----------------------------------------------------------------------
void createEntityGeom();
//-----------------------------------------------------------------------
void destroyEntityGeom();
//-----------------------------------------------------------------------
};
//-----------------------------------------------------------------------
void MyOGREFrameListener::createEntityGeom()
{
size_t k = 0;
size_t y = 0;
//强制容器把它的容量改为至少numRender,提供的numRender不小于当前大小。这一般强迫进行一次重新分配,因为容量需要增加。
//(如果n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。
//在我的经验中,使用reserve来从一个string中修整多余容量一般不如使用“交换技巧”,那是条款17的主题。)
renderEntity.reserve (numMesh);
renderEntity.resize (numMesh);
nodes.reserve (numMesh);
nodes.resize (numMesh);
//create a RayQuery to get the terrain height
//创建一个RayQuery对象去获得地形的高度,RaySceneQuery射线访问方法 //NEGATIVE_UNIT_Y表示标准的2D向量,之间的区别不是很理解
RaySceneQuery* raySceneQuery=mCamera->getSceneManager()->createRayQuery(Ray(Vector3(0,0,0), Vector3::NEGATIVE_UNIT_Y));
//RaySceneQueryResult查询结果迭代器
RaySceneQueryResult::iterator it;
RaySceneQueryResult& qryResult=raySceneQuery->execute();//execute()返回查询结果
for (size_t i = 0; i < numMesh; i++)
{
Vector3 position;
position.x=10*y+500;
position.y=0;
position.z=10*k+500;
//设置一条射线,这条射线就是一个机器人的XZ轴上的位置,Y轴位置用射线获得。
raySceneQuery->setRay (Ray(position, Vector3::UNIT_Y));
raySceneQuery->execute();
it = qryResult.begin();
if (it != qryResult.end() && it->worldFragment)
position.y = it->worldFragment->singleIntersection.y;
//得到相机所在的场景,得到场景根节点,创建一个新的场景节点,靠这个好理解多了,上一个方法,虽然节省点内存,但帧数下降点点
nodes=mCamera->getSceneManager()->getRootSceneNode()->createChildSceneNode("node"+StringConverter::toString(i));
//注册日志消息,用来干马,注册在哪里?又有什么用,体现在哪里?
LogManager::getSingleton().logMessage(":"+nodes->getName());
//创建一股机器人
renderEntity=mCamera->getSceneManager()->createEntity("robot"+StringConverter::toString(i), "robot.mesh");
nodes->attachObject(renderEntity);
nodes->setPosition(position);
nodes->setScale(Vector3(0.1,0.1,0.1));
AnimationState*anim=renderEntity->getAnimationState("Walk");//
animations.push_back(anim);//压入队列是为了方便帧监听进行更新动画帧
anim->setTimePosition(y+k);
anim->setEnabled(true);
y++;
if (y>14)
{
y=0;
k++;
}
}
//设置好以后,就开始删除,零时的对象。
mCamera->getSceneManager()->destroyQuery(raySceneQuery);
}
//-----------------------------------------------------------------------
void MyOGREFrameListener::destroyEntityGeom()
{
size_t i;
size_t j=0;
for (i=0;i<numMesh;i++)
{
LogManager::getSingleton().logMessage(" " +nodes->getName());
LogManager::getSingleton().logMessage(StringConverter::toString(j)+":"+StringConverter::toString(j<numMesh));
String name=nodes->getName();
mCamera->getSceneManager()->destroySceneNode(name);
mCamera->getSceneManager()->destroyEntity(renderEntity);
j++;
}
animations.clear();
}
//-----------------------------------------------------------------------
class MyOGREApplication : public ExampleApplication
{
public:
MyOGREApplication() {}
~MyOGREApplication()
{
}
protected:
virtual void chooseSceneManager(void)
{
// Get the SceneManager, in this case a generic one
//我们必须将场景管理器设为地面的场景管理器,而不是ExampleApplication里默认的那个//
//mSceneMgr = mRoot->createSceneManager("TerrainSceneManager");
mSceneMgr = mRoot->createSceneManager(ST_EXTERIOR_CLOSE);
}
virtual void createCamera(void)
{
// Create the camera
mCamera = mSceneMgr->createCamera(" layerCam");
mCamera->setPosition(700,100, 500);
mCamera->lookAt(600,80,600);
mCamera->setNearClipDistance( 1 );
//mCamera->setFarClipDistance( 1000 );
}
// Just override the mandatory create scene method
void createScene(void)
{
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
//白天的雾--------------------------start
////场景管理器的基类定义了一个叫做setWorldGeometry的方法,使派生类便于创建场景。当使用地面场景管理器(TerrainSceneManager)时,它需要一个文件名来加载地面属性。在createScene函数中添加这行代码
std::string terrain_cfg("terrain.cfg");
mSceneMgr -> setWorldGeometry( terrain_cfg );
//天空穹 看不见
//mSceneMgr->setSkyDome( true, "Examples/CloudySky", 30, 8 );
// Create a skydome
mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);
mSceneMgr->setShadowTextureSize(1024);
}
//-----------------------------------------------------------------------
void createFrameListener(void)
{
// This is where we instantiate our own frame listener
mFrameListener= new MyOGREFrameListener(mWindow, mCamera);
mRoot->addFrameListener(mFrameListener);
}
//-----------------------------------------------------------------------
};
#ifdef __cplusplus
extern "C" {
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
MyOGREApplication app;
try {
app.go();
} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL );
#else
std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
}
return 0;
}
#ifdef __cplusplus
}
#endif
|
|