mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-25 02:00:30 +01:00
8310a3fbad
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6000 dfc29bdd-3216-0410-991c-e03cc46cb475
279 lines
17 KiB
HTML
279 lines
17 KiB
HTML
<html>
|
|
<head>
|
|
<title>Irrlicht Engine Tutorial</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
</head>
|
|
|
|
<body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
|
|
<br>
|
|
<table width="95%" border="0" cellspacing="0" cellpadding="2" align="center">
|
|
<tr>
|
|
<td bgcolor="#666699" width="10"><b><a href="http://irrlicht.sourceforge.net" target="_blank"><img src="../../media/irrlichtlogo.jpg" width="88" height="31" border="0"></a></b></td>
|
|
<td bgcolor="#666699" width="100%">
|
|
<div align="center">
|
|
<div align="left"><b><font color="#FFFFFF">Tutorial 8. Special Effects</font></b></div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr bgcolor="#eeeeff">
|
|
<td height="90" colspan="2">
|
|
<div align="left">
|
|
<p>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 surface scene node. </p>
|
|
<p>The program which is described here will look like this:</p>
|
|
<p align="center"><img src="../../media/008shot.jpg" width="259" height="204"><br>
|
|
</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<table width="95%" border="0" cellspacing="0" cellpadding="2" align="center">
|
|
<tr>
|
|
<td bgcolor="#666699"> <b><font color="#FFFFFF">Lets start!</font></b></td>
|
|
</tr>
|
|
<tr>
|
|
<td height="90" bgcolor="#eeeeff" valign="top"> <div align="left">
|
|
<div align="left">
|
|
<p>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 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 buffer, and disables
|
|
shadows by itself, but just in case the demo runs slow on your hardware.</p>
|
|
<table width="95%" border="0" cellspacing="2" cellpadding="0" bgcolor="#CCCCCC" align="center">
|
|
<tr>
|
|
<td> <pre><font color="#008000" size="2">#include <irrlicht.h>
|
|
#include <iostream><br>
|
|
</font><font size="2"><b>using namespace </b>irr;
|
|
|
|
<font color="#008000">#pragma comment(lib, "Irrlicht.lib")
|
|
|
|
</font><b>int </b>main()
|
|
{
|
|
// ask user for driver<br> video::E_DRIVER_TYPE driverType;<br>
|
|
printf("Please select the driver you want for this example:\n"\<br> " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\<br> " (d) Software Renderer\n (e) Apfelbaum Software Renderer\n"\<br> " (f) NullDevice\n (otherKey) exit\n\n");<br><br> char i;<br> std::cin >> i;<br><br> switch(i)<br> {<br> case 'a': driverType = video::EDT_DIRECT3D9;break;<br> case 'b': driverType = video::EDT_DIRECT3D8;break;<br> case 'c': driverType = video::EDT_OPENGL; break;<br> case 'd': driverType = video::EDT_SOFTWARE; break;<br> case 'e': driverType = video::EDT_BURNINGSVIDEO;break;<br> case 'f': driverType = video::EDT_NULL; break;<br> default: return 1;<br> }
|
|
|
|
// create device and exit if creation failed<br> 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();<font face="Courier New">
|
|
</font></font></pre>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<p> 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 did not support the .an8 format when I wrote this tutorial.
|
|
I am a very bad 3d graphic artist, and so the texture mapping is not
|
|
very nice in this model. Luckily I am a better programmer than artist,
|
|
and so the Irrlicht Engine is able to create a cool texture mapping
|
|
for me: Just use the mesh manipulator and create a planar texture
|
|
mapping for the mesh. If you want to see the mapping I made with Anim8or,
|
|
uncomment this line. I also did not figure out how to<br>
|
|
set the material right in Anim8or, it has a specular light color
|
|
which I don't really<br>
|
|
like. I'll switch it off too with this code.</p>
|
|
<table width="95%" border="0" cellspacing="2" cellpadding="0" bgcolor="#CCCCCC" align="center">
|
|
<tr>
|
|
<td> <pre><font size=2> scene::IAnimatedMesh* mesh = smgr->getMesh(
|
|
<font color="#FF0000">"../../media/room.3ds"</font>);
|
|
|
|
smgr->getMeshManipulator()->makePlanarTextureMapping(
|
|
mesh->getMesh(<font color="#800080">0</font>), <font color="#800080">0.008f</font>);
|
|
|
|
scene::ISceneNode* node = <font color="#800080">0</font>;
|
|
|
|
node = smgr->addAnimatedMeshSceneNode(mesh);
|
|
node->setMaterialTexture(<font color="#800080">0</font>, driver->getTexture(<font color="#FF0000">"../../media/wall.jpg"</font>));
|
|
node->getMaterial(0).SpecularColor.set(0,0,0,0);</font></pre></td>
|
|
</tr>
|
|
</table>
|
|
<p> Now, for the first special effect: Animated water. It works like
|
|
this: The WaterSurfaceSceneNode takes a mesh as input and makes it
|
|
wave like a water surface. And if we let this scene node use a nice
|
|
material like the MT_REFLECTION_2_LAYER, it looks really cool. We
|
|
are doing this with the next few lines of code. As input mesh, we
|
|
create a hill 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. </p>
|
|
<table width="95%" border="0" cellspacing="2" cellpadding="0" bgcolor="#CCCCCC" align="center">
|
|
<tr>
|
|
<td> <pre> mesh = smgr->addHillPlaneMesh(<font color="#FF0000">"myHill"</font>,
|
|
core::dimension2d<f32>(<font color="#800080">20</font>,<font color="#800080">20</font>),
|
|
core::dimension2d<s32>(<font color="#800080">40</font>,<font color="#800080">40</font>), <font color="#800080">0</font>, <font color="#800080">0</font>,
|
|
core::dimension2d<f32>(<font color="#800080">0</font>,<font color="#800080">0</font>),
|
|
core::dimension2d<f32>(<font color="#800080">10</font>,<font color="#800080">10</font>));
|
|
|
|
node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(<font color="#800080">0</font>), <font color="#800080">3.0f</font>, <font color="#800080">300.0f</font>, <font color="#800080">30.0f</font>);
|
|
node->setPosition(core::vector3df(<font color="#800080">0</font>,<font color="#800080">7</font>,<font color="#800080">0</font>));
|
|
|
|
node->setMaterialTexture(<font color="#800080">0</font>, driver->getTexture(<font color="#FF0000">"../../media/stones.jpg"</font>));
|
|
node->setMaterialTexture(<font color="#800080">1</font>, driver->getTexture(<font color="#FF0000">"../../media/water.jpg"</font>));
|
|
|
|
node->setMaterialType(video::EMT_REFLECTION_2_LAYER<font size=3 face="Courier New">);
|
|
</font></pre></td>
|
|
</tr>
|
|
</table>
|
|
<p> 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. 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.</p>
|
|
<table width="95%" border="0" cellspacing="2" cellpadding="0" bgcolor="#CCCCCC" align="center">
|
|
<tr>
|
|
<td> <pre><font size=2> <font color="#0A246A"><i>// create light
|
|
|
|
</i></font> node = smgr->addLightSceneNode(<font color="#800080">0</font>, core::vector3df(<font color="#800080">0</font>,<font color="#800080">0</font>,<font color="#800080">0</font>),
|
|
video::SColorf(<font color="#800080">1.0f</font>, <font color="#800080">0.6f</font>, <font color="#800080">0.7f</font>, <font color="#800080">1.0f</font>), <font color="#800080">600.0f</font>);
|
|
scene::ISceneNodeAnimator* anim = <font color="#800080">0</font>;
|
|
anim = smgr->createFlyCircleAnimator (core::vector3df(<font color="#800080">0</font>,<font color="#800080">150</font>,<font color="#800080">0</font>),<font color="#800080">250.0f</font>);
|
|
node->addAnimator(anim);
|
|
anim->drop();
|
|
|
|
<font color="#0A246A"><i>// attach billboard to light
|
|
|
|
</i></font> node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(<font color="#800080">50</font>, <font color="#800080">50</font>));
|
|
node->setMaterialFlag(video::EMF_LIGHTING, <b>false</b>);
|
|
node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
|
|
node->setMaterialTexture(<font color="#800080">0</font>, driver->getTexture(<font color="#FF0000">"../../media/particlewhite.bmp"</font>));
|
|
|
|
</font></pre></td>
|
|
</tr>
|
|
</table>
|
|
<p> 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. There is a particle system scene node into which
|
|
you can put particle emitters, which make particles come out of nothing.
|
|
These emitters are quite flexible and usually have lots of parameters
|
|
like direction, amount and color of the particles they should create.<br>
|
|
There are different emitters, for example a point emitter which lets
|
|
particles pop out at a fixed point. If the particle emitters available
|
|
in the engine are not enough for you, you can easily create your own
|
|
ones, you'll simply have to create a class derived from the IParticleEmitter
|
|
interface and attach it to the particle system using setEmitter().<br>
|
|
In this example we create a box particle emitter, which creates particles
|
|
randomly 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.</p>
|
|
<p> 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 be added to the particle system, simulating
|
|
additional effects like gravity or wind. The particle affector we
|
|
use in this example is an affector, which modifies the color of the
|
|
particles: It lets them fade out. Like the particle emitters, additional
|
|
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 easily possible to create smoke, rain, explosions,
|
|
snow, and so on.<br>
|
|
</p>
|
|
</div>
|
|
<table width="95%" border="0" cellspacing="2" cellpadding="0" bgcolor="#CCCCCC" align="center">
|
|
<tr>
|
|
<td> <pre><font size="2"> scene::IParticleSystemSceneNode* ps = <font color="#800080">0</font>;
|
|
ps = smgr->addParticleSystemSceneNode(<b>false</b>);
|
|
ps->setPosition(core::vector3df(-<font color="#800080">70</font>,<font color="#800080">60</font>,<font color="#800080">40</font>));
|
|
ps->setScale(core::vector3df(<font color="#800080">2</font>,<font color="#800080">2</font>,<font color="#800080">2</font>));
|
|
|
|
ps->setParticleSize(core::dimension2d<f32>(<font color="#800080">20.0f</font>, <font color="#800080">10.0f</font>));
|
|
|
|
scene::IParticleEmitter* em = ps->createBoxEmitter(
|
|
core::aabbox3d<f32>(-<font color="#800080">7</font>,<font color="#800080">0</font>,-<font color="#800080">7</font>,<font color="#800080">7</font>,<font color="#800080">1</font>,<font color="#800080">7</font>),
|
|
core::vector3df(<font color="#800080">0.0f</font>,<font color="#800080">0.03f</font>,<font color="#800080">0.0f</font>),
|
|
<font color="#800080">80</font>,<font color="#800080">100</font>,
|
|
video::SColor(<font color="#800080">0</font>,<font color="#800080">255</font>,<font color="#800080">255</font>,<font color="#800080">255</font>), video::SColor(<font color="#800080">0</font>,<font color="#800080">255</font>,<font color="#800080">255</font>,<font color="#800080">255</font>),
|
|
<font color="#800080">800</font>,<font color="#800080">2000</font>);
|
|
|
|
ps->setEmitter(em);
|
|
em->drop();
|
|
|
|
scene::IParticleAffector* paf =
|
|
ps->createFadeOutParticleAffector();
|
|
|
|
ps->addAffector(paf);
|
|
paf->drop();
|
|
|
|
ps->setMaterialFlag(video::EMF_LIGHTING, <b>false</b>);
|
|
ps->setMaterialTexture(<font color="#800080">0</font>, driver->getTexture(<font color="#FF0000">"../../media/particle.bmp"</font>));
|
|
ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA)<font size="2">;</font></font></pre></td>
|
|
</tr>
|
|
</table>
|
|
<p> 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. For creating the shadow, we simply need to call addShadowVolumeSceneNode().
|
|
The color of shadows is only adjustable globally for all shadows, by
|
|
calling ISceneManager::setShadowColor(). Voila, here is our dynamic
|
|
shadow.<br>
|
|
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 the scale of a dynamic lighted
|
|
model is not (1,1,1). Otherwise it would get too dark or too bright
|
|
because the normals will be scaled too.</p>
|
|
<table width="95%" border="0" cellspacing="2" cellpadding="0" bgcolor="#CCCCCC" align="center">
|
|
<tr>
|
|
<td><pre><font size=2> mesh = smgr->getMesh(<font color="#FF0000">"../../media/dwarf.x"</font>);
|
|
scene::IAnimatedMeshSceneNode* anode = <font color="#800080">0</font>;
|
|
|
|
anode = smgr->addAnimatedMeshSceneNode(mesh);
|
|
anode->setPosition(core::vector3df(-<font color="#800080">50</font>,<font color="#800080">20</font>,-<font color="#800080">60</font>));
|
|
anode->setAnimationSpeed(15);
|
|
<font color="#0A246A">
|
|
// add shadow</font>
|
|
anode->addShadowVolumeSceneNode();
|
|
smgr->setShadowColor(video::SColor(<font color="#800080">220</font>,<font color="#800080">0</font>,<font color="#800080">0</font>,<font color="#800080">0</font>));
|
|
</font><font size=2><font color="#0A246A">
|
|
// make the model a little bit bigger and normalize its normals <br> // because of this for correct lighting</font><br> anode->setScale(core::vector3df(2,2,2));<br> anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);</font><font size=3 face="Courier New"><br></font></pre></td>
|
|
</tr>
|
|
</table>
|
|
<p> Finally we simply have to draw everything, that's all.</p>
|
|
<table width="95%" border="0" cellspacing="2" cellpadding="0" bgcolor="#CCCCCC" align="center">
|
|
<tr>
|
|
<td><pre><font size=2> scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
|
|
camera->setPosition(core::vector3df(-<font color="#800080">50</font>,<font color="#800080">50</font>,-<font color="#800080">150</font>));
|
|
|
|
|
|
<b>int </b>lastFPS = -<font color="#800080">1</font>;
|
|
|
|
<b>while</b>(device->run())
|
|
{
|
|
driver->beginScene(<b>true</b>, <b>true</b>, <font color="#800080">0</font>);
|
|
|
|
smgr->drawAll();
|
|
|
|
driver->endScene();
|
|
|
|
<b>int </b>fps = driver->getFPS();
|
|
|
|
<b>if </b>(lastFPS != fps)
|
|
{
|
|
core::stringw str = L"Irrlicht Engine - SpecialFX example [";<br> str += driver->getName();<br> str += "] FPS:";<br> str += fps;<br><br> device->setWindowCaption(str.c_str());<br> lastFPS = fps;<br> }
|
|
}
|
|
|
|
device->drop();
|
|
|
|
<b>return </b><font color="#800080">0</font>;
|
|
}
|
|
|
|
</font>
|
|
</pre></td>
|
|
</tr>
|
|
</table>
|
|
<p> </p>
|
|
<p> </p>
|
|
<p> </p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<p> </p>
|
|
</body>
|
|
</html>
|