Sophie

Sophie

distrib > Mandriva > 2010.1 > x86_64 > media > contrib-release > by-pkgid > 58828b263d8f56d90ac336dea07a4586 > files > 739

irrlicht-doc-1.6.1-1mdv2010.1.x86_64.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<title>Irrlicht Engine: Tutorial 8: SpecialFX</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
</head><body>
<table class="irrlicht" >
  <tr valign="middle"> 
    <td><font size="2"><a class="qindex" href="index.html"><font color="#FFFFFF">Home</font></a> 
      | <a class="qindex" href="namespaces.html"><font color="#FFFFFF">Namespaces</font></a> 
      | <a class="qindex" href="hierarchy.html"><font color="#FFFFFF">Hierarchy</font></a> 
      | <a class="qindex" href="classes.html"><font color="#FFFFFF">Alphabetical 
      List</font></a> | <a class="qindex" href="annotated.html"><font color="#FFFFFF"> 
      Class list</font></a> | <a class="qindex" href="files.html"><font color="#FFFFFF">Files</font></a> 
      | <a class="qindex" href="namespacemembers.html"><font color="#FFFFFF"> 
      Namespace&nbsp;Members</font></a> | <a class="qindex" href="functions.html"><font color="#FFFFFF">Class 
      members</font></a> | <a class="qindex" href="globals.html"><font color="#FFFFFF">File 
      members</font></a> | <a class="qindex" href="pages.html"><font color="#FFFFFF">Tutorials</font></a></font> </td>
  </tr>
</table>
<!-- Generated by Doxygen 1.5.6 -->
<div class="contents">
<h1><a class="anchor" name="example008">Tutorial 8: SpecialFX </a></h1><div align="center">
<img src="008shot.jpg" alt="008shot.jpg">
</div>
 <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>
We start like in some tutorials before. Please note that this time, the 'shadows' flag in <a class="el" href="namespaceirr.html#baf4d8719cc26b0d30813abf85e47c76" title="Creates an Irrlicht device. The Irrlicht device is the root object for using the...">createDevice()</a> is set to true, for we want to have a dynamic shadow casted from an animated character. If this example runs too 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. <div class="fragment"><pre class="fragment"><span class="preprocessor">#include &lt;<a class="code" href="irrlicht_8h.html" title="Main header file of the irrlicht, the only file needed to include.">irrlicht.h</a>&gt;</span>
<span class="preprocessor">#include &lt;iostream&gt;</span>

<span class="keyword">using namespace </span>irr;

<span class="preprocessor">#ifdef _MSC_VER</span>
<span class="preprocessor"></span><span class="preprocessor">#pragma comment(lib, "Irrlicht.lib")</span>
<span class="preprocessor"></span><span class="preprocessor">#endif</span>
<span class="preprocessor"></span>
<span class="keywordtype">int</span> main()
{
        <span class="comment">// ask if user would like shadows</span>

        <span class="keywordtype">char</span> i;
        printf(<span class="stringliteral">"Please press 'y' if you want to use realtime shadows.\n"</span>);

        std::cin &gt;&gt; i;

        <span class="keyword">const</span> <span class="keywordtype">bool</span> shadows = (i == <span class="charliteral">'y'</span>);

        <span class="comment">// ask user for driver</span>

        <a class="code" href="namespaceirr_1_1video.html#e35a6de6d436c76107ad157fe42356d0" title="An enum for all types of drivers the Irrlicht Engine supports.">video::E_DRIVER_TYPE</a> driverType;

        printf(<span class="stringliteral">"Please select the driver you want for this example:\n"</span>\
                <span class="stringliteral">" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"</span>\
                <span class="stringliteral">" (d) Software Renderer\n (e) Burning's Software Renderer\n"</span>\
                <span class="stringliteral">" (f) NullDevice\n (otherKey) exit\n\n"</span>);

        std::cin &gt;&gt; i;

        <span class="keywordflow">switch</span>(i)
        {
                <span class="keywordflow">case</span> <span class="charliteral">'a'</span>: driverType = <a class="code" href="namespaceirr_1_1video.html#e35a6de6d436c76107ad157fe42356d04691ca314f9018f508dcf2c57dcaacec" title="Direct3D 9 device, only available on Win32 platforms.">video::EDT_DIRECT3D9</a>;<span class="keywordflow">break</span>;
                <span class="keywordflow">case</span> <span class="charliteral">'b'</span>: driverType = <a class="code" href="namespaceirr_1_1video.html#e35a6de6d436c76107ad157fe42356d08cc3807f6f28404f3424ad7e31b3142f" title="Direct3D8 device, only available on Win32 platforms.">video::EDT_DIRECT3D8</a>;<span class="keywordflow">break</span>;
                <span class="keywordflow">case</span> <span class="charliteral">'c'</span>: driverType = <a class="code" href="namespaceirr_1_1video.html#e35a6de6d436c76107ad157fe42356d02715182a79f1cb8e2826fd68a8150a53" title="OpenGL device, available on most platforms.">video::EDT_OPENGL</a>;   <span class="keywordflow">break</span>;
                <span class="keywordflow">case</span> <span class="charliteral">'d'</span>: driverType = <a class="code" href="namespaceirr_1_1video.html#e35a6de6d436c76107ad157fe42356d01598cd235a1a6bd052e2011b559e8995" title="The Irrlicht Engine Software renderer.">video::EDT_SOFTWARE</a>; <span class="keywordflow">break</span>;
                <span class="keywordflow">case</span> <span class="charliteral">'e'</span>: driverType = <a class="code" href="namespaceirr_1_1video.html#e35a6de6d436c76107ad157fe42356d0e85481da26159b967191ccc6de1e4a05" title="The Burning&amp;#39;s Software Renderer, an alternative software renderer.">video::EDT_BURNINGSVIDEO</a>;<span class="keywordflow">break</span>;
                <span class="keywordflow">case</span> <span class="charliteral">'f'</span>: driverType = <a class="code" href="namespaceirr_1_1video.html#e35a6de6d436c76107ad157fe42356d0cfdbd476cbfd4d05e72f9adffcc42210" title="Null driver, useful for applications to run the engine without visualisation.">video::EDT_NULL</a>;     <span class="keywordflow">break</span>;
                <span class="keywordflow">default</span>: <span class="keywordflow">return</span> 1;
        }
</pre></div><p>
Create device and exit if creation failed. We make the stencil flag optional to avoid slow screen modes for runs without shadows. <div class="fragment"><pre class="fragment">        IrrlichtDevice *device =
                <a class="code" href="namespaceirr.html#baf4d8719cc26b0d30813abf85e47c76" title="Creates an Irrlicht device. The Irrlicht device is the root object for using the...">createDevice</a>(driverType, core::dimension2d&lt;u32&gt;(640, 480),
                16, <span class="keyword">false</span>, shadows);

        <span class="keywordflow">if</span> (device == 0)
                <span class="keywordflow">return</span> 1; <span class="comment">// could not create selected driver.</span>

        video::IVideoDriver* driver = device-&gt;getVideoDriver();
        scene::ISceneManager* smgr = device-&gt;getSceneManager();
</pre></div><p>
For our environment, we load a .3ds file. It is a small room I modelled with Anim8or and exported into the 3ds format because the Irrlicht Engine does not support the .an8 format. 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 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. <div class="fragment"><pre class="fragment">        scene::IAnimatedMesh* mesh = smgr-&gt;getMesh(<span class="stringliteral">"../../media/room.3ds"</span>);

        smgr-&gt;getMeshManipulator()-&gt;makePlanarTextureMapping(mesh-&gt;getMesh(0), 0.004f);

        scene::ISceneNode* node = 0;

        node = smgr-&gt;addAnimatedMeshSceneNode(mesh);
        node-&gt;setMaterialTexture(0, driver-&gt;getTexture(<span class="stringliteral">"../../media/wall.jpg"</span>));
        node-&gt;getMaterial(0).SpecularColor.set(0,0,0,0);
</pre></div><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 EMT_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 want to. <div class="fragment"><pre class="fragment">        mesh = smgr-&gt;addHillPlaneMesh( <span class="stringliteral">"myHill"</span>,
                core::dimension2d&lt;f32&gt;(20,20),
                core::dimension2d&lt;u32&gt;(40,40), 0, 0,
                core::dimension2d&lt;f32&gt;(0,0),
                core::dimension2d&lt;f32&gt;(10,10));

        node = smgr-&gt;addWaterSurfaceSceneNode(mesh-&gt;getMesh(0), 3.0f, 300.0f, 30.0f);
        node-&gt;setPosition(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(0,7,0));

        node-&gt;setMaterialTexture(0, driver-&gt;getTexture(<span class="stringliteral">"../../media/stones.jpg"</span>));
        node-&gt;setMaterialTexture(1, driver-&gt;getTexture(<span class="stringliteral">"../../media/water.jpg"</span>));

        node-&gt;setMaterialType(<a class="code" href="namespaceirr_1_1video.html#c8e9b6c66f7cebabd1a6d30cbc5430f1d8574343353ed8ade6e78bc04d64b6ae" title="A reflecting material with an optional non reflecting texture layer.">video::EMT_REFLECTION_2_LAYER</a>);
</pre></div><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, and to make it look more cool, we attach a billboard scene node to it. <div class="fragment"><pre class="fragment">        <span class="comment">// create light</span>

        node = smgr-&gt;addLightSceneNode(0, <a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(0,0,0),
                video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 800.0f);
        scene::ISceneNodeAnimator* anim = 0;
        anim = smgr-&gt;createFlyCircleAnimator (<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(0,150,0),250.0f);
        node-&gt;addAnimator(anim);
        anim-&gt;drop();

        <span class="comment">// attach billboard to light</span>

        node = smgr-&gt;addBillboardSceneNode(node, core::dimension2d&lt;f32&gt;(50, 50));
        node-&gt;setMaterialFlag(<a class="code" href="namespaceirr_1_1video.html#8a3bc00ae8137535b9fbc5f40add70d3cea597a2692b8415486a464a7f954d34" title="Will this material be lighted? Default: true.">video::EMF_LIGHTING</a>, <span class="keyword">false</span>);
        node-&gt;setMaterialType(<a class="code" href="namespaceirr_1_1video.html#c8e9b6c66f7cebabd1a6d30cbc5430f11b5a814c4466aca2943ff056003a50d1" title="A transparent material.">video::EMT_TRANSPARENT_ADD_COLOR</a>);
        node-&gt;setMaterialTexture(0, driver-&gt;getTexture(<span class="stringliteral">"../../media/particlewhite.bmp"</span>));
</pre></div><p>
The next special effect is a lot more interesting: A particle system. The particle system in the Irrlicht Engine is quite modular and extensible, but yet easy to use. There is a particle system scene node into which you can put a particle emitter, which makes 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 create.<p>
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(). 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 lifetime of the particles.<p>
Because only with emitters particle system would be a little bit boring, there are particle affectors which modify particles while they fly around. Affectors can be added to a particle system for 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().<p>
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. <div class="fragment"><pre class="fragment">        <span class="comment">// create a particle system</span>

        scene::IParticleSystemSceneNode* ps =
                smgr-&gt;addParticleSystemSceneNode(<span class="keyword">false</span>);

        scene::IParticleEmitter* em = ps-&gt;createBoxEmitter(
                core::aabbox3d&lt;f32&gt;(-7,0,-7,7,1,7), <span class="comment">// emitter size</span>
                <a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(0.0f,0.06f,0.0f),   <span class="comment">// initial direction</span>
                80,100,                             <span class="comment">// emit rate</span>
                video::SColor(0,255,255,255),       <span class="comment">// darkest color</span>
                video::SColor(0,255,255,255),       <span class="comment">// brightest color</span>
                800,2000,0,                         <span class="comment">// min and max age, angle</span>
                <a class="code" href="namespaceirr_1_1core.html#f6dc5c45ff13e7712758c827ff58676b" title="Typedef for an f32 dimension.">core::dimension2df</a>(10.f,10.f),         <span class="comment">// min size</span>
                <a class="code" href="namespaceirr_1_1core.html#f6dc5c45ff13e7712758c827ff58676b" title="Typedef for an f32 dimension.">core::dimension2df</a>(20.f,20.f));        <span class="comment">// max size</span>

        ps-&gt;setEmitter(em); <span class="comment">// this grabs the emitter</span>
        em-&gt;drop(); <span class="comment">// so we can drop it here without deleting it</span>

        scene::IParticleAffector* paf = ps-&gt;createFadeOutParticleAffector();

        ps-&gt;addAffector(paf); <span class="comment">// same goes for the affector</span>
        paf-&gt;drop();

        ps-&gt;setPosition(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(-70,60,40));
        ps-&gt;setScale(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(2,2,2));
        ps-&gt;setMaterialFlag(<a class="code" href="namespaceirr_1_1video.html#8a3bc00ae8137535b9fbc5f40add70d3cea597a2692b8415486a464a7f954d34" title="Will this material be lighted? Default: true.">video::EMF_LIGHTING</a>, <span class="keyword">false</span>);
        ps-&gt;setMaterialFlag(<a class="code" href="namespaceirr_1_1video.html#8a3bc00ae8137535b9fbc5f40add70d34bc03b7b9dd19e577bf909313ea62510" title="May be written to the zbuffer or is it readonly. Default: true.">video::EMF_ZWRITE_ENABLE</a>, <span class="keyword">false</span>);
        ps-&gt;setMaterialTexture(0, driver-&gt;getTexture(<span class="stringliteral">"../../media/fire.bmp"</span>));
        ps-&gt;setMaterialType(<a class="code" href="namespaceirr_1_1video.html#c8e9b6c66f7cebabd1a6d30cbc5430f126529b1cf18ec4d8073809f6bd15ebbb" title="Makes the material transparent based on the vertex alpha value.">video::EMT_TRANSPARENT_VERTEX_ALPHA</a>);
</pre></div><p>
Next we add a volumetric light node, which adds a glowing fake area light to the scene. Like with the billboards and particle systems we also assign a texture for the desired effect, though this time we'll use a texture animator to create the illusion of a magical glowing area effect. <div class="fragment"><pre class="fragment">        scene::IVolumeLightSceneNode * n = smgr-&gt;addVolumeLightSceneNode(0, -1,
                                32,                              <span class="comment">// Subdivisions on U axis</span>
                                32,                              <span class="comment">// Subdivisions on V axis</span>
                                video::SColor(0, 255, 255, 255), <span class="comment">// foot color</span>
                                video::SColor(0, 0, 0, 0));      <span class="comment">// tail color</span>

        <span class="keywordflow">if</span> (n)
        {
                n-&gt;setScale(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(56.0f, 56.0f, 56.0f));
                n-&gt;setPosition(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(-120,50,40));

                <span class="comment">// load textures for animation</span>
                core::array&lt;video::ITexture*&gt; textures;
                <span class="keywordflow">for</span> (<a class="code" href="namespaceirr.html#c66849b7a6ed16e30ebede579f9b47c6" title="32 bit signed variable.">s32</a> g=7; g &gt; 0; --g)
                {
                        <a class="code" href="namespaceirr_1_1core.html#de1071a878633f2f6d8a75c5d11fec19" title="Typedef for character strings.">core::stringc</a> tmp;
                        tmp = <span class="stringliteral">"../../media/portal"</span>;
                        tmp += g;
                        tmp += <span class="stringliteral">".bmp"</span>;
                        video::ITexture* t = driver-&gt;getTexture( tmp.c_str() );
                        textures.push_back(t);
                }

                <span class="comment">// create texture animator</span>
                scene::ISceneNodeAnimator* glow = smgr-&gt;createTextureAnimator(textures, 150);

                <span class="comment">// add the animator</span>
                n-&gt;addAnimator(glow);

                <span class="comment">// drop the animator because it was created with a create() function</span>
                glow-&gt;drop();
        }
</pre></div><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.<p>
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. <div class="fragment"><pre class="fragment">        <span class="comment">// add animated character</span>

        mesh = smgr-&gt;getMesh(<span class="stringliteral">"../../media/dwarf.x"</span>);
        scene::IAnimatedMeshSceneNode* anode = 0;

        anode = smgr-&gt;addAnimatedMeshSceneNode(mesh);
        anode-&gt;setPosition(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(-50,20,-60));
        anode-&gt;setAnimationSpeed(15);

        <span class="comment">// add shadow</span>
        anode-&gt;addShadowVolumeSceneNode();
        smgr-&gt;setShadowColor(video::SColor(150,0,0,0));

        <span class="comment">// make the model a little bit bigger and normalize its normals</span>
        <span class="comment">// because of the scaling, for correct lighting</span>
        anode-&gt;setScale(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(2,2,2));
        anode-&gt;setMaterialFlag(<a class="code" href="namespaceirr_1_1video.html#8a3bc00ae8137535b9fbc5f40add70d33efe2d4921909a842adfc44dacc74520" title="Normalizes normals. Default: false.">video::EMF_NORMALIZE_NORMALS</a>, <span class="keyword">true</span>);
</pre></div><p>
Finally we simply have to draw everything, that's all. <div class="fragment"><pre class="fragment">        scene::ICameraSceneNode* camera = smgr-&gt;addCameraSceneNodeFPS();
        camera-&gt;setPosition(<a class="code" href="namespaceirr_1_1core.html#06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(-50,50,-150));

        <span class="comment">// disable mouse cursor</span>
        device-&gt;getCursorControl()-&gt;setVisible(<span class="keyword">false</span>);

        <a class="code" href="namespaceirr.html#c66849b7a6ed16e30ebede579f9b47c6" title="32 bit signed variable.">s32</a> lastFPS = -1;

        <span class="keywordflow">while</span>(device-&gt;run())
        <span class="keywordflow">if</span> (device-&gt;isWindowActive())
        {
                driver-&gt;beginScene(<span class="keyword">true</span>, <span class="keyword">true</span>, 0);

                smgr-&gt;drawAll();

                driver-&gt;endScene();

                <span class="keyword">const</span> <a class="code" href="namespaceirr.html#c66849b7a6ed16e30ebede579f9b47c6" title="32 bit signed variable.">s32</a> fps = driver-&gt;getFPS();

                <span class="keywordflow">if</span> (lastFPS != fps)
                {
                        <a class="code" href="namespaceirr_1_1core.html#ef83fafbb1b36fcce44c07c9be23a7f2" title="Typedef for wide character strings.">core::stringw</a> str = L<span class="stringliteral">"Irrlicht Engine - SpecialFX example ["</span>;
                        str += driver-&gt;getName();
                        str += <span class="stringliteral">"] FPS:"</span>;
                        str += fps;

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

        device-&gt;drop();

        <span class="keywordflow">return</span> 0;
}
</pre></div> </div>
<hr size="1">
<address style="align: right;">
<small> </small>
</address>
<table width="100%" border="0" cellspacing="0" cellpadding="2">
  <tr> 
    <td width="0"> <div align="left"><small><a href="http://irrlicht.sourceforge.net" target="_blank"><img src="irrlicht.png" alt="The Irrlicht Engine" align="middle" border=0 width=88 height=31></a></small></div></td>
    <td> <div align="left"><small><em><font size="2">The <a href="http://irrlicht.sourceforge.net" target="_blank">Irrlicht 
        Engine</a> Documentation &copy; 2003-2009 by Nikolaus Gebhardt. Generated 
        on Sun Jan 10 09:24:06 2010 by <a href="http://www.doxygen.org" target="_blank">Doxygen</a> 
        (1.5.6)</font></em></small></div></td>
  </tr>
</table>
<address style="align: right;">
</address>
</body>
</html>