这个例子告诉我们如何去使用Irr引擎实时渲染一个纹理。实时渲染纹理是一个制作优美特效的手段。另外,这个例子告诉我们如何渲染镜面。

/*

这个例子告诉我们如何去使用Irr引擎实时渲染一个纹理。实时渲染纹理是一个制作优美特效的手段。另外,这个例子告诉我们如何渲染镜面。

开始依旧和之前一样,包含头文件,让用户定义渲染设备,创建Irr设备。
*/

#include <irrlicht.h>
#include <iostream>

using namespace irr;

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

int main()
{
// 让用户选择设备类型

video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;

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) Burning's 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_BURNINGSVIDEO;break;
   case 'f': driverType = video::EDT_NULL;     break;
   default: return 1;
}

// 创建设备,若失败则直接返回

IrrlichtDevice *device =
   createDevice(driverType, core::dimension2d<s32>(640, 480),
   16, false, false);

if (device == 0)
   return 1;

video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();

/*
现在我们读取一个将被显示的Mesh.这个Mesh我们依旧使用常见的.md2格式模型。
不同之处在于:我们设置模型自发光为20,而一般默认值为0。
这样的话,如果动态光照开启就可以进行镜面渲染。而这个自发光值也将会影响镜面渲染。
*/

// 读取并显示一个Mesh

scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode(
   smgr->getMesh("../../media/faerie.md2"));

if (fairy)
{
   // 设置纹理
   fairy->setMaterialTexture(0, driver->getTexture("../../media/faerie2.bmp"));
   // 开启动态光照
   fairy->setMaterialFlag(video::EMF_LIGHTING, true);
   // 设置自发光强度大小(即镜面渲染中的亮度大小)
   fairy->getMaterial(0).Shininess = 20.0f;
   fairy->setPosition(core::vector3df(-10,0,-100));
   fairy->setMD2Animation ( scene::EMAT_STAND );
}

/*
为了在模型上实现镜面映射渲染,我们在场景中设置一个动态光照。我们将它设置在模型旁边。
另外,为了使模型看起来不太黑,我们设置环境光为灰色。
*/

// 增加一个场景光照
scene::ILightSceneNode* light = smgr->addLightSceneNode(0,
   core::vector3df(-15,5,-105), video::SColorf(1.0f, 1.0f, 1.0f));

// 设置环境光
smgr->setAmbientLight(video::SColor(0,160,160,160));

/*
下面的将是一些标准步骤:添加一个用户控制摄象机,隐藏鼠标,增加一个测试立方体,使它旋转起来等
*/

// 添加一个FPS摄象机场景节点
scene::ICameraSceneNode* fpsCamera = smgr->addCameraSceneNodeFPS();
fpsCamera->setPosition(core::vector3df(-50,50,-150));

// 隐藏鼠标图标显示
device->getCursorControl()->setVisible(false);

// 创建一个测试用的立方体
scene::ISceneNode* test = smgr->addCubeSceneNode(60);

// 使立方体旋转起来,并且设置一些光照属性
scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
   core::vector3df(0.3f, 0.3f,0));

test->setPosition(core::vector3df(-100,0,-100));
// 关闭动态光照
test->setMaterialFlag(video::EMF_LIGHTING, false);
test->addAnimator(anim);
anim->drop();

// 设置窗口标题
device->setWindowCaption(L"Irrlicht Engine - Render to Texture and Specular Highlights example");

/*
为了获取渲染后的纹理,我们先需要一个纹理对象。它和普通的纹理不同,我们需要先使用
IVideoDriver::createRenderTargetTexture()创建它并且指定纹理的大小。
请注意:这里不允许使用比桢缓存尺寸还大的纹理尺寸。
因为我们不打算以用户摄象机做为镜面摄象机,所以我们创建了一个新的摄象机,由它来获取
渲染出的纹理。
(译者注:镜面渲染的原理是,由一个摄象机点拍摄当前渲染桢,把这个拍摄到的结果做为一个
纹理帖到一个模型上)
*/

// 创建渲染目标
video::ITexture* rt = 0;
scene::ICameraSceneNode* fixedCam = 0;

if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET))
{
  
   rt = driver->createRenderTargetTexture(core::dimension2d<s32>(256,256));
   // 为渲染目标设置材质属性
   test->setMaterialTexture(0, rt);

   // 增加一个固定摄象机
   fixedCam = smgr->addCameraSceneNode(0, core::vector3df(10,10,-80),
    core::vector3df(-10,10,-100));
}
else
{
   // 报错信息
   gui::IGUISkin* skin = env->getSkin();
   gui::IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
   if (font)
    skin->setFont(font);

   gui::IGUIStaticText* text = env->addStaticText(
    L"Your hardware or this renderer is not able to use the "\
    L"render to texture feature. RTT Disabled.",
    core::rect<s32>(150,20,470,60));

   text->setOverrideColor(video::SColor(100,255,255,255));
}

/*
接近结束了,现在我们需要进行绘制了。每桢,我们绘制场景两次。
绘制第一次是为了方便镜面摄象机进行渲染截取,此时我们就可以获得渲染目标纹理了。但是请
注意,此时我们需要设置测试方块不可见,因为我们的动态镜面纹理中不应当出现渲染立方体本身。
恩,我希望这样讲不会太复杂。
*/

int lastFPS = -1;

while(device->run())
if (device->isWindowActive())
{
   driver->beginScene(true, true, 0);

   if (rt)
   {
    // 绘制渲染纹理中的场景
   
    // 设置渲染目标的纹理
    driver->setRenderTarget(rt, true, true, video::SColor(0,0,0,255));    

    // 设置立方体不可见,并设置镜面混合摄象机为活动摄象机
    test->setVisible(false);
    smgr->setActiveCamera(fixedCam);

    // 绘制整个场景并将其绘制到渲染缓冲中去
    smgr->drawAll();                

    // set back old render target
    driver->setRenderTarget(0);     

    // 设置立方体为可见,并更换回FPS摄象机为活动摄象机
    test->setVisible(true);
    smgr->setActiveCamera(fpsCamera);
   }
  
   // 绘制第二次场景
   smgr->drawAll();
   env->drawAll();

   driver->endScene();

   // 窗口标题显示桢数
   int fps = driver->getFPS();
   if (lastFPS != fps)
   {
    core::stringw str = L"Irrlicht Engine - Render to Texture and Specular Highlights example";
    str += " FPS:";
    str += fps;

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

if (rt)
   rt->drop(); // 释放渲染对象

device->drop(); // 释放设备
return 0;
}