irrlicht/examples.net/Examples_CSharp/example08.cs

290 lines
12 KiB
C#

/*
In this tutorial, we explore some of the special effects that are possible with Irrlicht.
*/
using System;
using System.Text;
using System.IO;
using Irrlicht;
using Irrlicht.Video;
using Irrlicht.GUI;
using Irrlicht.Core;
using Irrlicht.Scene;
namespace _08._SpecialFX
{
class Program
{
string path="../../../../media/";
IrrlichtDevice device;
/// <summary>
/// Main entry point for the program.
/// </summary>
/// <param name="args">Arguments to pass the software.</param>
[STAThread]
static void Main(string[] args)
{
Program prog = new Program();
prog.run();
}
public void run()
{
/* At first, we let the user select the driver type,
then start up the engine, set a caption, and get a
pointer to the video driver.
*/
// ask user for driver
DriverType driverType;
// Ask user to select driver:
StringBuilder sb = new StringBuilder();
sb.Append("Please select the driver you want for this example:\n");
sb.Append("\n(a) Direct3D 9.0c\n(b) Direct3D 8.1\n(c) OpenGL 1.5");
sb.Append("\n(d) Software Renderer\n(e) Apfelbaum Software Renderer");
sb.Append("\n(f) Null Device\n(otherKey) exit\n\n");
// Get the user's input:
TextReader tIn = Console.In;
TextWriter tOut = Console.Out;
string input = string.Empty;
bool shadows = false;
tOut.Write("Do you want to use realtime shadows? (y/n)");
input = tIn.ReadLine();
if (input == "y") shadows = true;
tOut.Write(sb.ToString());
input = tIn.ReadLine();
// Select device based on user's input:
switch (input)
{
case "a":
driverType = DriverType.DIRECT3D9;
break;
case "b":
driverType = DriverType.DIRECT3D8;
break;
case "c":
driverType = DriverType.OPENGL;
break;
case "d":
driverType = DriverType.SOFTWARE;
break;
case "e":
driverType = DriverType.SOFTWARE2;
break;
case "f":
driverType = DriverType.NULL_DRIVER;
break;
default:
return;
}
/* 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.*/
/*
* From the unmanaged API documentation:
* stencilbuffer:
* Specifies if the stencil buffer should be enabled.
* Set this to true, if you want the engine be able to draw stencil buffer shadows.
* Note that not all devices are able to use the stencil buffer.
* If they don't no shadows will be drawn.
*/
device = new IrrlichtDevice(driverType, new Dimension2D(1024, 768), 32, false, shadows, true);
if (device == null)
{
tOut.Write("Device creation failed.");
return;
}
ISceneManager smgr=device.SceneManager;
IVideoDriver driver=device.VideoDriver;
/* 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 set the material right in Anim8or, it has an emissive light color
which I don't really like. I'll switch it off too with this code.*/
IAnimatedMesh mesh= smgr.GetMesh(
path+"room.3ds");
smgr.MeshManipulator.MakePlanarTextureMapping(
mesh.GetMesh(0), 0.008f);
ISceneNode node = smgr.AddAnimatedMeshSceneNode(mesh, null, 0);
node.SetMaterialTexture(
0,driver.GetTexture(path+"wall.jpg"));
node.GetMaterial(0).EmissiveColor.Set(0,0,0,0);
// Add a shadow to the room if it is not dark enough
/* The result is interesting but not exactly what I was expecting!
Try for yourself... I think this could be a little problem in the
Irrlicht.NET wrapper but I promise I will investigate further to see
if I can make it work as intended
Forum Article (http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=10584)
*/
// IAnimatedMeshSceneNode xnode = (IAnimatedMeshSceneNode)node;
// xnode.AddShadowVolumeSceneNode();
//
/*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.*/
mesh = smgr.AddHillPlaneMesh("myHill",
new Dimension2Df(20,20),
new Dimension2D(40,40),new Material(),0,
new Dimension2Df(0,0),
new Dimension2Df(10,10));
node = smgr.AddWaterSurfaceSceneNode(mesh.GetMesh(0),3.0f,300.0f,30.0f,null,0);
node.Position=new Vector3D(0,7,0);
node.SetMaterialTexture(0, driver.GetTexture(path+"water.jpg"));
node.SetMaterialTexture(1, driver.GetTexture(path+"stones.jpg"));
node.SetMaterialType(MaterialType.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.
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
node = smgr.AddLightSceneNode(null, new Vector3D(0,0,0),
new Colorf(1.0f, 0.6f, 0.7f, 1.0f), 600.0f,0);
ISceneNodeAnimator anim = smgr.CreateFlyCircleAnimator(new Vector3D(0,150,0),250.0f,0.0005f);
node.AddAnimator(anim);
// attach billboard to light
node = smgr.AddBillboardSceneNode(node, new Dimension2Df(50, 50),new Vector3D(),0);
node.SetMaterialFlag(MaterialFlag.LIGHTING, false);
node.SetMaterialType(MaterialType.TRANSPARENT_ADD_COLOR);
node.SetMaterialTexture(0,
driver.GetTexture(path+"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. 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.
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
articles, 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 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.*/
IParticleSystemSceneNode ps = smgr.AddParticleSystemSceneNode(
false,null,0,new Vector3D(-70,60,40),new Vector3D(),new Vector3D(2,2,2));
ps.ParticleSize= new Dimension2Df(20,10);
IParticleEmitter em = ps.CreateBoxEmitter(
new Box3D(-7,0,-7,7,1,7),new Vector3D(0.0f,0.03f,0.0f),
80,100,
new Color(0,255,255,255),new Color(0,255,255,255),
800,2000,0);
ps.SetEmitter(em);
IParticleAffector paf=
ps.CreateFadeOutParticleAffector(new Color(),1500);
ps.AddAffector(paf);
ps.SetMaterialFlag(MaterialFlag.LIGHTING, false);
ps.SetMaterialTexture(0,
driver.GetTexture(path+"particle.bmp"));
ps.SetMaterialType(MaterialType.TRANSPARENT_VERTEX_ALPHA);
/*As our last special effect, we want a dynamic shadow be casted from an animated
character. For this we load a quake 2 .md2 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. 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.*/
mesh = smgr.GetMesh(path+"faerie.md2");
IAnimatedMeshSceneNode anode = smgr.AddAnimatedMeshSceneNode(mesh,null,0);
anode.Position = new Vector3D(-50,45,-60);
anode.SetMD2Animation(MD2AnimationType.STAND);
anode.SetMaterialTexture(0,
driver.GetTexture(path+"Faerie5.BMP"));
// add shadow
anode.AddShadowVolumeSceneNode();
smgr.ShadowColor=new Color(220,0,0,0);
// make the model a little bit bigger and normalize its normals
// because of this for correct lighting
anode.Scale= new Vector3D(2,2,2);
anode.SetMaterialFlag(MaterialFlag.NORMALIZE_NORMALS, true);
/*Finally we simply have to draw everything, that's all.*/
ICameraSceneNode camera = smgr.AddCameraSceneNodeFPS();
camera.Position=new Vector3D(-50,50,-150);
// Remove the mouse cursor:
device.CursorControl.Visible = false;
int lastFPS=-1;
while (device.Run())
{
if (device.WindowActive)
{
device.VideoDriver.BeginScene(true, true, new Color(0, 200, 200, 200));
device.SceneManager.DrawAll();
device.VideoDriver.EndScene();
int fps = device.VideoDriver.FPS;
if (lastFPS != fps)
{
device.WindowCaption = "Irrlicht Engine - SpecialFX tutorial [" +
device.VideoDriver.Name + "] FPS:" + fps.ToString();
lastFPS = fps;
}
}
}
/*
In the end, delete the Irrlicht device.
*/
// Instead of device->drop, we'll use:
GC.Collect();
}
}
}
// Retrieved from "http://www.irrforge.org/index.php/CS_Tutorial_8"
// This page has been accessed 247 times. This page was last modified 19:28, 23 Jan 2006.