Пример #1
0
        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;

            tOut.Write(sb.ToString());
            string 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;
            }

            // Create device and exit if creation fails:
            device = new IrrlichtDevice(driverType, new Dimension2D(1024, 768), 32, false, true, true);

            if (device == null)
            {
                tOut.Write("Device creation failed.");
                return;
            }

            /*
             * Get a pointer to the video driver and the SceneManager so that
             * we do not always have to write device->getVideoDriver() and
             * device->getSceneManager().
             */

            ISceneManager smgr   = device.SceneManager;
            IVideoDriver  driver = device.VideoDriver;

            device.FileSystem.AddZipFileArchive(path + "map-20kdm2.pk3");

            IAnimatedMesh q3levelmesh = smgr.GetMesh("20kdm2.bsp");
            ISceneNode    q3node      = null;

            if (q3levelmesh != null)
            {
                q3node = smgr.AddOctTreeSceneNode(q3levelmesh.GetMesh(0), null, 0);
            }

            /*So far so good, we've loaded the quake 3 level like in tutorial 2.
            *  Now, here comes something different: We create a triangle selector. A
            *  triangle selector is a class which can fetch the triangles from scene
            *  nodes for doing different things with them, for example collision
            *  detection. There are different triangle selectors, and all can be
            *  created with the ISceneManager. In this example, we create an
            *  OctTreeTriangleSelector, which optimizes the triangle output a little
            *  bit by reducing it like an octree. This is very useful for huge meshes
            *  like quake 3 levels.
            *  After we created the triangle selector, we attach it to the q3node.
            *  This is not necessary, but in this way, we do not need to care for the
            *  selector, for example dropping it after we do not need it anymore.*/

            ITriangleSelector selector = null;

            if (q3node != null)
            {
                q3node.Position = new Vector3D(-1370, -130, -1400);
                selector        = smgr.CreateOctTreeTriangleSelector(
                    q3levelmesh.GetMesh(0), q3node, 128);
                // not implemented but not necessary
                //q3node.TriangleSelector=selector;
            }

            /*We add a first person shooter camera to the scene for being able to move in
             * the quake 3 level like in tutorial 2. But this, time, we add a special
             * animator to the camera: A Collision Response animator. This thing modifies
             * the scene node to which it is attached to in that way, that it may no
             * more move through walls and is affected by gravity. The only thing we have
             * to tell the animator is how the world looks like, how big the scene node is,
             * how gravity and so on. After the collision response animator is attached to
             * the camera, we do not have to do anything more for collision detection,
             * anything is done automaticly, all other collision detection code below is
             * for picking. And please note another cool feature: The collsion response
             * animator can be attached also to all other scene nodes, not only to cameras.
             * And it can be mixed with other scene node animators. In this way, collision
             * detection and response in the Irrlicht engine is really, really easy.
             * Now we'll take a closer look on the parameters of
             * createCollisionResponseAnimator(). The first parameter is the TriangleSelector,
             * which specifies how the world, against collision detection is done looks like.
             * The second parameter is the scene node, which is the object, which is affected
             * by collision detection, in our case it is the camera. The third defines how big
             * the object is, it is the radius of an ellipsoid. Try it out and change the radius
             * to smaller values, the camera will be able to move closer to walls after this.
             * The next parameter is the direction and speed of gravity. You could set it to
             * (0,0,0) to disable gravity. And the last value is just a translation: Without
             * this, the ellipsoid with which collision detection is done would be around
             * the camera, and the camera would be in the middle of the ellipsoid. But as
             * human beings, we are used to have our eyes on top of the body, with which
             * we collide with our world, not in the middle of it. So we place the scene
             * node 50 units over the center of the ellipsoid with this parameter. And
             * that's it, collision detection works now.
             */
            ICameraSceneNode camera = smgr.AddCameraSceneNodeFPS(null, 100, 300, 0);

            camera.Position = new Vector3D(-100, 50, -150);
            ISceneNodeAnimator anim = smgr.CreateCollisionResponseAnimator(
                selector, camera, new Vector3D(30, 50, 30),
                new Vector3D(0, -3, 0), new Vector3D(0, 50, 0), 0);

            camera.AddAnimator(anim);

            /*Because collision detection is no big deal in irrlicht, I'll describe how
             * to do two different types of picking in the next section. But before this,
             * I'll prepare the scene a little. I need three animated characters which we
             * could pick later, a dynamic light for lighting them, a billboard for drawing
             * where we found an intersection, and, yes, I need to get rid of this mouse
             * cursor. :)*/
            //disable mouse cursor
            device.CursorControl.Visible = false;

            // add billboard
            IBillboardSceneNode bill = smgr.AddBillboardSceneNode(
                null, new Dimension2Df(20, 20), new Vector3D(), 0);

            bill.SetMaterialType(MaterialType.TRANSPARENT_ADD_COLOR);
            bill.SetMaterialTexture(0, driver.GetTexture(
                                        path + "particle.bmp"));
            bill.SetMaterialFlag(MaterialFlag.LIGHTING, false);
            bill.SetMaterialFlag(MaterialFlag.ZBUFFER, false);
            Material material = new Material();

            material.Texture1 = driver.GetTexture(
                path + "faerie2.bmp");
            material.Lighting = true;

            IAnimatedMeshSceneNode node   = null;
            IAnimatedMesh          faerie = smgr.GetMesh(
                path + "faerie.md2");

            if (faerie != null)
            {
                node          = smgr.AddAnimatedMeshSceneNode(faerie, null, 0);
                node.Position = new Vector3D(-70, 0, -90);
                node.SetMD2Animation(MD2AnimationType.RUN);
                node.SetMaterial(0, material);

                node          = smgr.AddAnimatedMeshSceneNode(faerie, null, 0);
                node.Position = new Vector3D(-70, 0, -30);
                node.SetMD2Animation(MD2AnimationType.SALUTE);
                node.SetMaterial(0, material);

                node          = smgr.AddAnimatedMeshSceneNode(faerie, null, 0);
                node.Position = new Vector3D(-70, 0, -60);
                node.SetMD2Animation(MD2AnimationType.JUMP);
                node.SetMaterial(0, material);
            }

            material.Texture1 = null;
            material.Lighting = false;

            //Add a light
            smgr.AddLightSceneNode(null, new Vector3D(-60, 100, 400),
                                   new Colorf(1.0f, 1.0f, 1.0f, 1.0f), 600, 0);

            /*For not making it too complicated, I'm doing picking inside the drawing
             * loop. We take two pointers for storing the current and the last selected
             * scene node and start the loop.*/
            ISceneNode selectedSceneNode     = null;
            ISceneNode lastSelectedSceneNode = null;

            int lastFPS = -1;

            while (device.Run())
            {
                if (device.WindowActive)
                {
                    device.VideoDriver.BeginScene(true, true, new Color(0, 200, 200, 200));
                    device.SceneManager.DrawAll();

                    /*After we've drawn the whole scene whit smgr->drawAll(), we'll do the
                     * first picking: We want to know which triangle of the world we are
                     * looking at. In addition, we want the exact point of the quake 3
                     * level we are looking at. For this, we create a 3d line starting at
                     * the position of the camera and going through the lookAt-target of it.
                     * Then we ask the collision manager if this line collides with a
                     * triangle of the world stored in the triangle selector. If yes, we draw
                     * the 3d triangle and set the position of the billboard to the intersection
                     * point.*/
                    Line3D line = new Line3D();
                    line.start = camera.Position;
                    line.end   = line.start +
                                 (camera.Target - line.start).Normalize() * 1000;
                    Vector3D   intersection;
                    Triangle3D tri;
                    if (smgr.SceneCollisionManager.GetCollisionPoint(
                            line, selector, out intersection, out tri))
                    {
                        bill.Position = intersection;

                        driver.SetTransform(TransformationState.WORLD, new Matrix4());
                        driver.SetMaterial(material);
                        driver.Draw3DTriangle(tri, new Color(0, 255, 0, 0));
                    }

                    /*Another type of picking supported by the Irrlicht Engine is scene node
                     * picking based on bouding boxes. Every scene node has got a bounding box,
                     * and because of that, it's very fast for example to get the scene node
                     * which the camera looks at. Again, we ask the collision manager for this,
                     * and if we've got a scene node, we highlight it by disabling Lighting in
                     * its material, if it is not the billboard or the quake 3 level.*/
                    selectedSceneNode = smgr.SceneCollisionManager.
                                        GetSceneNodeFromCameraBB(camera, 0);

                    if (lastSelectedSceneNode != null)
                    {
                        lastSelectedSceneNode.SetMaterialFlag(
                            MaterialFlag.LIGHTING, true);
                    }

                    if (selectedSceneNode == q3node ||
                        selectedSceneNode == bill)
                    {
                        selectedSceneNode = null;
                    }

                    if (selectedSceneNode != null)
                    {
                        selectedSceneNode.SetMaterialFlag(
                            MaterialFlag.LIGHTING, false);
                    }
                    lastSelectedSceneNode = selectedSceneNode;

                    /*That's it, we just have to finish drawing.*/

                    driver.EndScene();

                    int fps = device.VideoDriver.FPS;
                    if (lastFPS != fps)
                    {
                        device.WindowCaption = "Irrlicht Engine - Quake 3 Map example [" +
                                               device.VideoDriver.Name + "] FPS:" + fps.ToString();
                        lastFPS = fps;
                    }
                }
            }

            /*
             * In the end, delete the Irrlicht device.
             */
            // Instead of device->drop, we'll use:
            GC.Collect();
        }
Пример #2
0
    public void runIndoorTest()
    {
        device = new IrrlichtDevice(SelectedDriverType,
                                    new Dimension2D(800, 600), 16, false, true, false);

        device.EventReceiver = this;
        device.ResizeAble    = true;
        device.WindowCaption = "Irrlicht.NET indoor test";

        // load some textures and meshes

        ITexture texSydney = device.VideoDriver.GetTexture(@"..\..\media\sydney.bmp");
        ITexture texWall   = device.VideoDriver.GetTexture(@"..\..\media\wall.jpg");
        ITexture texLogo   = device.VideoDriver.GetTexture(@"..\..\media\irrlichtlogoaligned.jpg");

        Irrlicht.Scene.IAnimatedMesh mesh =
            device.SceneManager.GetMesh(@"..\..\media\sydney.md2");

        if (mesh == null)
        {
            System.Windows.Forms.MessageBox.Show(
                @"Could not load mesh ..\..\media\sydney.md2, exiting.",
                "Problem starting program");
            return;
        }

        // add a cube to the scene

        ISceneNode node = device.SceneManager.AddCubeSceneNode(15,
                                                               null, -1, new Vector3D(30, -15, 0));

        node.SetMaterialTexture(0, texWall);
        node.SetMaterialFlag(Irrlicht.Video.MaterialFlag.LIGHTING, false);

        // add an animator to the cube to make it rotate

        ISceneNodeAnimator anim = device.SceneManager.CreateRotationAnimator(new Vector3D(0.2f, 0.2f, 0));

        node.AddAnimator(anim);

        // add animated mesh

        IAnimatedMeshSceneNode anode = device.SceneManager.AddAnimatedMeshSceneNode(mesh, null, -1);

        anode.SetMaterialTexture(0, texSydney);
        anode.SetMaterialFlag(MaterialFlag.LIGHTING, false);

        anode.Scale    = new Vector3D(2, 2, 2);
        anode.Position = new Vector3D(0, -20, 0);

        // add a shadow

        Shadow = anode.AddShadowVolumeSceneNode();
        if (Shadow != null)
        {
            Shadow.Visible = false;
        }

        // where no light there no shadow
        device.SceneManager.AddLightSceneNode(null, new Vector3D(20, 100, -50),
                                              new Colorf(255, 0, 0), 200, -1);

        // add quake 3 level

        device.FileSystem.AddZipFileArchive("../../media/map-20kdm2.pk3");

        IAnimatedMesh q3levelmesh = device.SceneManager.GetMesh("20kdm2.bsp");
        ISceneNode    q3node      = device.SceneManager.AddOctTreeSceneNode(q3levelmesh, null, -1);

        q3node.Position = new Vector3D(-1370, -130, -1400);

        // create octtree triangle selector for q3 mesh

        ITriangleSelector selector = device.SceneManager.CreateOctTreeTriangleSelector(
            q3levelmesh.GetMesh(0), q3node, 128);

        // add billboard

        IBillboardSceneNode bill = device.SceneManager.AddBillboardSceneNode(null,
                                                                             new Dimension2Df(20, 20), new Vector3D(0, 0, 0), -1);

        bill.SetMaterialType(MaterialType.TRANSPARENT_ADD_COLOR);
        bill.SetMaterialTexture(0, device.VideoDriver.GetTexture("../../media/particle.bmp"));
        bill.SetMaterialFlag(MaterialFlag.LIGHTING, false);
        bill.SetMaterialFlag(MaterialFlag.ZBUFFER, false);

        // create camera

        ICameraSceneNode cam =
            device.SceneManager.AddCameraSceneNodeFPS(null, 100, 300, -1);

        cam.Position = new Vector3D(20, 300, -50);

        // make cursor invisible
        device.CursorControl.Visible = false;

        // create collision animator and add it to the camera

        ISceneNodeAnimator collAnim = device.SceneManager.CreateCollisionResponseAnimator(
            selector, cam,
            new Vector3D(30, 50, 30),            // size of ellipsoid around camera
            new Vector3D(0, -3, 0),              // gravity
            new Vector3D(0, 50, 0),              // translation
            0.0005f);                            // sliding value

        cam.AddAnimator(collAnim);

        // load some font and set it into the skin

        IGUIFont font = device.GUIEnvironment.GetFont("../../media/fonthaettenschweiler.bmp");

        device.GUIEnvironment.Skin.Font = font;

        // add some gui stuff

        device.GUIEnvironment.AddMessageBox("Hello World",
                                            "I'm a Irrlicht.NET MessageBox. Please press SPACE to close me.", true,
                                            MessageBoxFlag.OK | MessageBoxFlag.CANCEL, null, -1);

        // start drawing loop

        int fps = 0;

        while (device.Run())
        {
            if (device.WindowActive)
            {
                device.VideoDriver.BeginScene(true, true, new Color(255, 0, 0, 50));

                // draw scene

                device.SceneManager.DrawAll();
                device.GUIEnvironment.DrawAll();

                // do some collision testing

                Line3D line = new Line3D();
                line.start = cam.Position;
                line.end   = ((cam.Target - line.start).Normalize() * 1000.0f) + line.start;

                Vector3D   intersection = new Vector3D();
                Triangle3D tri          = new Triangle3D();

                if (device.SceneManager.SceneCollisionManager.GetCollisionPoint(
                        line, selector, out intersection, out tri))
                {
                    bill.Position = intersection;

                    Material mat = new Material();
                    mat.Lighting = false;

                    device.VideoDriver.SetTransform(TransformationState.WORLD, new Matrix4());
                    device.VideoDriver.SetMaterial(mat);
                    device.VideoDriver.Draw3DTriangle(tri, new Color(0, 255, 0, 0));
                }

                // draw 2d logo

                device.VideoDriver.Draw2DImage(
                    texLogo, new Position2D(10, 10),
                    new Rect(0, 0, 88, 31),
                    new Rect(new Position2D(0, 0), device.VideoDriver.ScreenSize),
                    new Color(0xffffff), false);

                // draw some text
                font.Draw("Press 'S' to toggle the visibility of the realtime shadow.",
                          new Position2D(120, 20), new Color(100, 150, 200, 200));

                device.VideoDriver.EndScene();

                if (fps != device.VideoDriver.FPS)
                {
                    fps = device.VideoDriver.FPS;
                    device.WindowCaption = "Irrlicht.NET test (primitives:" +
                                           device.VideoDriver.PrimitiveCountDrawn + ") fps:" + fps;
                }
            }
        }
    }
Пример #3
0
        public void run()
        {
            /* The start of the main function starts like in most other example.
             * We ask the user for the desired renderer and start it up.
             */

            // 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;

            tOut.Write(sb.ToString());
            string 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;
            }

            // Create device and exit if creation fails:
            IrrlichtDevice device = new IrrlichtDevice(
                driverType, new Dimension2D(640, 480), 32, false, true, true);

            if (device == null)
            {
                tOut.Write("Device creation failed.");
                return;
            }

            /* set this as event receiver*/
            device.EventReceiver = this;
            /*************************************************/

            /* First, we add standard stuff to the scene: A nice irrlicht engine logo,
             * a small help text, a user controlled camera, and we disable the mouse
             * cursor.*/
            ISceneManager   smgr   = device.SceneManager;
            IVideoDriver    driver = device.VideoDriver;
            IGUIEnvironment env    = device.GUIEnvironment;

            driver.SetTextureCreationFlag(TextureCreationFlag.ALWAYS_32_BIT, true);

            // add irrlicht logo
            env.AddImage(driver.GetTexture(path + "irrlichtlogoalpha.tga"),
                         new Position2D(10, 10), true, null, 0, "");

            // add some help text
            IGUIStaticText text = env.AddStaticText(
                "Press 'W' to change wireframe mode\nPress 'D' to toggle detail map",
                new Rect(10, 453, 200, 475), true, true, null, -1);

            // add camera
            ICameraSceneNode camera =
                smgr.AddCameraSceneNodeFPS(null, 100.0f, 1200.0f, -1);

            camera.Position = new Vector3D(1900 * 2, 255 * 2, 3700 * 2);
            camera.Target   = new Vector3D(2397 * 2, 343 * 2, 2700 * 2);
            camera.FarValue = 12000.0f;

            // disable mouse cursor
            device.CursorControl.Visible = false;

            /* Here comes the terrain renderer scene node: We add it just like any other scene
             * node to the scene using ISceneManager::addTerrainSceneNode(). The only parameter
             * we use is a file name to the heightmap we use. A heightmap is simply a gray
             * scale texture. The terrain renderer loads it and creates the 3D terrain
             * from it.
             * To make the terrain look more big, we change the scale factor of it to
             * (40, 4.4, 40). Because we don't have any dynamic lights in the scene, we
             * switch off the lighting, and we set the file terrain-texture.jpg as texture
             * for the terrain and detailmap3.jpg as second texture, called detail map.
             * At last, we set the scale values for the texture: The first texture will be
             * repeated only one time over the whole terrain, and the second one (detail map)
             * 20 times.
             */
            // add terrain scene node
            terrain = smgr.AddTerrainSceneNode(
                path + "terrain-heightmap.bmp", null, -1,
                new Vector3D(), new Vector3D(40, 4.4f, 40), new Color(255, 255, 255, 255));

            terrain.SetMaterialFlag(MaterialFlag.LIGHTING, false);
            terrain.SetMaterialType(MaterialType.DETAIL_MAP);
            terrain.SetMaterialTexture(0, driver.GetTexture(path + "terrain-texture.jpg"));
            terrain.SetMaterialTexture(1, driver.GetTexture(path + "detailmap3.jpg"));


            terrain.ScaleTexture(1.0f, 20.0f);

            /* To be able to do collision with the terrain, we create a triangle selector.
             * If you want to know what triangle selectors do, just take a look into the
             * collision tutorial. The terrain triangle selector works together with the
             * terrain. To demonstrate this, we create a collision response animator and
             * attach it to the camera, so that the camera will not be able to fly through
             * the terrain.*/
            // create triangle selector for the terrain
            ITriangleSelector selector =
                smgr.CreateTerrainTriangleSelector(terrain, 0);

            // create collision response animator and attach it to the camera
            ISceneNodeAnimator anim = smgr.CreateCollisionResponseAnimator(
                selector, camera, new Vector3D(60, 100, 60),
                new Vector3D(0, 0, 0),
                new Vector3D(0, 50, 0), 0.0005f);

            camera.AddAnimator(anim);

            //we add the skybox which we already used in lots of Irrlicht examples.
            driver.SetTextureCreationFlag(TextureCreationFlag.CREATE_MIP_MAPS, false);

            smgr.AddSkyBoxSceneNode(
                driver.GetTexture(path + "irrlicht2_up.jpg"),
                driver.GetTexture(path + "irrlicht2_dn.jpg"),
                driver.GetTexture(path + "irrlicht2_lf.jpg"),
                driver.GetTexture(path + "irrlicht2_rt.jpg"),
                driver.GetTexture(path + "irrlicht2_ft.jpg"),
                driver.GetTexture(path + "irrlicht2_bk.jpg"), null, 0);

            driver.SetTextureCreationFlag(TextureCreationFlag.CREATE_MIP_MAPS, true);



            /* That's it, draw everything. Now you know how to use terrain
             * in Irrlicht.
             */
            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 - Terrain example [" +
                                               device.VideoDriver.Name + "] FPS:" + fps.ToString();
                        lastFPS = fps;
                    }
                }
            }


            /*
             * In the end, delete the Irrlicht device.
             */
            // Instead of device.drop, we'll use:
            GC.Collect();
        }
Пример #4
0
    public void runTerrainTest()
    {
        device = new IrrlichtDevice(SelectedDriverType,
                                    new Dimension2D(800, 600), 16, false, false, false);

        device.EventReceiver = this;
        device.ResizeAble    = true;
        device.WindowCaption = "Irrlicht.NET terrain test";

        // create a camera

        ICameraSceneNode cam =
            device.SceneManager.AddCameraSceneNodeFPS(null, 100, 1200, -1);

        cam.Position = new Vector3D(1900 * 2, 255 * 2, 3700 * 2);
        cam.Target   = new Vector3D(2397 * 2, 343 * 2, 2700 * 2);
        cam.FarValue = 12000.0f;

        // create the terrain

        ITerrainSceneNode terrain = device.SceneManager.AddTerrainSceneNode(
            "../../media/terrain-heightmap.bmp",
            null, -1, new Vector3D(), new Vector3D(40, 4.4f, 40), new Color(255, 255, 255, 255));

        terrain.SetMaterialFlag(MaterialFlag.LIGHTING, false);
        terrain.SetMaterialType(MaterialType.DETAIL_MAP);
        terrain.SetMaterialTexture(0, device.VideoDriver.GetTexture("../../media/terrain-texture.jpg"));
        terrain.SetMaterialTexture(1, device.VideoDriver.GetTexture("../../media/detailmap3.jpg"));

        terrain.ScaleTexture(1.0f, 20.0f);

        // create terrain triangle selector for collision

        ITriangleSelector selector = device.SceneManager.CreateTerrainTriangleSelector(terrain, 0);

        // create collision animator and add it to the camera

        ISceneNodeAnimator collAnim = device.SceneManager.CreateCollisionResponseAnimator(
            selector, cam,
            new Vector3D(30, 50, 30),           // size of ellipsoid around camera
            new Vector3D(0, 0, 0),              // gravity
            new Vector3D(0, 50, 0),             // translation
            0.0005f);                           // sliding value

        cam.AddAnimator(collAnim);

        // add sky box

        device.SceneManager.AddSkyBoxSceneNode(
            device.VideoDriver.GetTexture("../../media/irrlicht2_up.jpg"),
            device.VideoDriver.GetTexture("../../media/irrlicht2_dn.jpg"),
            device.VideoDriver.GetTexture("../../media/irrlicht2_lf.jpg"),
            device.VideoDriver.GetTexture("../../media/irrlicht2_rt.jpg"),
            device.VideoDriver.GetTexture("../../media/irrlicht2_ft.jpg"),
            device.VideoDriver.GetTexture("../../media/irrlicht2_bk.jpg"),
            null, -1);

        // make cursor invisible
        device.CursorControl.Visible = false;

        // draw everything

        while (device.Run())
        {
            if (device.WindowActive)
            {
                device.VideoDriver.BeginScene(true, true, new Color(255, 0, 0, 50));

                device.SceneManager.DrawAll();
                device.GUIEnvironment.DrawAll();

                device.VideoDriver.EndScene();
            }
        }
    }
        public virtual bool ContactMade(ITriangleSelector selector, Triangle triangle, Vector3 iPoint, int edge)
        {
            Vector3 n = triangle.Normal;

            if (edge != -1)
            {
                n = Vector3.Normalize(position - iPoint);
            }

            float d = n.Y;

            if (d > groundSlope)
            {
                onGround = true;
                velocity.Y = 0;
                groundNormal += n;
            }
            else if (d < -groundSlope)
            {
                velocity.Y = 0;
                jump = 0;
            }
            return true;
        }