您的位置:首页 > 其它

[OGRE]基础教程来三发:来谈一谈摄像机吧

2013-10-03 19:47 162 查看
今天我们来谈谈OGRE中的摄像机吧,像机吧,机吧,吧。

首先先来给大家介绍两个函数:createViewport和createCamera,这两个方法已经在基类ExampleApplication中定义了。

我们把这两个函数加到TutorialApplication 类中:

#include "ExampleApplication.h"
class TutorialApplication : public ExampleApplication
{
public:
TutorialApplication()
{
}
~TutorialApplication()
{
}
protected:
virtual void createCamera(void)
{
}

virtual void createViewports(void)
{
}

void createScene(void)
{
//设置背景灯光
mSceneMgr->setAmbientLight( ColourValue( 1, 1, 1 ) );

//第一个机器人
Entity *ent1 = mSceneMgr->createEntity( "Robot", "robot.mesh" );
SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode" ,Vector3( -100, 0, 0 ) );
node1->attachObject( ent1 );
node1->yaw( Degree( -90 ) );
}
};


cpp文件不做任何修改:

#include "TutorialApplication.h"
#include "windows.h"

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
{
TutorialApplication app;
try
{
app.go();
}
catch( Exception& e )
{
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
}


我们用这两个方法,演示摄像机和视口具体建立和使用。

首先,先来创建个摄像机。场景管理器里有自带的摄像机,以此来创建我们的摄像机。
添加下面的代码到创建摄像机方法里:

// 创建摄像机

mCamera = mSceneMgr->createCamera("PlayerCam");


这将创建一个叫"PlayerCam"的摄像机。如果你不打算保留它的指针,那么你可以调用场景管理器的方法 getCamera通过传递它的名字来获取它。

接下来,继续设置摄像机的初始位置和朝向。
我们将设置摄像机朝向坐标原点,所以我们需要设置一个恰当的Z轴距离。也就是说,摄像机身在Z轴,朝向原点。
添加下面的代码到刚才的后面:

mCamera->setPosition(Vector3(0,10,500));

mCamera->lookAt(Vector3(0,0,0));


lookAt方法和OpenGL中的是一样的,能够设置它面向任何你想要的角度。
接下来需要设置一个近距离裁剪,该距离内的事物是你看不到的。我们可以将值设为5单位距离。
设置近距离裁剪后,你能够在离实体很近的时候,很容易的透过实体看到场景。
还有一种很微小的情况就是,当你和某个物体很近时,这个物体将填满你的整个视野。
同样,你也可以设置远距离裁剪,在需要远距离渲染大场景的时候,用来增加帧速,减少渲染的内容。
添加如下代码,以实现近距离裁剪:
mCamera->setNearClipDistance(5);


设置远距离裁剪和上面一样,方法名是这个:setFarClipDistance。当然,现在没有必要设置远距离裁剪。
现在需要考虑考虑视口的问题了。

当你开始处理多个摄像机时,视口类的概念就变得对你很有用了。
在同一个时间内Ogre中可能有多个场景管理器在运行,也有可能把场景分为多个区域,然后用分开的摄像机去渲染场景中不同的区域。

为了了解Ogre是怎样渲染场景的,考虑一下Ogre中这三样重要的东西:摄像机,场景管理器,和渲染窗口。
其他两个我们都已经有所涉及,渲染窗口我们还没有涉及到,但是它是所有物体呈现的最基本的窗口。
场景管理器实体mSceneMgr创建摄像机mCamera去观察场景。
必须告诉渲染窗口使用哪些摄像机来呈现场景,那些窗口被渲染了进来。

接下来我们来了解一下如何建立视口。

建立视口的方法通常是简单的调用渲染窗口中addViewport函数,把它提供给正在使用的摄像机。

ExampleApplication类已经通过我们的渲染窗口移到mWindow类里面了,因此添加这些代码:

//创建一个视图
Viewport* vp = mWindow->addViewport(mCamera);


现在我们拥有自己的视口了,我们可以用它做到的东西非常有限。

最重要的是我们可以做的是调用setBackgroundColour方法给背景设置任意我们选择的颜色,我们把背景设置为黑色。

//设置背景颜色
vp->setBackgroundColour(ColourValue(0,0,0));


最后,也是最重要的事情:设置摄像机的纵宽比。

如果你用的是一些非标准全窗口视口,而未能设置这个的话结果会出现一个非常奇怪的场景图。

我们立刻纵宽比为默认纵宽比:

// 修改摄像头的纵宽比为默认纵宽比
mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));


运行一下你可以看到一个黑色的框框。

当然你可以把背景颜色搞成红色看一下风骚的显示效果:



当然还是要把这个改回去,改成0,0,0黑色吧,这样便于我们测试光源和阴影的效果。

说道阴影,我们着重介绍三种阴影效果:

1.调制纹理阴影(SHADOWTYPE_TEXTURE_MODULATIVE)-是这3种中最节省资源的。她创建一个阴影投射者的黑与白渲染到纹理,然后用于场景中。
2.调制模板阴影(SHADOWTYPE_STENCIL_MODULATIVE)-这项技术是在所有的非透明体被渲染到场景以后再渲染所有的阴影体来调制阴影,她耗费资源没有加成模板阴影强,但是也不是非常精确。
3.加成模板阴影(SHADOWTYPE_STENCIL_ADDITIVE)-这项技术是渲染每一个光源作为分离的部分附加到场景中。对显卡来说这是比较麻烦的,因为在场景中每一个附加的光源需要一个附加渲染通路。

用阴影在Ogre中相对来说是比较简单的。

SceneManager类中有一个setShadowTechnique成员函数,我们可以使用它设置我们想要的阴影类型。

这样只要你创建了一个实体,调用setCastShadows方法来设置这个实体是否投射阴影。我们现在将设置环境光全变暗,然后设置阴影类型。

找到TutorialApplication::createScene成员函数添加如下代码:

//设置背景灯光
mSceneMgr->setAmbientLight(ColourValue(0, 0, 0));
mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);


现在场景管理器运用的是加成模板阴影。接下来就是用一个实体实现投射阴影,这次我们不用机器人了,改用一个日本武士:

void createScene(void)
{
//设置背景灯光
mSceneMgr->setAmbientLight(ColourValue(1, 1, 1));
mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);

//一个实物
Entity *ent1 = mSceneMgr->createEntity( "Ninja", "ninja.mesh" );
ent1->setCastShadows(true);

//场景节点
SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode" ,Vector3( 0, 0, 0 ) );
node1->attachObject( ent1 );
node1->yaw( Degree( -180 ) );
}


现在我们需要一个平面来展示投影的效果,假设是一个平面把y正半轴作为她的法线(面朝上),与原点的距离为0:

Plane plane(Vector3::UNIT_Y, 0);


现在我们需要注册这个平面以便于我们可以把她运用到我们的应用程序中。

MeshManager类知道所有读到我们应用程序中的模型(例如:前面用到的robot.mesh和ninja.mesh)。
createPlane成员函数接收一个平面定义,通过参数制造的一个模型。
我们可以这样注册一个平面:

MeshManager::getSingleton().createPlane("ground",

ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,

1500,1500,20,20,true,1,5,5,Vector3::UNIT_Z);


这一大串函数和参数,说来就话长了。在此就不解释太多这个函数的细节了,大家可以查看API文档。

总之我们知道实现的效果是:注册了我们的平面尺寸为1500×1500,新模型名字叫“ground”。
现在,我们可以通过模型创建一个实体把她放置到场景中:

//布置到场景中
Entity *ent2 = mSceneMgr->createEntity("GroundEntity", "ground");
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent2);


对ground来说在结束之前我们还有两件事情要做。
首先是我们需要在上面贴纹理,第二件事是告诉场景管理器我们不想把这个平面设置成投射阴影体。
我们将用"Examples/Rockwall""Examples/Rockwall"材质脚本:

ent2->setMaterialName("Examples/Rockwall");
ent2->setCastShadows(false);


我们把背景光设置成黑色:

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


这样有利于我们观察我们接下来要设置的光源。

光源种类 Ogre提供了三种光源类型。
1.点光源(LT_POINT)-从一个点发出光放射到四周。
2.聚光源(LT_SPOTLIGHT)-严格来说聚光灯工作有点像手电筒。你在某个地方设置了灯光的起点,然后灯光射向一个方向。你可以告诉光源内锥角度大小和外锥角度大小(你知道手电筒内部会明亮一些。)
3.有向光(LT_DIRECTIONAL)-有向光模拟非常遥远地方的灯光,在场景中从某个方向照射物体。如果你想要一个夜晚的场景你就需要模拟月光。

在Ogre中创建一个光源需要调用场景管理器中的createLight方法然后提供光源的名称,就跟我们创建实体和摄像机一样。
光源仅仅有两个方法setPosition和setDirection(而且并不是像旋转,偏移,滚动一样有全套的移动函数)。
如果你需要移动光源(例如创建一个光源跟随角色),你需要把光源绑定到场景节点上。
因此,从基础的点光源开始吧。

首先我们要创建光源,设置它的类型和它的位置:
//创建光源
Light *light = mSceneMgr->createLight("Light1");
light->setType(Light::LT_POINT);
light->setPosition(Vector3(0, 150, 250));


现在我们已经创建好了光源,我们可以设置她的漫射色和镜面色了。让我们设置漫反射为红色,镜面反射为蓝色:

//设置光的漫反射和镜面色
light->setDiffuseColour(1.0, 0.0, 0.0);
light->setSpecularColour(0.0, 0.0, 1.0);


好的现在编译和运行这个应用程序。成功了!



妈蛋吓老子一跳。
我们现在可以看见Ninja和她投射的影子了。确定你也可以从前面,侧面都可以看到她。

接着让我们试试有向光,添加一些黄色的有向光射向她的前面。
设置光源和颜色的步骤和设置点光源是一样的:

//创建有向光源
light = mSceneMgr->createLight("Light3");
light->setType(Light::LT_DIRECTIONAL);
light->setDiffuseColour(ColourValue(.25, .25, 0));
light->setSpecularColour(ColourValue(.25, .25, 0));


因为有向光是从无穷远的距离射来的,因此我们不需要设置位置,仅仅是设置她的方向。
我们设置光的方向是z正半轴和y负半轴(类似从ninja的45度角正前方射过来):
light->setDirection(Vector3( 0, -1, 1 ));


编译并运行这个应用程序。
走近看可以看到影子:



因为有向光很微弱,所以影子也比较弱。
最后让我们来试试聚光灯。

我们将创建一个蓝色的聚光灯:
//创建聚光灯源
light = mSceneMgr->createLight("Light2");
light->setType(Light::LT_SPOTLIGHT);
light->setDiffuseColour(0, 0, 1.0);
light->setSpecularColour(0, 0, 1.0);
light->setDirection(-1, -1, 0);
light->setPosition(Vector3(300, 300, 0));
light->setSpotlightRange(Degree(35), Degree(50));


效果很幽森:



这样我们就简单的介绍了光源和阴影的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OGRE