Ogre三维框架基础篇(一)

Ogre场景示例

SceneManager

在写代码前要先明白一些概念。首先是SceneManager,我称之为场景管理器。它是管理所有出现在屏幕上的东西,比如模型,比如光源,比如摄像头。场景管理器也有不同的类型,具体的类型可以查看这里SceneManagers FAQ .
SceneManager

SceneNode

SceneNode保存着与之相连的模型信息,一个模型只有与SceneNode绑定后才能被渲染出来。相对的,SceneNode没有对象与之绑定的话也是无法在屏幕上渲染出来的。SceneNode携带一些比如位置,缩放,旋转等信息用于对绑定对象进行简单的处理。
SceneNode作为一个节点存在在整个节点树中,所有节点组成一棵庞大的树,我们可以不断向树里面添加节点。

1
2
mSceneMgr->getRootSceneNode()//获得根节点
mSceneMgr->getRootSceneNode()->createChildSceneNode("Node");//在根节点上生成一个新的子节点,并赋予姓名“Node”.

还有一点是节点与其父节点关系是相对的。
比如说现在RootNode坐标为(0,0,0),Node1作为RootNode的子节点坐标为(0,0,0),Node2作为Node1的子节点坐标为(10,20,30)。现在将Node1的坐标改为(10,10,10),则Node2的坐标也会相应的变为(20,30,40)。

场景代码

在createScene方法中加入以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//创建视图-------------------------------------------------------------------------------------
void TutorialApplication::createScene(void)
{
// create your scene here :)
// Set the scene's ambient light 设置环境光源的亮度 默认为0不可见,故一定要加上这句
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5f, 0.5f, 0.5f));
//移动摄像头的位置
mCamera->setPosition(0, 47, 222);
//生成模型
Ogre::Entity* ogreEntity = mSceneMgr->createEntity("MyEntity", "ogrehead.mesh");
//创建子场景结点并加入结点树中
Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node1");
//设置结点位置
//node->setPosition(10,0,0);
//将模型与场景结点绑定使其可见
node->attachObject(ogreEntity);
//建立点光源,位置为20,80,50
Ogre::Light* light = mSceneMgr->createLight("MainLight");
light->setPosition(20.0f, 80.0f, 50.0f);

//现在建立第二个模型,使用构造函数直接指定坐标
Ogre::Entity* ogreEntity2 = mSceneMgr->createEntity("SecondEntity","ogrehead.mesh");
Ogre::SceneNode* node2 = mSceneMgr->getRootSceneNode()->createChildSceneNode("Node2",Ogre::Vector3(84,48,0));
node2->attachObject(ogreEntity2);

//建立第三个模型,用于缩放
Ogre::Entity* ogreEntity3 = mSceneMgr->createEntity("ogrehead.mesh");
Ogre::SceneNode* ogreNode3 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
ogreNode3->setPosition(0, 104, 0);
ogreNode3->setScale(2, 1.2, 1); //x轴上放大为普通的两倍,y轴1.2倍,z轴不变
ogreNode3->attachObject(ogreEntity3);

//建立第四个模型,用于旋转
Ogre::Entity* ogreEntity4 = mSceneMgr->createEntity("ogrehead.mesh");
Ogre::SceneNode* ogreNode4 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
ogreNode4->setPosition(-84, 48, 0);
//基于正方向,顺时针
ogreNode4->roll(Ogre::Degree(-90));//逆时针90度
ogreNode4->attachObject(ogreEntity4);
}

运行截图

XYZ坐标&缩放

XYZ坐标
如图所示,基本上所有的三维编程都是基于这个标准设定三维空间。

旋转

旋转
想象自己作为原点,向各轴正方向看去,以顺时针为正方向,逆时针为负方向。

###文件配置
plugins.cfg是加载插件的配置文件。
resources.cfg是加载资源文件的配置文件。
ogre.cfg是整个Ogre系统的配置文件。
它们存在于../bin/debug or release 文件夹下。
详细的内容在官方WIKI上。

Ogre的显示

Camera——Ogre摄像头

BaseApplication中的createCamera()就是创建摄像头,现在我们在TutorialApplication类中重写createCamera()方法。

1
2
//TutorialApplication.h中加入
virtual void createCamera();

1
2
3
4
//TutorialApplication.cpp中加入
void TutorialApplication::createCamera()
{
}

createCamera中的代码,其中SDKCameraMan用于控制摄像头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//创建摄像头--------------------
void TutorialApplication::createCamera(void){
//创建一个名为“PlayerCam”的摄像头
mCamera = mSceneMgr->createCamera("PlayerCam");
//设定摄像头位置
mCamera->setPosition(Ogre::Vector3(0, 300, 500));
//摄像头朝向
mCamera->lookAt(Ogre::Vector3(0, 0, 0));
//盲区为5,即是说在5单位里面的mesh都将不会被渲染
mCamera->setNearClipDistance(5);
//SDKCameraMan是一个摄像头控制器
mCameraMan = new OgreBites::SdkCameraMan(mCamera);
//以上这些变量都是在BaseApplication中定义,同样也在其析构函数中释放变量的内存
}

Viewports——视图监视器

Viewports是用于处理多摄像头时的情况。可用于分屏和迷你地图。一个Viewport是对一个Camera所拍摄到的场景的反映,所以一个Viewport只能绑定一个Camera。而一个Camera所拍摄到的场景可以通过多个Viewport反映到不同的区域,所以一个Camera则可以绑定多个Viewport。一个Camera同时只可以拍摄一个场景,所以一个Camera只可以绑定一个场景。一个场景可以由多个观察者去观察,所以它可以绑定多个Camera。
我们打个比方吧,将一个酒店大厅作为一个Scene,它同时被多台监视器监控,那么监视器就是camera,在监控室中,每个监视器反馈到不同的屏幕上,如此一个屏幕就作为一个Viewport,而整个监控室就相当于整个程序的窗口。
同样重写BaseApplication中的createViewports()方法

1
2
//TutorialApplication.h中加入
virtual void createViewports();

1
2
3
4
//TutorialApplication.cpp中加入
void TutorialApplication::createViewports()
{
}

createViewports中添加代码

1
2
3
4
5
6
7
8
9
10
11
//创建可视区域--------------
void TutorialApplication::createViewports(void){
//一个视图监视器,将其与一个摄像机绑定
Ogre::Viewport* vp = mWindow->addViewport(mCamera);
//设置背景颜色为黑
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));

//窗口的纵横比,使其与Camera的宽高比相同
mCamera->setAspectRatio(
Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
}

创建一个Plane模型

我们现在要做的是不通过导入mesh数据凭空建一个模型,当然是一个最简单的模型——平面模型,并加上材质贴图。
首先,新建一个Plane实例

1
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);

Plane朝向
然后通过MeshManager来建立一个平面模型。MeshManager是管理所有mesh资源的一个类。

1
2
3
4
5
6
7
8
Ogre::MeshManager::getSingleton().createPlane(
"ground",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
plane,
1500, 1500, 20, 20,
true,
1, 5, 5,
Ogre::Vector3::UNIT_Z);

其中各个参数的含义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
OgreMeshManager.h 中定义:

Mesh * Ogre::MeshManager::createPlane (
const String & name, // 平面模型的名称   
const Plane & plane, // 所使用的平面定义的名称   
Real width, // 平面宽度 (X 方向)   
Real height, // 平面高度 (Y 方向)   
int xsegments = 1, // X 方向分割数目   
int ysegments = 1, // Y 方向分割数目   
bool normals = true, // 是否创建垂直于平面的法线   
int numTexCoordSets = 1, // 纹理坐标集的数目(也就是多层纹理的层数)   
Real uTile = 1.0f, // U 方向纹理铺嵌行数   
Real vTile = 1.0f, // V 方向纹理铺嵌行数   
const Vector3 & upVector = Vector3::UNIT_Y,   // 上方向法线,指示平面的正面朝向   
HardwareBuffer::Usage vertexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY, // 顶点缓存用途   
HardwareBuffer::Usage indexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY,   // 索引缓存用途   
bool vertexShadowBuffer = true, // 顶点阴影缓存   
bool indexShadowBuffer = true // 索引阴影缓存  

)
*/

最后通过mSceneMgr来调用

1
2
3
4
//设置平面模型的材质
groundEntity->setMaterialName("Examples/Rockwall");
Ogre::Entity* groundEntity = mSceneMgr->createEntity("ground");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);

灯光&投影

灯光在Ogre中可以分为三种类型

Ogre::Light::LT_POINT - 点光源,类似于电灯泡
Ogre::Light::LT_SPOTLIGHT - 投射光源,类似于手电筒
Ogre::Light::LT_DIRECTIONAL - 平行光源,类似与太阳光

三种类型光源的调用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//阴影投射技术
mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);

//光柱
Ogre::Light* spotLight = mSceneMgr->createLight("SpotLight");
//漫反射
spotLight->setDiffuseColour(0, 0, 1.0);
//镜面反射
spotLight->setSpecularColour(0, 0, 1.0);
//设置光源的类型为光柱(类似手电筒的投射光)
spotLight->setType(Ogre::Light::LT_SPOTLIGHT);
//灯光投射方向,此处为x,y轴45度方向处。
spotLight->setDirection(-1, -1, 0);
//灯光位置
spotLight->setPosition(Ogre::Vector3(200, 200, 0));

Ogre::Light* directionalLight = mSceneMgr->createLight("DirectionalLight");
//设置灯光类型为平行光
directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
directionalLight->setDiffuseColour(Ogre::ColourValue(.4, 0, 0));
directionalLight->setSpecularColour(Ogre::ColourValue(.4, 0, 0));
directionalLight->setDirection(Ogre::Vector3(0, -1, 1));

Ogre::Light* pointLight = mSceneMgr->createLight("PointLight");
//设置灯光类型为点光源
pointLight->setType(Ogre::Light::LT_POINT);
pointLight->setDiffuseColour(.3, .3, .3);
pointLight->setSpecularColour(.3, .3, .3);
pointLight->setPosition(Ogre::Vector3(0, 150, 250));

运行结果

createScene()中的完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//创建视图-------------------------------------------------------------------------------------
void TutorialApplication::createScene(void)
{
// create your scene here :)
Ogre::Entity* ninjaEntity = mSceneMgr->createEntity("ninja.mesh");
//打开实物投影
ninjaEntity->setCastShadows(true);
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ninjaEntity);

//一个平台实例,y轴为0,铺满x和z轴
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
//Mesh管理器,用于mesh模型资源的管理器
//createPlane方法用于建立一个平面
Ogre::MeshManager::getSingleton().createPlane(
"ground",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
plane,
1500, 1500, 20, 20,
true,
1, 5, 5,
Ogre::Vector3::UNIT_Z);

Ogre::Entity* groundEntity = mSceneMgr->createEntity("ground");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
groundEntity->setCastShadows(false);
//设置平面模型的材质
groundEntity->setMaterialName("Examples/Rockwall");

mSceneMgr->setAmbientLight(Ogre::ColourValue(0, 0, 0));

//阴影投射技术
mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);

//光柱
Ogre::Light* spotLight = mSceneMgr->createLight("SpotLight");
//漫反射
spotLight->setDiffuseColour(0, 0, 1.0);
//镜面反射
spotLight->setSpecularColour(0, 0, 1.0);
//设置光源的类型为光柱(类似手电筒的投射光)
spotLight->setType(Ogre::Light::LT_SPOTLIGHT);
//灯光投射方向,此处为x,y轴45度方向处。
spotLight->setDirection(-1, -1, 0);
//灯光位置
spotLight->setPosition(Ogre::Vector3(200, 200, 0));

Ogre::Light* directionalLight = mSceneMgr->createLight("DirectionalLight");
//设置灯光类型为平行光
directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
directionalLight->setDiffuseColour(Ogre::ColourValue(.4, 0, 0));
directionalLight->setSpecularColour(Ogre::ColourValue(.4, 0, 0));
directionalLight->setDirection(Ogre::Vector3(0, -1, 1));

Ogre::Light* pointLight = mSceneMgr->createLight("PointLight");
//设置灯光类型为点光源
pointLight->setType(Ogre::Light::LT_POINT);
pointLight->setDiffuseColour(.3, .3, .3);
pointLight->setSpecularColour(.3, .3, .3);
pointLight->setPosition(Ogre::Vector3(0, 150, 250));
}

运行结果

结语

Ogre基础的场景,摄像头和灯源显示的部分就到此为止了。


详情的可以查看Ogre wiki的基础教程1Ogre wiki的基础教程2部分。