本文主要是介绍OGRE渲染引擎之光照、相机、阴影,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本文翻译自OGRE 1.12.0
本教程将扩展在场景中使用Lights并使用它们投射阴影。
本教程的完整源代码(BasicTutorial2.cpp)可以在样本目录Samples / Tutorials中找到。
Note
有关如何设置Ogre项目并成功编译的说明,请参阅创建OGRE项目。
The OGRE Camera Class
相机是我们用来查看场景的对象。Ogre :: Camera是一个特殊的对象,其作用类似于Ogre :: SceneNode。它有类似setPosition和yaw这样的函数。你还可以将其附加到SceneNode。例如,你可能希望将摄像机临时附加到遵循天空路径的SceneNode以创建航空过场动画。就像SceneNode一样,Camera的位置将相对于其父SceneNode。Camera不是SceneNode(它实际上是从Frustum类继承的),但是对于移动和旋转,你可以将其视为SceneNode。
Note
从版本1.10开始,不推荐使用与旋转和平移相关的功能。你应该将相机附加到Ogre :: SceneNode并使用此节点进行所有转换。
Creating a Camera
我们现在将介绍我们刚刚在前一个教程中应用的相机创建部分。我们记得现在我们需要为像机创建SceneNode。第一步是创建SceneNode并要求SceneManager创建一个新的Camera。添加以下内容以创建SceneNode和Camera:
SceneNode* camNode = scnMgr->getRootSceneNode()->createChildSceneNode();Camera* cam = scnMgr->createCamera("myCam");
您可以使用SceneManager的getCamera方法按名称检索相机。
接下来,我们将定位Camera并使用名为lookAt的方法使用camNode设置其方向。
camNode->setPosition(200, 300, 400);camNode->lookAt(Vector3(0, 0, 0), Node::TransformSpace::TS_WORLD);
Ogre :: SceneNode :: lookAt方法非常有用。它完全符合它的名字。它旋转SceneNode,使其视线聚焦在您给出的矢量上。使相机“看向”点。
我们要做的最后一件事(除了将摄像机连接到SceneNode之外)将近剪裁距离设置为5个单位。这是相机不再渲染任何网格的距离。如果你非常接近网格,这有时会切割网格,让你看到它的内部。另一种选择是用一块微小的,高度放大的网格纹理填充整个屏幕。这取决于你在场景中想要的东西。为了说明,我们将在此处进行设置。
cam->setNearClipDistance(5);camNode->attachObject(cam);
Viewports
在场景中处理多个摄像机时,Viewport的概念变得非常有用。我们现在将接触它,因为它将帮助您更多地了解Ogre如何决定在渲染场景时使用哪个相机。Ogre可以让多个SceneManagers同时运行。它还允许你分解屏幕并使用单独的相机渲染场景的不同视图。这将允许创建像分屏和迷你图这样的东西。这些内容将在后面的教程中介绍。
有三个结构对于理解Ogre如何渲染场景至关重要:Camera,SceneManager和RenderWindow。我们还没有介绍RenderWindow,它基本上代表了我们渲染的整个窗口。SceneManager将创建摄像机以查看场景,然后我们告诉RenderWindow在哪里显示每个摄像机的视图。我们告诉RenderWindow使用屏幕区域的方式是给它一个Ogre :: Viewport。在许多情况下,我们只需创建一个Camera并创建一个代表整个屏幕的Viewport。
Creating a Viewport
让我们为场景创建一个视口。为此,我们将使用RenderWindow的addViewport方法。
Viewport* vp = getRenderWindow()->addViewport(cam);
getRenderWindow()是在OgreBites :: ApplicationContext中为我们定义的一个函数,它返回Ogre :: RenderWindow。
现在让我们设置视口的背景颜色。
vp->setBackgroundColour(ColourValue(0, 0, 0));
我们将它设置为黑色,因为我们稍后会添加彩色照明,我们不希望背景颜色影响我们看到照明的方式。
我们要做的最后一件事是设置相机的纵横比。如果您使用的是标准全窗口视口以外的其他内容,则无法设置此项可能会导致场景失真。我们将在此处设置它以进行演示,即使我们使用的是默认宽高比。
cam->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
我们从视口中检索宽度和高度以设置纵横比。
正如我们所提到的,默认设置已经设置为使用全屏的尺寸。
编译并运行您的应用程序。你应该只看到黑屏,只要确保它运行。
Building the Scene
在我们进入阴影和光照之前,让我们在场景中添加一些元素。让我们把一个忍者放在事物的中间。设置环境光后立即添加以下代码:
Entity* ninjaEntity = scnMgr->createEntity("ninja.mesh");ninjaEntity->setCastShadows(true);scnMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ninjaEntity);
这应该看起来很熟悉,除非我们要求网格这次投射阴影。请注意,这次我们创建了一个子场景节点,并将ninjaEntity全部连接在一起。
我们还将为忍者创造一些东西。我们可以使用Ogre :: MeshManager从头开始创建网格。我们将使用它来生成纹理平面以用作地面。
我们要做的第一件事是创建一个抽象的Plane对象。这不是网格,它更像是一个蓝图。
Plane plane(Vector3::UNIT_Y, 0);
我们通过提供一个垂直于我们的平面的矢量和它到原点的距离来创建一个平面。所以我们创建了一个垂直于y轴的平面并且距离原点的零个单位。如下图:
Plane构造函数还有其他重载,使得我们传递第二个向量而不是距离原点的距离。这允许我们在想要的3D空间中构建任何平面。
现在我们要求MeshManager使用我们的平面蓝图创建一个网格。MeshManager已经在初始化我们的应用程序时跟踪我们加载的资源。最重要的是,它可以为我们创建新的网格。
MeshManager::getSingleton().createPlane("ground", RGN_DEFAULT,plane,1500, 1500, 20, 20,true,1, 5, 5,Vector3::UNIT_Z);
这是一个复杂的函数,我们还没有完全了解它。如果您想了解更多信息,可以阅读Ogre :: MeshManager类规范。基本上,我们创建了一个名为“ground”的新网格,大小为1500x1500。
现在我们将使用这个网格创建一个新实体。
Entity* groundEntity = scnMgr->createEntity("ground");scnMgr->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
请注意,不要把为createEntity指定的参数混淆为Entity的名称。它实际上是我们刚刚创建的网格的名称。我们习惯于看到网格名称以'.mesh'结尾。
我们想告诉SceneManager不要从我们的地面实体投射阴影。这其实只是一种浪费。不要混淆,这意味着地面不会投下阴影,这并不意味着我们不能将阴影投射到地面上。
groundEntity->setCastShadows(false);
最后,我们需要提供一个材质。目前,最简单的方法是使用Ogre包含的脚本中的材质及其样本。您应该在SDK或您下载的源目录中使用这些资源来构建Ogre。
groundEntity->setMaterialName("Examples/Rockwall");
确保将材质和Examples.material脚本的纹理添加到资源加载路径。在我们的例子中,纹理名称为'rockwall.tga'。您可以通过阅读材料脚本中的条目自己找到该名称。
Using Shadow in Ogre
在Ogre中启用阴影很容易。SceneManager类有一个我们可以使用的Ogre :: SceneManager :: setShadowTechnique方法。然后每当我们创建一个实体时,我们调用setCastShadows来选择将投射阴影的实体。setShadowTechinique方法采用了几种不同的技术。有关更多详细信息,请参阅Ogre :: ShadowTechnique。
让我们关掉环境光,这样我们就能看到灯光的全部效果。添加以下内容:
scnMgr->setAmbientLight(ColourValue(0, 0, 0));scnMgr->setShadowTechnique(ShadowTechnique::SHADOWTYPE_STENCIL_MODULATIVE);
现在SceneManager将使用调制模板阴影。让我们添加一些灯来看这个动作
Lights
Ogre提供三种类型的光照。
- Ogre :: Light :: LT_POINT - 此光从一个点向各个方向均匀地发散。
- Ogre :: Light :: LT_SPOTLIGHT - 这个灯像手电筒一样工作。 它产生一个光柱,在中心更亮,并逐渐消失。
- Ogre::Light::DIRECTIONAL- 这个光模拟了一个非常遥远的巨大光源 - 就像日光一样。 光线以相同的角度到达整个场景。
- Ogre :: Light类具有广泛的属性。其中最重要的两个是漫反射和镜面反射颜色。每个材质脚本定义材质反射的镜面和漫反射光照量。这些属性将在后面的一些教程中介绍。
Creatint a Light
让我们为场景添加一个灯光。我们通过调用Ogre :: SceneManager :: createLight函数来完成此操作。创建完groundEntity后立即添加以下代码:
Light* spotLight = scnMgr->createLight("SpotLight");
我们将漫反射和镜面反射颜色设置为纯蓝色。
spotLight->setDiffuseColour(0, 0, 1.0);spotLight->setSpecularColour(0, 0, 1.0);
接下来,我们将灯光的类型设置为聚光灯。
spotLight->setType(Light::LT_SPOTLIGHT);
聚光灯需要一个位置和一个方向 - 记住它就像一个手电筒。我们将聚光灯放在忍者的右肩上方,以45度的角度照射在他身上。
SceneNode* spotLightNode = scnMgr->getRootSceneNode()->createChildSceneNode();spotLightNode->attachObject(spotLight);spotLightNode->setDirection(-1, -1, 0);spotLightNode->setPosition(Vector3(200, 200, 0));
最后,我们设置了所谓的聚光灯范围。这些角度决定了光从中间的明亮区域到外侧边缘的调光器的位置。
spotLight->setSpotlightRange(Degree(35), Degree(50));
编译并运行应用程序。你应该看到一个忍者的阴影蓝色图。
Creating More Lights
接下来,我们将为场景添加定向光。这种类型的光基本上模拟日光或月光。灯光在整个场景中以相同的角度投射。和以前一样,我们首先创建Light并设置其类型。
Light* directionalLight = scnMgr->createLight("DirectionalLight");directionalLight->setType(Light::LT_DIRECTIONAL);
现在我们将漫反射和镜面反射颜色设置为深红色。
directionalLight->setDiffuseColour(ColourValue(0.4, 0, 0));directionalLight->setSpecularColour(ColourValue(0.4, 0, 0));
最后,我们需要设置Light的方向。定向光没有位置,因为它被建模为无限远的点光源。
SceneNode* directionalLightNode = scnMgr->getRootSceneNode()->createChildSceneNode(); directionalLightNode->attachObject(directionalLight);
directionalLightNode->setDirection(Vector3(0, -1, 1));
Light类还定义了一个Ogre :: Light :: setAttenuation函数,它允许你控制光线离开更远时的消散方式。完成本教程后,请尝试在场景中使用此函数以查看它对灯光的影响。
编译并运行应用程序。你的忍者现在应该在他身后投下阴影,场景应该充满红光。
为了完成该设置,我们现在将为我们的场景添加一个点光源。
Light* pointLight = scnMgr->createLight("PointLight");
pointLight->setType(Light::LT_POINT);
我们将镜面反射和漫反射颜色设置为深灰色。
pointLight->setDiffuseColour(0.3, 0.3, 0.3);pointLight->setSpecularColour(0.3, 0.3, 0.3);
点光源没有方向,它只有一个位置。我们将最后一盏灯放在忍者的上方和后方。
SceneNode* pointLightNode = scnMgr->getRootSceneNode()->createChildSceneNode();pointLightNode->attachObject(pointLight);pointLightNode->setPosition(Vector3(0, 150, 250));
编译并运行应用程序。你现在应该在忍者面前看到一个长长的阴影。你应该看到点光源的效果使忍者背后的区域变亮。试着想一想为什么颜色会像他们那样。例如,为什么忍者背后的阴影似乎根本没有红色?
Shadow Types
Ogre支持一组不同的阴影类型。更多有关详细信息,请参阅Ogre :: ShadowTechnique枚举器。
尝试尝试不同的阴影类型。您可以在Ogre :: SceneManager类中使用其他与阴影相关的方法。
Ogre不提供软阴影作为引擎的一部分。您可以编写自己的顶点和片段程序来实现软阴影和许多其他内容。ogre手册有阴影的完整描述。
Conclusion
本教程介绍了如何在场景中使用灯光和阴影。首先,我们介绍了如何使用MeshManager从头开始生成网格。然后我们选择了Ogre应该使用哪种阴影类型。最后,我们开始向场景添加每种类型Light的示例。我们创造了聚光灯,定向灯和点光源。你甚至可以通过编写自己的顶点和片段程序来扩展Ogre的光照和阴影系统。有关详细信息,请参阅ogre手册。
我们已经介绍了许多不同的设置,允许你自定义Ogre渲染光影的方式。完成每个教程后,最好使用你拥有的新工具。这将大大提高您使用库的舒适度,这是学习使用API文档的绝佳方式。
这篇关于OGRE渲染引擎之光照、相机、阴影的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!