Thursday, December 24, 2009

Learning Blender

I spent some time trying to learn Blender. I have no previous experience with 3D modeling tools and Blender looks very complicated and confusing for me. It has many key combinations and buttons, even your actions can lead to something unexpected.

At first I spent some time reading Blender – Noob to Pro and doing the examples. I managed to get the basics – grab, rotate, scale, extrude, etc.

I haven’t made any decent model so I start to read Introduction to Character Animation by Ryan Dale. It is a really great document, if you need to learn Blender, this book can help you a lot.

Here are my first attempts, don’t laugh much:


Shaping the mouth.

The head. It looks creepy.


 
I made some mistakes.


Yey, almost done!

Thursday, December 17, 2009

Irrlicht – my third person camera

Currently I work on my own RPG game and I hope after gaining enough experience with it I’ll try to make my own MMORPG. Am I humble enough?

There are many MMORPG games on the market and all of them can work as an inspiration. My first task was to make a third person camera or more precisely third person camera animator. You don’t need to make an animator to use this logic. Creating an animator leads to some complications that I won’t discuss here.

We will use the right mouse button to orbit around the object and the scroller to zoom in and out. You need to add something like this in your event receiver or in OnEvent function of the animator:

 case EMIE_RMOUSE_PRESSED_DOWN:
  MouseKeys[2] = true;

  break;
 case EMIE_RMOUSE_LEFT_UP:
  MouseKeys[2] = false;

  break;
 case EMIE_MOUSE_MOVED:
  MousePos = CursorControl->getRelativePosition();

  break;
 case EMIE_MOUSE_WHEEL:
  Zoom = Zoom + event.MouseInput.Wheel*ZoomSpeed;

  if (Zoom < TargetMinDistance)
   Zoom = TargetMinDistance;

  if (Zoom > TargetMaxDistance)
      Zoom = TargetMaxDistance;

Now, when we have the input data, we must implement the logic. You must add this in animateNode function of your animator, or in some update method if you don’t use an animator.

 core::vector3df target = targetNode->getPosition();

 f32 nRotX = RotX;
 f32 nRotY = RotY;

 if (isMouseKeyDown(2))
 {
  if (!Rotating)

  {
   RotateStart = MousePos;
   Rotating = true;

   nRotX = RotX;
   nRotY = RotY;
  }

  else
  {
   nRotX += (RotateStart.X - MousePos.X) * RotateSpeed;

   nRotY += (RotateStart.Y - MousePos.Y) * RotateSpeed;

  }
 }
 else if(Rotating)
 {

  RotX += (RotateStart.X - MousePos.X) * RotateSpeed;

  RotY += (RotateStart.Y - MousePos.Y) * RotateSpeed;

  nRotX = RotX;
  nRotY = RotY;
  Rotating = false;

 }

 target = targetNode->getPosition();

 Pos.X = Zoom + target.X;
 Pos.Y = Zoom + target.Y;

 Pos.Z = target.Z;

 Pos.rotateXYBy(nRotY, target);

 Pos.rotateXZBy(-nRotX, target);

 camera->setPosition(Pos);

 camera->setTarget(target); 

This is very basic functionality but you will grasp the logic. I’ve used the Maya animator the get the idea. My code have a nasty flip on the top and the bottom, you can fix it if you want with restricting the camera movement or changing the up vector. And don’t make the camera parent or child of the target.

Saturday, November 7, 2009

Blender – more than 3D

Blender is quite popular, open-source, graphics software released under the GNU General Public License. It is used in many projects – commercial or other, and can be a good choice for resource creation.


Blender has many nice features for modeling, rendering and animation of 3D characters and scenes.

Blender is relatively complex and difficult for newbies. If you intent to learn blender you need to equip yourself with some patience.

Animation with Blender - Best Character Animation for Suzanne Awards 2009.

Saturday, October 31, 2009

Irrlicht Engine - Easy Tutorial – Basics

This post is part of my tutorial on how to use Irrlicht Engine and a continuation to the article Irrlicht Engine - Easy Tutorial – Intro.

Let’s view the example I used in the previous post. Here is the code:

#include <irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;

using namespace io;
using namespace gui;

int main()

{
 IrrlichtDevice *device = createDevice(
   video::EDT_OPENGL,
   dimension2d<u32>(800, 600),
   16, false, false, false, 0);

 if (!device)
  return 1;

 IVideoDriver* driver = device->getVideoDriver();

 ISceneManager* sceneManager =
   device->getSceneManager();

 sceneManager->addCameraSceneNode();

 while(device->run())

 {
  driver->beginScene(
    true, true, SColor(255,50,130,50));

  sceneManager->drawAll();
  driver->endScene();
 }

 device->drop();
 return 0;
}


This is a very basic application. First thing we need to do is to create Irrlicht device with the createDevice function. The first parameter is video::E_DRIVER_TYPE type and can be video::EDT_DIRECT3D9, video::EDT_DIRECT3D8, video::EDT_OPENGL, video::EDT_NULL, video::EDT_SOFTWARE, video::EDT_BURNINGSVIDEO. I’ll use video::EDT_OPENGL because my Irrlicht binaries are from the official site and they are not built with DirectX. (And I am lazy.)

Next parameter as you can assume is the window size. I won’t discuss the other parameters now as they are not important for my tutorial. In fact I can call createDevice this way:

IrrlichtDevice *device = createDevice(

   video::EDT_OPENGL,
   dimension2d<u32>(800, 600));

When you finish using the device don’t forget to call:
device->drop(); 
You can learn more for the Irrlicht device class here - http://irrlicht.sourceforge.net/docu/classirr_1_1_irrlicht_device.html.

And now the cool part – the scene manager object. It manages the scene nodes, meshes, cameras, lights and so on. Your scene is represented as a hierarchical scene graph.
You obtain a reference to the scene manager object through the call:

device->getSceneManager();

Let’s do something fun with our example. I’ll change our camera to FPS mode – FPS camera in Irrlicht is a camera node suited for a first person shooter. It moves with the arrows and rotates with the mouse.
I’ll add some simple scene nodes as cube and sphere.

To add a FPS camera we must call:
ICameraSceneNode *camera = sceneManager->addCameraSceneNodeFPS();

Our cube:
ISceneNode *cube = sceneManager->

        addCubeSceneNode(15.0f, 0, -1, core::vector3df(150,10,10));

To make the camera look at the cube:
camera->setTarget(cube->getAbsolutePosition());

I’ll add a light source with the default parameters. Without it our objects will look ugly and black. Now they will be ugly but with some light on the front side.

Here is the full code:
#include <irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;

using namespace io;
using namespace gui;

int main()

{
 IrrlichtDevice *device = createDevice(
   video::EDT_OPENGL,
   dimension2d<u32>(800, 600));

 if (!device)
  return 1;

 IVideoDriver* driver = device->getVideoDriver();

 ISceneManager* sceneManager =
   device->getSceneManager();

 ICameraSceneNode *camera =
   sceneManager->addCameraSceneNodeFPS();

 ISceneNode *cube = sceneManager->
   addCubeSceneNode(15.0f, 0, -1,
     core::vector3df(150,10,10));

 sceneManager->addSphereSceneNode(
   5.0f, 16, 0, -1,
   core::vector3df(100,30,10));

 sceneManager->addLightSceneNode();

 camera->setTarget(cube->getAbsolutePosition());

 while(device->run())
 {
  driver->beginScene(

    true, true, SColor(255,50,130,50));

  sceneManager->drawAll();
  driver->endScene();
 }

 device->drop();
 return 0;
} 
 
 

And the result


Wednesday, October 28, 2009

Irrlicht - How to get mouse pointer coordinates on a terrain?

You may need the coordinates where a user clicked on your terrain for many reasons. For example many MMORPG games use the mouse to move the character. Using point-and-click system is relatively easy for the players and not hard to implement as a code.

How to get mouse coordinates from a 3D place with Irrlicht? You need to use getCollisionPoint member function of the irr::scene::ISceneCollisionManager class. The current documentation at the official site is for version 1.5.1 but the current Irrlicht version is 1.6. getCollisionPoint function has one more parameter in the current version.
If you try to compile the project with only four parameters you’ll get an error message:

**** Build of configuration Debug for project GameNext ****

**** Internal Builder is used for build ****
g++ -ID:\irrlicht-1.6\include -O0 -g3 -Wall -c -fmessage-length=0 -osrc\GameNext.o ..\src\GameNext.cpp
..\src\GameNext.cpp: In function `int main()':
..\src\GameNext.cpp:59: error: no matching function for call to `irr::scene::ISceneCollisionManager::getCollisionPoint(const irr::core::line3d<irr::f32>&, irr::scene::ITriangleSelector*&, irr::core::vector3df&, irr::core::triangle3df&)'
D:/irrlicht-1.6/include/ISceneCollisionManager.h:43: note: candidates are: virtual bool irr::scene::ISceneCollisionManager::getCollisionPoint(const irr::core::line3d<irr::f32>&, irr::scene::ITriangleSelector*, irr::core::vector3df&, irr::core::triangle3df&, const irr::scene::ISceneNode*&)
..\src\GameNext.cpp:57: warning: unused variable 'node'
Build error occurred, build is stopped
Time consumed: 1873 ms.

The right syntax is:

bool getCollisionPoint(const core::line3d<f32>& ray,
        ITriangleSelector* selector, core::vector3df& outCollisionPoint,
        core::triangle3df& outTriangle, const ISceneNode*& outNode)


So how would our code look like?

First we need to get the cursor position in the 2D space.
core::position2d< s32 > pos = cursor->getPosition();
Now, we need to get the 3D vector from it.
const core::line3d<f32> ray = 
        collisionManager->getRayFromScreenCoordinates(pos);
And check if our line intersects with the terrain.
if(collisionManager->getCollisionPoint
        (ray, selector, point, triangle, node))

{
 // do something
}

Here is the full demo code:

#include <irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;

using namespace io;
using namespace gui;

int main() {

 IrrlichtDevice *device = createDevice(video::EDT_OPENGL,
   dimension2d<u32> (800, 600),
   16, false, false, false, 0);

 if (!device)
  return 1;

 IVideoDriver* driver = device->getVideoDriver();

 ISceneManager* sceneManager = device->getSceneManager();
 IGUIEnvironment* guiEnvironment = device->getGUIEnvironment();

 // -------
 scene::ITerrainSceneNode* currentTerrain =
   sceneManager->addTerrainSceneNode(

     "media/poiheightmap.bmp", // height map
     0, // parent node
     -1, // node id
     core::vector3df(0.f, 0.f, 0.f), // position

     core::vector3df(0.f, 0.f, 0.f), // rotation
     core::vector3df(100.f, 1.f, 100.f), // scale

     video::SColor(255, 255, 255, 255), // vertexColor

     5, // maxLOD
     scene::ETPS_17, // patchSize
     4);

 currentTerrain->setMaterialFlag(video::EMF_LIGHTING, false);
 currentTerrain->setMaterialTexture(0,
   driver->getTexture("media/terrain-texture.jpg"));

 currentTerrain->setMaterialTexture(1,
   driver->getTexture("media/detailmap3.jpg"));
 currentTerrain->scaleTexture(1.0f, 20.0f);

 ITriangleSelector* selector = sceneManager->
   createTerrainTriangleSelector(currentTerrain);

 currentTerrain->setTriangleSelector(selector);

 // retrieve the SceneCollisionManager object
 ISceneCollisionManager* collisionManager =

   sceneManager->getSceneCollisionManager();

 // get cursor
 ICursorControl *cursor = device->getCursorControl();

 // simple camera with position and target
 sceneManager->addCameraSceneNode(0,
   core::vector3df(100.f, 60.f, 100.f),
   core::vector3df(900.f, 0.f, 900.f));

 // this sphere will mark our collision point
 ISceneNode* sphere = sceneManager->addSphereSceneNode();

 while (device->run()) {
  core::position2d<s32> pos = cursor->getPosition();

  core::vector3df point;
  core::triangle3df triangle;

  const ISceneNode *node = 0;
  const core::line3d<f32> ray = collisionManager->

    getRayFromScreenCoordinates(pos);
  if (collisionManager->getCollisionPoint
    (ray, selector, point, triangle, node))

  {
   sphere->setPosition(point);
  }

  driver->beginScene(true, true, SColor(255, 50, 130, 50));

  sceneManager->drawAll();
  guiEnvironment->drawAll();
  driver->endScene();

 }

 selector->drop();

 device->drop();

 return 0;
}

Sunday, October 25, 2009

Irrlicht Engine – Easy Tutorial - Intro

Irrlicht Engine is a powerful way to make your own game even if you are not pro at game development. I decided to write a simple and easy tutorial for beginners on how to make games with Irrlicht. I’ll make it in several parts with a lot of examples.
What do you need to know for this tutorial?

  • Basic programming
  • C++

What do you need for this tutorial?
  • Irrlicht - http://irrlicht.sourceforge.net/
  • C++ IDE – I use Eclipse - http://eclipse.org/ for many of my projects, I’ll use it here too.
  • If you want to use Irrlicht with DirectX9 you must get DirectX SDK and build Irrlicht with it. I am lazy so I’ll use OpenGL.


Intro
How to make Eclipse build your project with Irrlicht support. Of course you don’t need to use Eclipse, if so skip this part.

Create new Eclipse project – in my case I’ll call it IrrlichtTutorial.




To add Irrlicht to your project you need to select it and go to Project->Properties from the main menu tab.


Then select C/C++ Build -> Settings. You will see something like this:


Go to GCC C++ Compiler->Directories and add the path to Irrlicht includes in my case D:\irrlicht-1.6\include.





Then go to the C++ Linker part and select Libraries Tab. Add Irrlicht in the first field (Libraries) and the path to the appropriate Irrlicht lib subfolder in the second. In my case it would be D:\irrlicht-1.6\lib\Win32-gcc.



That’s it. Let’s test if we can build a project. Of course to run an Irrlicht project you must have Irrlicht.dll in your path. If you use multiple Irrlicht versions you can add the correct dll in your project folder.
Now, lets build something simple yet useful. A simple window doing nothing is just fine. Here is the code:

#include <irrlicht.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

int main()
{
 IrrlichtDevice *device = createDevice( video::EDT_OPENGL, dimension2d<u32>(800, 600), 16,
   false, false, false, 0);

 if (!device)
  return 1;

 IVideoDriver* driver = device->getVideoDriver();
 ISceneManager* sceneManager = device->getSceneManager();
 IGUIEnvironment* guiEnvironment = device->getGUIEnvironment();


 sceneManager->addCameraSceneNode();

 while(device->run())
 {
  driver->beginScene(true, true, SColor(255,50,130,50));
  sceneManager->drawAll();
  guiEnvironment->drawAll();
  driver->endScene();
 }

 device->drop();
 return 0;
}



And what we’ve done:



An empty window. Cool!

Next: Irrlicht Engine - Easy Tutorial - Basics

Wednesday, October 21, 2009

Irrlicht

Irrlicht Engine is a C++, 3D game engine. It is open-source, cross platform and relatively easy to work with especially for noob like me. The project has good documentation and tutorials and it is not hard to start with.



Running official examples.




I found something annoying with the latest Irrlicht version. If you want to use it with DirectX you must build it and enable the DirectX support. The binaries from the distribution are not built with it. At first I didn’t understand the message:

Irrlicht Engine version 1.6
Microsoft Windows XP Professional Service Pack 3 (Build 2600)
DIRECT3D9 Driver was not compiled into this dll. Try another one.

I suppose the Irrlicht developers had a reason to make things this way but it is not very convenient.
So if you want to use it with DirectX you must build it from the source code. Fortunately it is not hard to do because Irrlicht comes with its project files. Just add the SDK and run a build.


For more information visit its official site - http://irrlicht.sourceforge.net/.