irrlicht之13.RenderToTexture
这个例子告诉我们如何去使用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;
}