Ogre2中级教材.docx

上传人:b****8 文档编号:23883430 上传时间:2023-05-21 格式:DOCX 页数:17 大小:22.63KB
下载 相关 举报
Ogre2中级教材.docx_第1页
第1页 / 共17页
Ogre2中级教材.docx_第2页
第2页 / 共17页
Ogre2中级教材.docx_第3页
第3页 / 共17页
Ogre2中级教材.docx_第4页
第4页 / 共17页
Ogre2中级教材.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

Ogre2中级教材.docx

《Ogre2中级教材.docx》由会员分享,可在线阅读,更多相关《Ogre2中级教材.docx(17页珍藏版)》请在冰豆网上搜索。

Ogre2中级教材.docx

Ogre2中级教材

文档:

教程:

中级教程:

中级教程二

出自Ogre3D开放资源地带

跳转到:

导航,搜索

中级教程2:

射线场景查询及基础鼠标用法

有关这篇教程,无论遇到任何问题,都可以到论坛发帖寻求帮助。

目录

[隐藏]

∙1介绍

∙2前期准备

∙3开始

∙4创建场景

∙5帧监听器介绍

∙6创建帧监听器

∙7增加鼠标查看

∙8地形碰撞检测

∙9地形选择

∙10进阶练习

o10.1简单练习

o10.2中级练习

o10.3高级练习

o10.4进阶练习

介绍

本教程中,我们会初步创建一个基础场景编辑器。

在过程之中,我们会涉及到:

1.如何使用RaySceneQueries阻止镜头穿透地面

2.如何使用MouseListener和MouseMotionListener接口

3.使用鼠标选取地面上的x和y坐标

你可以在这里找到完整代码。

跟随着教程,你会慢慢地向你自己的工程项目中增加代码,并且随着编译看到结果。

前期准备

本教程假设你已经知道了如何创建Ogre工程,并且可以成功编译。

假设你已经了解了基本的Ogre对象(场景节点,实体,等等)。

你也应该熟悉STL迭代器基本的使用方法,因为本教程会用到。

(Ogre也大量用到STL,如果你还不熟悉STL,那么你需要花些时间学习一下。

开始

首先,你需要为此演示程序创建一个新工程。

在创建工程时,选空工程、自己的框架,以及初始化进度条和CEGUI支持,不选编译后拷贝。

向工程中,增加一个名叫“MouseQuery.cpp”的文件,并向其中添加如下代码:

#include

#include

#include

#include"ExampleApplication.h"

classMouseQueryListener :

publicExampleFrameListener,publicOIS:

:

MouseListener

{

public:

MouseQueryListener(RenderWindow*win,Camera*cam,SceneManager*sceneManager,CEGUI:

:

Renderer*renderer)

:

ExampleFrameListener(win,cam,false,true),mGUIRenderer(renderer)

{

}//MouseQueryListener

~MouseQueryListener()

{

}

boolframeStarted(constFrameEvent&evt)

{

returnExampleFrameListener:

:

frameStarted(evt);

}

/*MouseListenercallbacks.*/

boolmouseMoved(constOIS:

:

MouseEvent&arg)

{

returntrue;

}

boolmousePressed(constOIS:

:

MouseEvent&arg,OIS:

:

MouseButtonIDid)

{

returntrue;

}

boolmouseReleased(constOIS:

:

MouseEvent&arg,OIS:

:

MouseButtonIDid)

{

returntrue;

}

 

protected:

RaySceneQuery*mRaySceneQuery;//Therayscenequerypointer

boolmLMouseDown,mRMouseDown;//Trueifthemousebuttonsaredown

intmCount;//Thenumberofrobotsonthescreen

SceneManager*mSceneMgr;//Apointertothescenemanager

SceneNode*mCurrentObject;//Thenewlycreatedobject

CEGUI:

:

Renderer*mGUIRenderer;//CEGUIrenderer

};

classMouseQueryApplication :

publicExampleApplication

{

protected:

CEGUI:

:

OgreCEGUIRenderer*mGUIRenderer;

CEGUI:

:

System*mGUISystem;//ceguisystem

public:

MouseQueryApplication()

{

}

~MouseQueryApplication()

{

}

protected:

voidchooseSceneManager(void)

{

//Usetheterrainscenemanager.

mSceneMgr=mRoot->createSceneManager(ST_EXTERIOR_CLOSE);

}

voidcreateScene(void)

{

}

voidcreateFrameListener(void)

{

mFrameListener=newMouseQueryListener(mWindow,mCamera,mSceneMgr,mGUIRenderer);

mFrameListener->showDebugOverlay(true);

mRoot->addFrameListener(mFrameListener);

}

};

 

#ifOGRE_PLATFORM==PLATFORM_WIN32||OGRE_PLATFORM==OGRE_PLATFORM_WIN32

#defineWIN32_LEAN_AND_MEAN

#include"windows.h"

INTWINAPIWinMain(HINSTANCEhInst,HINSTANCE,LPSTRstrCmdLine,INT)

#else

intmain(intargc,char**argv)

#endif

{

//Createapplicationobject

MouseQueryApplicationapp;

try{

app.go();

}catch(Exception&e){

#ifOGRE_PLATFORM==OGRE_PLATFORM_WIN32

MessageBox(NULL,e.getFullDescription().c_str(),"Anexceptionhasoccurred!

",MB_OK|MB_ICONERROR|MB_TASKMODAL);

#else

fprintf(stderr,"Anexceptionhasoccurred:

 %s\n",

e.getFullDescription().c_str());

#endif

}

return0;

}

在继续下面教程以前,先确保上面代码可以正常编译。

创建场景

找到MouseQueryApplication:

:

createScene方法。

下面的代码应该都很熟悉了。

如果你不知道其中某些是做什么用的,请在继续本教程前,参考OgreAPI。

向createScene中,增加如下代码:

//Setambientlight

mSceneMgr->setAmbientLight(ColourValue(0.5,0.5,0.5));

mSceneMgr->setSkyDome(true,"Examples/CloudySky",5,8);

//Worldgeometry

mSceneMgr->setWorldGeometry("terrain.cfg");

//Setcameralookpoint

mCamera->setPosition(40,100,580);

mCamera->pitch(Degree(-30));

mCamera->yaw(Degree(-45));

既然我们建立了基本的世界空间,那么就要打开光标。

打开光标,要使用CEGUI函数调用。

不过在此之前,我们需要启用CEGUI。

我们首先创建一个OgreCEGUIRenderer,然后创建系统对象并将刚创建的Renderer传给它。

创建CEGUI我们会专门留待后续教程介绍,现在只要知道创建mGUIRenderer时必须以最后一个参数告诉CEGUI你要用那个场景管理器。

//CEGUIsetup

mGUIRenderer=newCEGUI:

:

OgreCEGUIRenderer(mWindow,Ogre:

:

RENDER_QUEUE_OVERLAY,false,3000,mSceneMgr);

mGUISystem=newCEGUI:

:

System(mGUIRenderer);

现在我们需要实际显示光标了。

同样地,我不打算过多解释这些代码。

我们会在后面的教程中详细介绍。

(其实也没什么,就是设置了一下CEGUI的窗口和鼠标的样式。

——Aaron注释)

//Mouse

CEGUI:

:

SchemeManager:

:

getSingleton().loadScheme((CEGUI:

:

utf8*)"TaharezLookSkin.scheme");

CEGUI:

:

MouseCursor:

:

getSingleton().setImage("TaharezLook","MouseArrow");

如果你编译并运行这个程序,你会发现一个光标出现在屏幕中央,但它还动不了。

帧监听器介绍

这是程序要做的全部事情。

FrameListener是代码中复杂的部分,所以我会花一些时间强调我们要完成的东西,以便在我们开始实现它之前,使你有一个大体的印象。

∙首先,我们想要将鼠标右键绑定到“鼠标观察”模式。

不能使用鼠标四下看看是相当郁闷的,所以我们首先对程序增加鼠标控制(尽管只是在我们保持鼠标右键按下时)。

∙第二,我们想要让镜头不会穿过地表。

这会使它更接近我们期望的样子。

∙第三,我们想要在地表上用鼠标左键点击一下,就在那里增加一个实体。

∙最后,我们想要能“拖拽”实体。

即选中我们想要看到的实体,按住鼠标左键不放,将它移动到我们想要放置的地方。

松开鼠标左键,就又会将它锁定在原地。

要做到这几点,我们要使用几个受保护的变量(这些已经加到类中了):

RaySceneQuery*mRaySceneQuery;//射线场景查询指针

boolmLMouseDown,mRMouseDown;//如果按下鼠标按钮,返回True

intmCount;//屏幕上机器人的数量

SceneManager*mSceneMgr;//指向场景管理器的指针

SceneNode*mCurrentObject;//新创建的物休

CEGUI:

:

Renderer*mGUIRenderer;//CEGUI渲染器

变量mRaySceneQuery握有RaySceneQuery的一个拷贝,我们会它来寻找地面上的坐标。

变量mLMouseDown和mRMouseDon会追踪我们是否按下鼠标键(例如:

如果按下鼠标左键,则mLMouseDown为true;否则,为false)。

mCount计数屏幕上有的实体数。

mCurrentObject握有指向最近创建的场景节点的指针(我们将用这个“拖拽”实体)。

最后,mGUIRenderer握有指向CEGUIRenderer的指针,我们将用它更新CEGUI。

还要注意的是,有许多和鼠标监听器相关的函数。

在本演示程序中,我们不会全部用到,但是它们必须全部在那儿,否则编译会报错说你没定义它们。

创建帧监听器

找到MouseQueryListener构造函数,增加如下初始化代码。

注意,由于地形相当小,所以我们也要减少移动和旋转速度。

//Setupdefaultvariables

mCount=0;

mCurrentObject=NULL;

mLMouseDown=false;

mRMouseDown=false;

mSceneMgr=sceneManager;

//Reducemovespeed

mMoveSpeed=50;

mRotateSpeed/=500;

为了MouseQueryListener能收到鼠标事件,我们必须把它注册为一个鼠标监听器。

如果对此不太熟悉,请参考基础教程5。

//Registerthissothatwegetmouseevents.

mMouse->setEventCallback(this);

最后,在构造函数中我们需要创建一个RaySceneQuery对象。

用场景管理器的一个调用创建:

//CreateRaySceneQuery

mRaySceneQuery=mSceneMgr->createRayQuery(Ray());

这是我们需要的全部构造函数了,但是如果我们创建一个RaySceneQuery,以后我们就必须销毁它。

找到MouseQueryListener析构函数(~MouseQueryListener),增加如下代码:

//Wecreatedthequery,andwearealsoresponsiblefordeletingit.

mSceneMgr->destroyQuery(mRaySceneQuery);

在进入下一阶段前,请确保你的代码可以正常编译。

增加鼠标查看

我们要将鼠标查看模式绑定到鼠标右键上,需要:

∙当鼠标被移动时,更新CEGUI(以便光标也移动)

∙当鼠标右键被按下时,设置mRMouseButton为true

∙当鼠标右键被松开时,设置mRMouseButton为false

∙当鼠标被“拖拽”时,改变视图

∙当鼠标被“拖拽”时,隐藏鼠标光标

找到MouseQueryListener:

:

mouseMoved方法。

我们将要增加代码使每次鼠标移动时移动鼠标光标。

向函数中增加代码:

//UpdateCEGUIwiththemousemotion

CEGUI:

:

System:

:

getSingleton().injectMouseMove(arg.state.X.rel,arg.state.Y.rel);

现在找到MouseQueryListener:

:

mousePressed方法。

这段代码当鼠标右键按下时,隐藏光标,并设置变量mRMouseDown为true。

//Leftmousebuttondown

if(id==OIS:

:

MB_Left)

{

mLMouseDown=true;

}//if

//Rightmousebuttondown

elseif(id==OIS:

:

MB_Right)

{

CEGUI:

:

MouseCursor:

:

getSingleton().hide();

mRMouseDown=true;

}//elseif

接下来,当鼠标右键抬起时,我们需要再次显示光标,并将mRMouseDown设置为false。

找到mouseReleased函数,增加如下代码:

//Leftmousebuttonup

if(id==OIS:

:

MB_Left)

{

mLMouseDown=false;

}//if

//Rightmousebuttonup

elseif(id==OIS:

:

MB_Right)

{

CEGUI:

:

MouseCursor:

:

getSingleton().show();

mRMouseDown=false;

}//elseif

现在,我们有了全部准备好的代码,我们想要在按住鼠标右键移动鼠标时改变视图。

我们要做的就是,读取他自上次调用方法后移动的距离。

这可以用与基础教程5中旋转摄像机镜头一样的方法实现。

找到TutorialFrameListener:

:

mouseMoved函数,就在返回状态前,增加如下代码:

//Ifwearedraggingtheleftmousebutton.

if(mLMouseDown)

{

}//if

//Ifwearedraggingtherightmousebutton.

elseif(mRMouseDown)

{

mCamera->yaw(Degree(-arg.state.X.rel*mRotateSpeed));

mCamera->pitch(Degree(-arg.state.Y.rel*mRotateSpeed));

}//elseif

现在如果你编译并运行这些代码,你将能够通过按住鼠标右键控制摄像机往哪里看。

地形碰撞检测

我们现在要实现它,以便当我们向着地面移动时,能够不穿过地面。

因为BaseFrameListener已经处理了摄像机移动,所以我们就不用碰那些代码了。

替代地,在BaseFrameListener移动了摄像机后,我们要确保摄像机在地面以上10个单位处。

如果它不在,我们要把它移到那儿。

请跟紧这段代码。

我们将在本教程结束前使用RaySceneQuery做几件别的事,而且在这段结束后,我不会再做如此详细的介绍。

找到MouseQueryListener:

:

frameStarted方法,移除该方法的全部代码。

我们首先要做的事是调用ExampleFrameListener:

:

frameStarted方法。

如果它返回false,则我们也会返回false。

//Processthebaseframelistenercode.Sincewearegoingtobe

//manipulatingthetranslatevector,weneedthistohappenfirst.

if(!

ExampleFrameListener:

:

frameStarted(evt))

returnfalse;

我们在frameStarted函数的最开始处做这些,是因为ExampleFrameListener的frameStarted成员函数移动摄像机,并且在此发生后我们需要在函数中安排我们的剩余行动。

我们的目标及时找到摄像机的当前位置,并沿着它向地面发射一条射线。

这被称为射线场景查询,它会告诉我们我们下面的地面的高度。

得到了摄像机的当前位置后,我们需要创建一条射线。

这条射线有一个起点(射线开始的地方),和一个方向。

在本教程的情况下,我们的方向是Y轴负向,因为我们指定射线一直向下。

一旦我们创建了射线,我们就告诉RaySceneQuery对象使用它。

//Setupthescenequery

Vector3camPos=mCamera->getPosition();

RaycameraRay(Vector3(camPos.x,5000.0f,camPos.z),Vector3:

:

NEGATIVE_UNIT_Y);

mRaySceneQuery->setRay(cameraRay);

注意,我们已经使用了5000.0f高度代替了摄像机的实际位置。

如果我们使用摄像机的Y坐标代替这个高度,如果摄像机在地面以下,我们会错过整个地面。

现在我们需要执行查询,得到结果。

查询结果是std:

:

iterator类型的。

//Performthescenequery

RaySceneQueryResult&result=mRaySceneQuery->execute();

RaySceneQueryResult:

:

iteratoritr=result.begin();

在本教程中的这个地形条件下,查询结果基本上是一个worldFragment的列表和一个可移动物体(稍后的教程会介绍到)的列表。

如果你对STL迭代器不太熟悉,只要知道调用begin方法获得迭代器的第一个元素。

如果result.begin()==result.end(),那么无返回结果。

在下一个演示程序里,我们将处理SceneQuery的多个返回值。

目前,我们只要挥挥手,在其间移动。

下面的这行代码保证了至少返回一个查询结果(itr !

=result.end()),那个结果是地面(itr->worldFragment)。

//Gettheresults,setthecameraheight

if(itr !

=result.end()&&itr->worldFragment)

{

worldFragment结构包含有在变量singleIntersection(一个Vector3)中射线击中地面的位置。

我们要得到地面的高度,依靠将这个向量的Y值赋值给一个本地变量。

一旦我们有了高度,我们就要检查摄像机是否低于这一高度,如果低于这一高度,那么我们要将摄像机向上移动至地面高度。

注意,我们实际将摄像机多移动了10个单位。

这样保证我们不能由于太靠近地面而看穿地面。

RealterrainHeight=itr->worldFragment->singleIntersection.y;

if((terrainHeight+10.0f)>camPos.y)

mCamera->setPosition(camPos.x,terrainHeight+10.0f,camPos.z);

}

returntrue;

最后,我们返回true,继续渲染。

此时,你应该编译测试你的程序了。

地形选择

在这部分中,每次点击鼠标左键,我们将向屏幕上创建和添加对象。

每次你点击、按住鼠标左键,就会创建一个对象并跟随你的光标。

你可以移动对象,直到你松开鼠标左键,同时对象也锁定在那一点上。

要做到这些,我们需要改变mousePressed函数。

在MouseQueryLlistener:

:

mousePressed函数中,找到如下代码。

我们将要在这个if语句中增加一些代码。

//Leftmousebuttondown

if(id==OIS:

:

MB_Left)

{

mLMouseDown=true;

}//if

第一段代码看起来会很熟悉。

我们会创建一条射线以供mRaySceneQuery对象使用,设置射线。

Ogre给我们提供了Camera:

:

getCameraToVie

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1