irrwowview

Tutorial 8: Special Effects

Tutorial 8: Special Effects
本教程描述了如何实现特效。淙了如何使用静态缓存阴影,粒子系统,公告板,动态光和水纹表面的场景节点。

程序的效果图如下:

 

Lets start!

程序的开始就像之前的教程那样。这里要注意的是:如果你想根据活动的角色产生动态投影,那么createDevice()函数的‘shadows’标志位要设成true。但如果运行缓慢,则设为false。如果引擎检测到你的硬件不支持模板缓存(stencil buffer),为了防止运行过慢,会自己关闭阴影。

#include <irrlicht.h>

 

#include <iostream>

 

using namespace irr;

 

 

 

#pragma comment(lib, "Irrlicht.lib")

 

 

 

int main()

 

{

 

  // ask user for driver
  video::E_DRIVER_TYPE driverType;
 

 

  printf("Please select the driver you want for this example:\n"\
    " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
    " (d) Software Renderer\n (e) Apfelbaum Software Renderer\n"\
    " (f) NullDevice\n (otherKey) exit\n\n");

  char i;
  std::cin >> i;

  switch(i)
  {
    case 'a': driverType = video::EDT_DIRECT3D9;break;
    case 'b': driverType = video::EDT_DIRECT3D8;break;
    case 'c': driverType = video::EDT_OPENGL;   break;
    case 'd': driverType = video::EDT_SOFTWARE; break;
    case 'e': driverType = video::EDT_SOFTWARE2;break;
    case 'f': driverType = video::EDT_NULL;     break;
    default: return 1;
  }     

 

 

 

  // create device and exit if creation failed
  IrrlichtDevice *device = createDevice(driverType,

 

    core::dimension2d<s32>(640, 480), 16, false, true);

 

 

 

  if (device == 0)

 

    return 1;

 

 

 

 video::IVideoDriver* driver = device->getVideoDriver();

 

 scene::ISceneManager* smgr = device->getSceneManager();

 

我们加载了一个*.3ds格式的文件作为世界环境。这是我用Anim8or 建模并生成*.3ds格式(由于写本教程时,IrrLicht引擎不支持*.an8格式的模型)的小房间。我是一个很差的3d图形美工,因此模型的纹理贴图并不漂亮。幸运的是我作为程序员比美工好,并能够用IrrLicht引擎创建一个很cool的纹理贴图:只要用网格管理器(mesh manipulator)为网格创建平面纹理贴图就可以了。如果你想看我用Anim8or 作的贴图效果,只需把这行注释就行了。我也不打算用Anim8or 设置材质,因为有我很不喜欢的emissive光。我会在代码中禁用它。

         scene::IAnimatedMesh* mesh = smgr->getMesh(

 

                 "../../media/room.3ds");

 

 

 

         smgr->getMeshManipulator()->makePlanarTextureMapping(

 

                 mesh->getMesh(0), 0.008f);

 

 

 

         scene::ISceneNode* node = 0;

 

 

 

         node = smgr->addAnimatedMeshSceneNode(mesh);

 

         node->setMaterialTexture(0,        driver->getTexture("../../media/wall.jpg"));

 

         node->getMaterial(0).EmissiveColor.set(0,0,0,0);

现在要实现的第一个特效是:流动的水。它应该这样工作:将一个网格作为输入制作成水表面场景节点(WaterSurfaceSceneNode),并使它好像水的表面产生波纹。而且如果把场景节点的材质设成MT_REFLECTION_2_LAYER ,那么效果真的很cool。我们会在下几行代码实现。作为输入网格,我们创建一个丘陵平面网格。其实任何网格都可以的,甚至可以使用room3ds(虽然看起来很奇怪)作为网格。

          mesh = smgr->addHillPlaneMesh("myHill",

 

                    core::dimension2d<f32>(20,20),

 

                    core::dimension2d<s32>(40,40), 0, 0,

 

                    core::dimension2d<f32>(0,0),

 

                    core::dimension2d<f32>(10,10));

 

 

 

          node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0), 3.0f, 300.0f, 30.0f);

 

          node->setPosition(core::vector3df(0,7,0));

 

 

 

          node->setMaterialTexture(0,    driver->getTexture("../../media/stones.jpg"));

 

          node->setMaterialTexture(1,    driver->getTexture("../../media/water.jpg"));

 

 

 

          node->setMaterialType(video::EMT_REFLECTION_2_LAYER);

 

第二个特效是很基础的,你应该在IrrLicht引擎的其它演示中看过:一个结合了动态光的透明公告板。我们简单地创建一个飞来飞去的灯光场景节点,并绑定一个公告板(能够知道灯光的位置),使它看起来更cool

         // create light

 

 

 

         node = smgr->addLightSceneNode(0, core::vector3df(0,0,0),

 

                 video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 600.0f);

 

         scene::ISceneNodeAnimator* anim = 0;

 

         anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f);

 

         node->addAnimator(anim);

 

         anim->drop();

 

 

 

         // attach billboard to light

 

 

 

         node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));

 

         node->setMaterialFlag(video::EMF_LIGHTING, false);

 

         node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);

 

         node->setMaterialTexture(0,         driver->getTexture("../../media/particlewhite.bmp"));

 

 

 

第三个特效是更有趣的:粒子系统(particle system)。IrrLicht引擎中的粒子系统是一个可扩展并且很容易使用的模块。要放一个粒子发射器到粒子系统里,发射器就会产生粒子了。这些发射器是什么灵活的,而且通常在创建时要设置很多参数(例如方向,数量和粒子的颜色)。
有各种不同的发射器,例如一个点发射器能使粒子从一个固定点射出。如果引擎中的粒子发射器不能满足你的要求,你可以自己创建一个,只要简单地创建一个继承自IParticleEmitter 接口的类并用setEmitter()函数把它绑定到粒子系统,
在这个例子中我们创建一个盒形粒子发射器,用于在盒子中随机创建粒子。createBoxEmitter()函数要定义盒子的大小,粒子的方向,每秒最多最少粒子生成量,粒子颜色和粒子的最长最短生存时间。

只使用了发射器的粒子系统是有点枯燥的,因此还使用粒子效果器来修改漂浮粒子的效果。效果器添加到粒子系统里,能附加模拟重力和风的效果。在这个盒子中,我们使用粒子效果器来修改粒子的颜色:使粒子淡出(渐渐消失)。就如粒子发射器那样,你可以自己实现一个继承自IParticleAffector的效果器并用addAffector()添加到粒子系统中。当设置好粒子系统的材质后,我们就有一个看起来很cool的营火。通过设置材质,纹理,粒子发射器和粒子效果器,我们还能制作烟雾,下雨,爆炸和雪等效果。

         scene::IParticleSystemSceneNode* ps = 0;

 

         ps = smgr->addParticleSystemSceneNode(false);

 

         ps->setPosition(core::vector3df(-70,60,40));

 

         ps->setScale(core::vector3df(2,2,2));

 

 

 

         ps->setParticleSize(core::dimension2d<f32>(20.0f, 10.0f));

 

 

 

         scene::IParticleEmitter* em = ps->createBoxEmitter(

 

                 core::aabbox3d<f32>(-7,0,-7,7,1,7),

 

                 core::vector3df(0.0f,0.03f,0.0f),

 

                 80,100,

 

                 video::SColor(0,255,255,255), video::SColor(0,255,255,255),

 

                 800,2000);

 

 

 

         ps->setEmitter(em);

 

         em->drop();

 

 

 

         scene::IParticleAffector* paf =

 

                 ps->createFadeOutParticleAffector();

 

 

 

         ps->addAffector(paf);

 

         paf->drop();

 

 

 

         ps->setMaterialFlag(video::EMF_LIGHTING, false);

 

         ps->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp"));

 

         ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);

作为最后的特效,我们想根据活动人物创建一个动态阴影。为此我们加载格式为*.xDirectX模型并放置在世界里。要创建阴影,我们只需简单地调用addShadowVolumeSceneNode()函数. 全局的阴影颜色都是通过调用ISceneManager::setShadowColor()函数设置的。瞧,这就是我们的动态阴影。
因为对于这个场景来说人物确实小了点,所以调用setScale()放大了模型。并因为要使人物根据动态光来发光,需要规格化法线来使人物正确地发光。如果动态光的比例不是(111),那么是必需这样设的。否则,会根据法线的比例而太光或太暗。

         mesh = smgr->getMesh("../../media/dwarf.x");

 

         scene::IAnimatedMeshSceneNode* anode = 0;

 

 

 

         anode = smgr->addAnimatedMeshSceneNode(mesh);

 

         anode->setPosition(core::vector3df(-50,20,-60));

 

         anode->setAnimationSpeed(15);

 

 

 

         // add shadow

 

         anode->addShadowVolumeSceneNode();

 

         smgr->setShadowColor(video::SColor(220,0,0,0));

 

 

 

         // make the model a little bit bigger and normalize its normals
         // because of this for correct lighting

         anode->setScale(core::vector3df(2,2,2));
         anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);

最后,我们只需简单地绘制全部,就如下面那样。

         scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();

 

         camera->setPosition(core::vector3df(-50,50,-150));

 

 

 

 

 

         int lastFPS = -1;

 

 

 

         while(device->run())

 

         {

 

                 driver->beginScene(true, true, 0);

 

 

 

                 smgr->drawAll();

 

 

 

                 driver->endScene();

 

 

 

                 int fps = driver->getFPS();

 

 

 

                 if (lastFPS != fps)

 

                 {

 

                   core::stringw str = L"Irrlicht Engine - SpecialFX example [";
                   str += driver->getName();
                   str += "] FPS:";
                   str += fps;

                   device->setWindowCaption(str.c_str());
                   lastFPS = fps;
                 }

 

         }

 

 

 

         device->drop();

 

        

 

         return 0;

 

}

 

 

 

 

 

 

 

posted on 2008-07-04 11:07 shjy 阅读(313) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理