Added a texture animator to volume light in special effects example to show off how cool it can look, and better integrated it into the tutorial.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1316 dfc29bdd-3216-0410-991c-e03cc46cb475
master
bitplane 2008-04-16 07:27:20 +00:00
parent 0e63486fbe
commit 818b79852a
1 changed files with 307 additions and 281 deletions

View File

@ -1,281 +1,307 @@
/* This tutorials describes how to do special effects. It shows how to use stencil /* This tutorials describes how to do special effects. It shows how to use stencil
buffer shadows, the particle system, billboards, dynamic light and the water buffer shadows, the particle system, billboards, dynamic light and the water
surface scene node. surface scene node.
We start like in some tutorials before. Please note that this time, the 'shadows' flag in We start like in some tutorials before. Please note that this time, the 'shadows' flag in
createDevice() is set to true, for we want to have a dynamic shadow casted from createDevice() is set to true, for we want to have a dynamic shadow casted from
an animated character. If your this example runs to slow, set it to false. an animated character. If your this example runs to slow, set it to false.
The Irrlicht Engine checks if your hardware doesn't support the stencil The Irrlicht Engine checks if your hardware doesn't support the stencil
buffer, and disables shadows by itself, but just in case the demo runs slow buffer, and disables shadows by itself, but just in case the demo runs slow
on your hardware.*/ on your hardware.*/
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
using namespace irr; using namespace irr;
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
int main() int main()
{ {
// ask if user would like shadows // ask if user would like shadows
char i; char i;
printf("Please press 'y' if you want to use realtime shadows.\n"); printf("Please press 'y' if you want to use realtime shadows.\n");
std::cin >> i; std::cin >> i;
bool shadows = (i == 'y');
bool shadows = (i == 'y');
// ask user for driver
// ask user for driver
video::E_DRIVER_TYPE driverType;
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"\ printf("Please select the driver you want for this example:\n"\
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\ " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (f) NullDevice\n (otherKey) exit\n\n"); " (d) Software Renderer\n (e) Burning's Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");
std::cin >> i;
std::cin >> i;
switch(i)
{ switch(i)
case 'a': driverType = video::EDT_DIRECT3D9;break; {
case 'b': driverType = video::EDT_DIRECT3D8;break; case 'a': driverType = video::EDT_DIRECT3D9;break;
case 'c': driverType = video::EDT_OPENGL; break; case 'b': driverType = video::EDT_DIRECT3D8;break;
case 'd': driverType = video::EDT_SOFTWARE; break; case 'c': driverType = video::EDT_OPENGL; break;
case 'e': driverType = video::EDT_BURNINGSVIDEO;break; case 'd': driverType = video::EDT_SOFTWARE; break;
case 'f': driverType = video::EDT_NULL; break; case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
default: return 1; case 'f': driverType = video::EDT_NULL; break;
} default: return 1;
}
// create device and exit if creation failed
// create device and exit if creation failed
IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(640, 480), IrrlichtDevice *device =
16, false, shadows); createDevice(driverType, core::dimension2d<s32>(640, 480),
16, false, shadows);
if (device == 0)
return 1; // could not create selected driver. if (device == 0)
return 1; // could not create selected driver.
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager(); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
/*
For our environment, we load a .3ds file. It is a small room I modelled /*
with Anim8or and exported it into the 3ds format because the Irrlicht Engine For our environment, we load a .3ds file. It is a small room I modelled
did not support the .an8 format when I wrote this tutorial. I am a very bad with Anim8or and exported it into the 3ds format because the Irrlicht Engine
3d graphic artist, and so the texture mapping is not very nice in this model. did not support the .an8 format when I wrote this tutorial. I am a very bad
Luckily I am a better programmer than artist, and so the Irrlicht Engine 3d graphic artist, and so the texture mapping is not very nice in this model.
is able to create a cool texture mapping for me: Just use the mesh manipulator Luckily I am a better programmer than artist, and so the Irrlicht Engine
and create a planar texture mapping for the mesh. If you want to see the mapping is able to create a cool texture mapping for me: Just use the mesh manipulator
I made with Anim8or, uncomment this line. I also did not figure out how to and create a planar texture mapping for the mesh. If you want to see the mapping
set the material right in Anim8or, it has a specular light color which I don't really I made with Anim8or, uncomment this line. I also did not figure out how to
like. I'll switch it off too with this code. set the material right in Anim8or, it has a specular light color which I don't really
*/ like. I'll switch it off too with this code.
*/
scene::IAnimatedMesh* mesh = smgr->getMesh(
"../../media/room.3ds"); scene::IAnimatedMesh* mesh = smgr->getMesh(
"../../media/room.3ds");
smgr->getMeshManipulator()->makePlanarTextureMapping(
mesh->getMesh(0), 0.004f); smgr->getMeshManipulator()->makePlanarTextureMapping(
mesh->getMesh(0), 0.004f);
scene::ISceneNode* node = 0;
scene::ISceneNode* node = 0;
node = smgr->addAnimatedMeshSceneNode(mesh);
node->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg")); node = smgr->addAnimatedMeshSceneNode(mesh);
node->getMaterial(0).SpecularColor.set(0,0,0,0); node->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
node->getMaterial(0).SpecularColor.set(0,0,0,0);
/*
Now, for the first special effect: Animated water. It works like this: The /*
WaterSurfaceSceneNode takes a mesh as input and makes Now, for the first special effect: Animated water. It works like this: The
it wave like a water surface. And if we let this scene node use a nice WaterSurfaceSceneNode takes a mesh as input and makes
material like the EMT_REFLECTION_2_LAYER, it looks really cool. We are it wave like a water surface. And if we let this scene node use a nice
doing this with the next few lines of code. As input mesh, we create a hill material like the EMT_REFLECTION_2_LAYER, it looks really cool. We are
plane mesh, without hills. But any other mesh could be used for this, you could doing this with the next few lines of code. As input mesh, we create a hill
even use the room.3ds (which would look really strange) if you wanted to. plane mesh, without hills. But any other mesh could be used for this, you could
*/ even use the room.3ds (which would look really strange) if you wanted to.
*/
// add animated water
// add animated water
mesh = smgr->addHillPlaneMesh("myHill",
core::dimension2d<f32>(20,20), mesh = smgr->addHillPlaneMesh("myHill",
core::dimension2d<u32>(40,40), 0, 0, core::dimension2d<f32>(20,20),
core::dimension2d<f32>(0,0), core::dimension2d<u32>(40,40), 0, 0,
core::dimension2d<f32>(10,10)); 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 = 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->setMaterialTexture(0, driver->getTexture("../../media/stones.jpg"));
node->setMaterialTexture(1, driver->getTexture("../../media/water.jpg"));
node->setMaterialType(video::EMT_REFLECTION_2_LAYER);
node->setMaterialType(video::EMT_REFLECTION_2_LAYER);
/*
The second special effect is very basic, I bet you saw it already in some /*
Irrlicht Engine demos: A transparent billboard combined with a dynamic light. The second special effect is very basic, I bet you saw it already in some
We simply create a light scene node, let it fly around, an to make it look Irrlicht Engine demos: A transparent billboard combined with a dynamic light.
more cool, we attach a billboard scene node to it. We simply create a light scene node, let it fly around, an to make it look
*/ more cool, we attach a billboard scene node to it.
*/
// create light
// create light
node = smgr->addLightSceneNode(0, core::vector3df(0,0,0),
video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 1200.0f); node = smgr->addLightSceneNode(0, core::vector3df(0,0,0),
scene::ISceneNodeAnimator* anim = 0; video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 1200.0f);
anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f); scene::ISceneNodeAnimator* anim = 0;
node->addAnimator(anim); anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f);
anim->drop(); node->addAnimator(anim);
anim->drop();
// attach billboard to light
// attach billboard to light
node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));
node->setMaterialFlag(video::EMF_LIGHTING, false); node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));
node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp")); node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
node->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));
/*
The next special effect is a lot more interesting: A particle system. The particle /*
system in the Irrlicht Engine is quit modular and extensible and yet easy to use. The next special effect is a lot more interesting: A particle system. The particle
There is a particle system scene node into which you can put particle emitters, which system in the Irrlicht Engine is quit modular and extensible and yet easy to use.
make particles come out of nothing. These emitters are quite flexible and usually have There is a particle system scene node into which you can put particle emitters, which
lots of parameters like direction, amount and color of the particles they should create. make particles come out of nothing. These emitters are quite flexible and usually have
There are different emitters, for example a point emitter which lets particles pop out lots of parameters like direction, amount and color of the particles they should create.
at a fixed point. If the particle emitters available in the engine are not enough for There are different emitters, for example a point emitter which lets particles pop out
you, you can easily create your own ones, you'll simply have to create a class derived at a fixed point. If the particle emitters available in the engine are not enough for
from the IParticleEmitter interface and attach it to the particle system using setEmitter(). you, you can easily create your own ones, you'll simply have to create a class derived
In this example we create a box particle emitter, which creates particles randomly from the IParticleEmitter interface and attach it to the particle system using setEmitter().
inside a box. The parameters define the box, direction of the particles, minimal and In this example we create a box particle emitter, which creates particles randomly
maximal new particles per second, color and minimal and maximal livetime of the particles. inside a box. The parameters define the box, direction of the particles, minimal and
maximal new particles per second, color and minimal and maximal livetime of the particles.
Because only with emitters particle system would be a little bit boring,
there are particle affectors, which modify particles during they fly around. They can Because only with emitters particle system would be a little bit boring,
be added to the particle system, simulating additional effects like gravity or wind. there are particle affectors, which modify particles during they fly around. They can
The particle affector we use in this example is an affector, which modifies the color be added to the particle system, simulating additional effects like gravity or wind.
of the particles: It lets them fade out. Like the particle emitters, additional The particle affector we use in this example is an affector, which modifies the color
particle affectors can also be implemented by you, simply derive a class from of the particles: It lets them fade out. Like the particle emitters, additional
IParticleAffector and add it with addAffector(). particle affectors can also be implemented by you, simply derive a class from
IParticleAffector and add it with addAffector().
After we set a nice material to the particle system, we have a cool looking camp fire.
By adjusting material, texture, particle emitter and affector parameters, it is also After we set a nice material to the particle system, we have a cool looking camp fire.
easily possible to create smoke, rain, explosions, snow, and so on. By adjusting material, texture, particle emitter and affector parameters, it is also
*/ easily possible to create smoke, rain, explosions, snow, and so on.
*/
// create a particle system
// create a particle system
scene::IParticleSystemSceneNode* ps = 0;
ps = smgr->addParticleSystemSceneNode(false); scene::IParticleSystemSceneNode* ps = 0;
ps->setPosition(core::vector3df(-70,60,40)); ps = smgr->addParticleSystemSceneNode(false);
ps->setScale(core::vector3df(2,2,2)); ps->setPosition(core::vector3df(-70,60,40));
ps->setScale(core::vector3df(2,2,2));
ps->setParticleSize(core::dimension2d<f32>(20.0f, 20.0f));
ps->setParticleSize(core::dimension2d<f32>(20.0f, 20.0f));
scene::IParticleEmitter* em = ps->createBoxEmitter(
core::aabbox3d<f32>(-7,0,-7,7,1,7), scene::IParticleEmitter* em = ps->createBoxEmitter(
core::vector3df(0.0f,0.06f,0.0f), core::aabbox3d<f32>(-7,0,-7,7,1,7),
80,100, core::vector3df(0.0f,0.06f,0.0f),
video::SColor(0,255,255,255), video::SColor(0,255,255,255), 80,100,
800,2000); video::SColor(0,255,255,255), video::SColor(0,255,255,255),
800,2000);
ps->setEmitter(em);
em->drop(); ps->setEmitter(em);
em->drop();
scene::IParticleAffector* paf =
ps->createFadeOutParticleAffector(); scene::IParticleAffector* paf =
ps->createFadeOutParticleAffector();
ps->addAffector(paf);
paf->drop(); ps->addAffector(paf);
paf->drop();
ps->setMaterialFlag(video::EMF_LIGHTING, false);
ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); ps->setMaterialFlag(video::EMF_LIGHTING, false);
ps->setMaterialTexture(0, driver->getTexture("../../media/fire.bmp")); ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA); ps->setMaterialTexture(0, driver->getTexture("../../media/fire.bmp"));
ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);
/*
As our last special effect, we want a dynamic shadow be casted from an animated /*
character. For this we load a DirectX .x model and place it into our world. Next we add a volumetric light node, which adds a glowing fake area light to
For creating the shadow, we simply need to call addShadowVolumeSceneNode(). the scene. Like with the billboards and particle systems we also assign a
The color of shadows is only adjustable globally for all shadows, by calling texture for the desired effect, though this time we'll use a texture animator
ISceneManager::setShadowColor(). Voila, here is our dynamic shadow. to create the illusion of a magical glowing area effect.
*/
Because the character is a little bit too small for this scene, we make it bigger scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(0, -1,
using setScale(). And because the character is lighted by a dynamic light, we need 32, // Subdivisions on U axis
to normalize the normals to make the lighting on it correct. This is always necessary if 32, // Subdivisions on V axis
the scale of a dynamic lighted model is not (1,1,1). Otherwise it would get too dark or video::SColor(0, 255, 255, 255), // foot color
too bright because the normals will be scaled too. video::SColor(0, 0, 0, 0) // tail color
*/ );
// add animated character if (n)
{
mesh = smgr->getMesh("../../media/dwarf.x"); n->setScale(core::vector3df(56.0f, 56.0f, 56.0f));
scene::IAnimatedMeshSceneNode* anode = 0; n->setPosition(core::vector3df(-120,50,40));
anode = smgr->addAnimatedMeshSceneNode(mesh); // load textures for animation
anode->setPosition(core::vector3df(-50,20,-60)); core::array<video::ITexture*> textures;
anode->setAnimationSpeed(15); for (s32 g=7; g > 0; --g)
{
//volumetric lighting core::stringc tmp;
scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(NULL, -1, tmp = "../../media/portal";
32, //Sub Divid U tmp += g;
32, //Sub Divid V tmp += ".bmp";
video::SColor(0, 180, 180, 180), //foot colour video::ITexture* t = driver->getTexture( tmp.c_str () );
video::SColor(0, 0, 0, 0) //tail colour textures.push_back(t);
); }
if (n) { // create texture animator
n->setScale(core::vector3df(56.0f, 56.0f, 56.0f)); scene::ISceneNodeAnimator *glow = smgr->createTextureAnimator(textures, 150);
n->setPosition(core::vector3df(-120,60,40));
video::SMaterial& mat = n->getMaterial(0); // add the animator
mat.setTexture(0, smgr->getVideoDriver()->getTexture("../../media/lightFalloff.png")); n->addAnimator(glow);
}
// drop the animator because it was created with a create() function
// add shadow glow->drop();
anode->addShadowVolumeSceneNode(); }
smgr->setShadowColor(video::SColor(150,0,0,0));
/*
// make the model a little bit bigger and normalize its normals As our last special effect, we want a dynamic shadow be casted from an animated
// because of this for correct lighting character. For this we load a DirectX .x model and place it into our world.
anode->setScale(core::vector3df(2,2,2)); For creating the shadow, we simply need to call addShadowVolumeSceneNode().
anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); The color of shadows is only adjustable globally for all shadows, by calling
ISceneManager::setShadowColor(). Voila, here is our dynamic shadow.
/*
Finally we simply have to draw everything, that's all. Because the character is a little bit too small for this scene, we make it bigger
*/ using setScale(). And because the character is lighted by a dynamic light, we need
to normalize the normals to make the lighting on it correct. This is always necessary if
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(); the scale of a dynamic lighted model is not (1,1,1). Otherwise it would get too dark or
camera->setPosition(core::vector3df(-50,50,-150)); too bright because the normals will be scaled too.
*/
// disable mouse cursor
device->getCursorControl()->setVisible(false); // add animated character
mesh = smgr->getMesh("../../media/dwarf.x");
int lastFPS = -1; scene::IAnimatedMeshSceneNode* anode = 0;
while(device->run()) anode = smgr->addAnimatedMeshSceneNode(mesh);
if (device->isWindowActive()) anode->setPosition(core::vector3df(-50,20,-60));
{ anode->setAnimationSpeed(15);
driver->beginScene(true, true, 0);
// add shadow
smgr->drawAll(); anode->addShadowVolumeSceneNode();
smgr->setShadowColor(video::SColor(150,0,0,0));
driver->endScene();
// make the model a little bit bigger and normalize its normals
int fps = driver->getFPS(); // because of this for correct lighting
anode->setScale(core::vector3df(2,2,2));
if (lastFPS != fps) anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
{
core::stringw str = L"Irrlicht Engine - SpecialFX example ["; /*
str += driver->getName(); Finally we simply have to draw everything, that's all.
str += "] FPS:"; */
str += fps;
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
device->setWindowCaption(str.c_str()); camera->setPosition(core::vector3df(-50,50,-150));
lastFPS = fps;
} // disable mouse cursor
} device->getCursorControl()->setVisible(false);
device->drop();
int lastFPS = -1;
return 0;
} while(device->run())
if (device->isWindowActive())
{
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;
}