OGRE的基本五教程.docx
《OGRE的基本五教程.docx》由会员分享,可在线阅读,更多相关《OGRE的基本五教程.docx(37页珍藏版)》请在冰豆网上搜索。
OGRE的基本五教程
-2007-03-31 | Ogre的基本教程
(一)
最近在公司弄的引擎
基础教程1SceneNode,Entity,SceneManager
场景节点,实体,场景管理器
一个空白的应用程序
#include"ExampleApplication.h"
classTutorialApplication :
publicExampleApplication
{
protected:
public:
TutorialApplication()
{
}
~TutorialApplication()
{
}
protected:
voidcreateScene(void)
{
}
};
#ifOGRE_PLATFORM==OGRE_PLATFORM_WIN32
#defineWIN32_LEAN_AND_MEAN
#include"windows.h"
INTWINAPIWinMain(HINSTANCEhInst,HINSTANCE,LPSTRstrCmdLine,INT)
#else
intmain(intargc,char**argv)
#endif
{
TutorialApplicationapp;
try{
app.go();
}catch(Exception&e){
#ifOGRE_PLATFORM==OGRE_PLATFORM_WIN32
MessageBox(NULL,e.getFullDescription().c_str(),
"Anexceptionhasoccured!
",MB_OK|MB_ICONERROR|MB_TASKMODAL);
#else
fprintf(stderr,"Anexceptionhasoccured:
%s\n",
e.getFullDescription().c_str());
#endif
}
return0;
}
引擎是如何工作的
SceneManager(场景管理器)Basics
所有显示的物体都是由SceneManager来管理的。
当你把一个空间物体放入scene(场景)
后SceneManager会追踪他们的位置。
当你创建摄象机(Cameras)来观察场景时,
SceneManager也会跟踪他们。
平面,广告牌,灯光也是一样SceneManager有多种类型,
有渲染地形的管理器,也有渲染BSP的,管理器的列表可以看这里
在教程里,我们还可以进一步了解它
Entity(实体)Basics
Entity是一种可以在场景中渲染的对象.你可以认为Entity是由3Dmeshs(网格)表现的任何物体。
机器人是一个Entity,鱼也是一个Entity,一个角色行走的地形将是一个非常大的
Entity。
但象灯光,广告牌,粒子系统,摄象机就不是Entity需要注释的一点是,引擎是把
renderableobjects(可渲染物体)和他们的位置方向分离的,这意味着你不能直接把一个Entity放到场景里,而是必须把Entity依附到一个SceneNode(场景节点)对象上,SceneNode包含了位置和方向信息
SceneNode(场景节点)Basics
前面已经提到,SceneNode保存了所有附在它上面的物体的位置和方向,当你创建了一个
Entity后,在你把它附在一个SceneNode前是不会被显示出来的。
同样的,SceneNode
并不是显示在屏幕上的对象。
只有你创建一个SceneNode并附上一个Entity或者其他对象时,
才会实际的显示在屏幕上。
SceneNode上可以附加多个对象,比如一个角色走在屏幕中,
你希望能产生一个光在他周围。
你的方法是先创建一个SceneNode,然后给角色创建一个
Entity并附到SceneNode上,然后你可以再创建灯光附在SceneNode上。
SceneNode也必须附在你创建的整个层次节点的SceneNode上。
在随后的教程里会有进一步的讲解。
SceneNodes一个要注释的主要感念就是,它的位置是和父SceneNodes相关的,每个SceneManager都包含一个rootnode(根节点)来让其他SceneNodes附加
你的第一个应用程序
回到前面创建的代码,找到TutorialApplication:
:
createScene成员函数,我们只需要
修改函数里的内容。
第一件要做的是给场景设置一个环境光,好让我们看到我们所做的
我们调用setAmbientLight函数来指定我们需要的颜色,ColourValue结构为0~1的RGB值把这行加createScene里
mSceneMgr->setAmbientLight(ColourValue(1,1,1));
接下来我们需要创建一个Entity,我们用SceneManager的创建Entity的函数
Entity*ent1=mSceneMgr->createEntity("Robot","robot.mesh");
接下来的几个问题,mSceneMgr从何而来我们调用的函数参数又是什么?
mSceneMgr包含了当前的SceneManager对象(这个是由ExampleApplication类来实现的)createEntity的第一个参数是我们创建的Entity的名字。
所有的Entity都必须有独一无二的名字。
如果你
试图创建有相同名字的两个Entity会出错。
"robot.mesh"参数是指你创建的Entity使用
的网格。
我们使用的mesh都由ExampleApplication类来预载现在我们已经创建了Entity,我们需要创建一个SceneNode来让它依附。
因为每个SceneManager都有一个rootSceneNode,我们要给这个node创建一个子节点
SceneNode*node1=
mSceneMgr->getRootSceneNode()->createChildSceneNode("RobotNode");
getRootSceneNode获取当前SceneManager的根节点,createChildSceneNode里的参数为创建的SceneNode的名字,SceneNode不能使用相同的名字。
最后我们需要把Entity附在SceneNode上,让robot可以被渲染出来
node1->attachObject(ent1);
编译和运行你的程序,你可以看到一个机器人站在屏幕上
CoordinatesandVectors(坐标和向量)
在深入了解前,我们要讨论一下坐标和向量对象,一些图形引擎使用X和Z轴来作为水平面
Y轴作为垂直轴。
当你看你的显示器时,X轴会从左向右穿过显示器,右边为X的正方向
Y轴是从显示器的底部到顶部,顶为Y轴的正方向,Z轴是从屏幕里面穿出来,屏幕外为Z的正方向(右手坐标系)注意我们的Robot为什么面向X正方向?
这是网格自己的属性,是有意这么设计的。
引擎并没有假定你模型的朝向。
你装载的每个Mesh都可能有它超向的startingdirection(开始方向)引擎使用Vector(向量)类来表现位置和方向(没有点类),向量定义为2(Vector2),3(Vector3),4(Vector4)维向量,Vector3是最常用的。
AddinganotherObject(增加另一个对象)
现在你明白坐标系统是如何工作的了,我们回到代码里,我们写的3行代码里,并没有指定
机器人所想显示的位置。
引擎的大部分函数都有它的默认参数
比如SceneNode:
:
createChildSceneNode函数有3个参数SceneNode的名字,SceneNode的位置,SceneNode朝向的旋转方向,位置你也看到了,用的是坐标coordinates(0,0,0).我们创建另一个SceneNode,这次我们指定一个起始位置
Entity*ent2=
mSceneMgr->createEntity("Robot2","robot.mesh");
SceneNode*node2=mSceneMgr->getRootSceneNode()->createChildSceneNode
("RobotNode2",Vector3(50,0,0));
node2->attachObject(ent2);
看上去和前面的代码很相似,但有2点不同,首先SceneNode和Entity的名字有些不同
其次,在开始位置上,我们指定了距离场景根节点X方向50个单位(所有的SceneNode
位置都是和他父亲相关的),编译程序,我们有了两个并排的机器人
进一步了解Entity
Entity类是非常广泛的,我不可能在这里覆盖到它的各部分,但足够你可以起步了这里指出一些常用的函数第一个是Entity:
:
setVisible和Entity:
:
isVisible.你可以设置一个Entity是否可见通过调用这个函数。
如果你需要隐藏一个Entity或者稍后再显示它,那么可以调用这函数,而不是销毁掉这个Entity然后稍后再创建它。
任何实体只有一个mesh和texture的拷贝在内存中。
所以不需要自己进行管理,getName可以获得Entity的名字,getParentSceneNode获得Entity所依附的SceneNode
进一步了解SceneNode
SceneNode类是非常复杂的,SceneNode可以做的事很多,下面列出一些最常用的你可以调用getPositionandsetPosition来设置和获得一个SceneNode的位置,通过调用translate让他相对于当前位置移动,SceneNode不光能设置位置,还有对象的缩放和旋转,调用scale来缩放,调用yaw,roll,和pitch函数来旋转。
使用resetOrientation来重置对象的旋转,也可以使用setOrientation,getOrientation,和rotate来实现更高级的旋转。
四元数会在后面的教程里提出,你已经看到了attachObject函数,同样可以用来操作附加在SceneNode上节点的相关函数有numAttachedObjects,getAttachedObject(有多个版本)detachObject(也有多个版本)detachAllObjects。
可以处理所有的parentSceneNode和childSceneNode。
因为所有的位置和平移都是相对于父SceneNode的,所以我们可以很简单的让两个SceneNode一起移动。
我们程序当前的代码
Entity*ent1=mSceneMgr->createEntity("Robot","robot.mesh");
SceneNode*node1=
mSceneMgr->getRootSceneNode()->createChildSceneNode("RobotNode");
node1->attachObject(ent1);
Entity*ent2=mSceneMgr->createEntity("Robot2","robot.mesh");
SceneNode*node2=mSceneMgr->getRootSceneNode()->createChildSceneNode
("RobotNode2",Vector3(50,0,0));
node2->attachObject(ent2);
如果我们替换第6行程序
SceneNode*node2=mSceneMgr->getRootSceneNode()->createChildSceneNode
("RobotNode2",Vector3(50,0,0));
为
SceneNode*node2=node1->createChildSceneNode("RobotNode2",
Vector3(50,0,0));
然后我们让RobotNode2为RobotNode的一个子节点,移动node1时,node2也会跟着移动,但移动node2不会影响node1,例如下面的代码,我们只移动node2
node2->translate(Vector3(10,0,10));
下面的代码我们移动RobotNode,因为RobotNode2是子节点,所以也会移动
node1->translate(Vector3(25,0,0));
然后,通过getSceneNode和getEntity的方法就可以通过名字获得SceneManager里所有SceneNode和Entity,因此,你不需要保存你创建的SceneNode的所有指针。
尝试去做
现在,你基本掌握了Entities(实体),SceneNodes(场景节点),和SceneManager
(场景管理器)。
我建议从上面的代码开始,在场景里增加或去除Robots。
然后清除掉createScene里的所有内容,然后运行下面各个代码段。
Scale
你可以通过调用SceneNodes的scale方法来缩放网格,
Entity*ent=mSceneMgr->createEntity("Robot","robot.mesh");
SceneNode*node=
mSceneMgr->getRootSceneNode()->createChildSceneNode("RobotNode");
node->attachObject(ent);
node->scale(.5,1,2);
ent=mSceneMgr->createEntity("Robot2","robot.mesh");
node=mSceneMgr->getRootSceneNode()->createChildSceneNode
("RobotNode2",Vector3(50,0,0));
node->attachObject(ent);
node->scale(1,2,1);
Rotations
你可以旋转对象通过yaw,pitch,roll的方法来决定是按角度还是弧度来旋转,Pitch是绕X轴旋转,Yaw是绕Y轴旋转Roll是绕Z轴旋转,使用你的右手做指引,拇指为轴,其他手指为正旋转方向。
例如,Pitch(90),将你的拇指指向右,其他手指就为旋转的方向
Entity*ent=mSceneMgr->createEntity("Robot","robot.mesh");
SceneNode*node=mSceneMgr->getRootSceneNode()->createChildSceneNode
("RobotNode",Vector3(-100,0,0));
node->attachObject(ent);
node->yaw(Degree(-90));
ent=mSceneMgr->createEntity("Robot2","robot.mesh");
node=
mSceneMgr->getRootSceneNode()->createChildSceneNode("RobotNode2");
node->attachObject(ent);
node->pitch(Degree(-90));
ent=mSceneMgr->createEntity("Robot3","robot.mesh");
node=mSceneMgr->getRootSceneNode()->createChildSceneNode
("RobotNode3",Vector3(100,0,0));
node->attachObject(ent);
node->roll(Degree(-90));
总结
你可以基本了解SceneManager,SceneNode,Entity类,你不必熟悉上面提供的所有函数,
因为这只是最基本的对象,我们会使用很频繁,通过学习后面的教程,你可以进一步来熟悉这些。
2007-03-31 | Ogre的基础教程
(二)
BeginnerTutorial2:
Cameras,Lights,andShadows
摄象机,光和阴影
介绍
这个教程会向你介绍一些引擎里的结构,就好象之前学过的,这个教程主要讲解引擎里的光对象
和如果使用它们来创建引擎。
也包括了摄象机的基础知识
通过这个教程,你可以慢慢加代码到你的工程,并看见到创建的结果
开始
在上一个教程,我们使用一个预先创建好的代码最起始点,我们将增加两个方法到我们的
TutorialApplication类里:
createViewport和createCamera这两个函数已经定义在基类
ExampleApplication里,在这个教程里我们来看他们怎么创建和使用CamerasandViewports
创建工程,增加包含这个代码的的源文件:
#include"ExampleApplication.h"
classTutorialApplication:
publicExampleApplication
{
protected:
public:
TutorialApplication()
{
}
~TutorialApplication()
{
}
protected:
virtualvoidcreateCamera(void)
{
}
virtualvoidcreateViewports(void)
{
}
voidcreateScene(void)
{
Entity*ent;
Light*light;
}
};
#ifX3D_PLATFORM==PLATFORM_WIN32||X3D_PLATFORM==X3D_PLATFORM_WIN32
#defineWIN32_LEAN_AND_MEAN
#include"windows.h"
INTWINAPIWinMain(HINSTANCEhInst,HINSTANCE,LPSTRstrCmdLine,INT)
#else
intmain(intargc,char**argv)
#endif
{
//Createapplicationobject
TutorialApplicationapp;
try{
app.go();
}catch(Exception&e){
#ifX3D_PLATFORM==PLATFORM_WIN32||X3D_PLATFORM==X3D_PLATFORM_WIN32
MessageBox(NULL,e.getFullDescription().c_str(),"Anexceptionhasoccured!
",
MB_OK|MB_ICONERROR|MB_TASKMODAL);
#else
fprintf(stderr,"Anexceptionhasoccured:
%s\n",
e.getFullDescription().c_str());
#endif
}
return0;
}
Camera
引擎摄象机(Camera)
Camera(摄象机)是我们创建来观察场景的,Camera的工作和SceneNode(场景节点)类似,Camera对象有setPosition,yaw,roll和pitch函数,你可以把它附加在SceneNode上。
就象SceneNode一样,Camera的位置也和它的父亲相关。
象移动和旋转,你都可以认为一个Camera一个SceneNode。
这个引擎的Camera与你预想不同的一点是一次只能有一个Camera。
就是说,我们不能为观察场景的一部分创建一个Camera,再创建另一个Camera来观察场景的其他部分,然后在通过enabling或disablingCamera来显示我们想要的场景位置。
但有一种替代的方法,创建一个SceneNode来作为"cameraholders"。
这个SceneNode可以简单的设置在场景的位置和指向你想看的方向。
当要显示场景的一部分时,只需要Camera附加在合适的SceneNode,我们会再看到这个技术在FrameListener的教程里
创建摄象机(Camera)
我们将覆盖ExampleApplication里常用的创建Camera的默认方法
找到TutorialApplication:
:
createCamera的成员函数,我们首先要做的是创建Camera
因为Camera是依赖他们所在的SceneManager,我们使用SceneManager对象来创建他们
增加下面这行代码来创建Camera:
//createthecamera
mCamera=mSceneMgr->createCamera("PlayerCam");
创建一个叫"PlayerCam"的Camera,我们可以使用SceneManger的getCamera函数,通过Camera的名字来获得Camera。
下一件事将要设置Camera的位置和它的朝向,我们将空间对象放在原点附近,因此我们给Camera设置一个好的距离在+Z方向上,摄象机将朝向原点,把这个加在上面代码的后面。
//setitsposition,direction
mCamera->setPosition(Vector3(0,10,500));
mCamera->lookAt(Vector3(0,0,0));
lookAt函数是很灵活的,你可以将Camera朝向任何位置来代替yaw,rotate,和pitch,SceneNode也有这个函数,可以简单的设置Entity朝向任何方向在各种情况下。
最后我们要设置nearclippingdistance为5个单位,clippingdistance指定一个Camera多近和多远以外的物体不再看到。
设置nearclippingdistance可以让你看穿屏幕上的Entity当你非常接近它们时。
当你距离一个物体很近时,它会充满整个屏幕,你只能看到它的很少一部分。
你可以同样设置farclippingdistance,这样引擎就不会渲染比这个值远的任何事物。
它的主要作用是增加刷新率,如果你渲染远距离大数量物体到屏幕上。
设置nearc