From delta3d Wiki
Jump to: navigation, search

Hello World!

In this tutorial, you will create a basic application using high level classes from Delta3D. Then you learn how to load a 3D model and setup a basic motion model.

Additional Tutorials that may apply:
Delta3D CMake
How to use CMake with a Delta3D Appliation
Delta3D installation and Hello World Screencast
Delta3D Environment Variables


The Header File

Create a new header file, in this case HelloWorldApp.h and add the following lines to include and allow the use of classes from dtCore and dtABC that we will need. Our example class will derive from dtABC::Application, so we need dtABC/application.h. It will also contain members using the dtCore::RefPtr template, so dtCore/refptr.h must be included as well.

#include <dtABC/application.h>
#include <dtCore/refptr.h>
#include <dtCore/object.h>
#include <dtCore/orbitmotionmodel.h>

Next, let's declare a sub-class called HelloWorldApp that derives from dtABC::Application. The Application class is the base level class for most applications. It contains the basic components required for displaying a window, creating a scene, and recieving input. By convention, sub-classes of Application take a reference to a string which is the filename for the application's config file. Let's also declare an override of the function virtual void Config(), we'll use that to setup our scene. We'll also need two data members: something to contain our 3D model and a motion motion to control the camera.

class HelloWorldApp : public dtABC::Application
{
   public:
      HelloWorldApp(const std::string& configFilename);

      // Override this function to setup your scene.
      virtual void Config();

   protected:
      // Destructors for subclasses of dtCore::Base must have a protected
      // destructor. Otherwise use of RefPtrs will cause some serious
      // problems if the objects are allocated on the stack.
      virtual ~HelloWorldApp();

   private:
      // dtCore::RefPtr is a template for a smart pointer that takes
      // care of reference counting for objects allocated on the heap.
      // It is good practice to store all objects that derive from
      // dtCore::Base inside a RefPtr.
      dtCore::RefPtr<dtCore::Object> mTerrainObject;
      dtCore::RefPtr<dtCore::OrbitMotionModel> mMotionModel;
};

The Implementation File

Let's move onto the implementation for our application. Here we'll need to implement three functions: the constructor, destructor, and Config(). Since we are building the whole application into one implementation file, we'll also need a main().
Now, create a file called HelloWorldApp.cpp file, and add the following code. These headers will bring in our class declaration, plus the interface for several Delta3D classes that we will use.

#include "HelloWorldApp.h"
#include <dtCore/deltawin.h>
#include <dtCore/transform.h>


Next, let's implement the constructor.

HelloWorldApp::HelloWorldApp(const std::string& configFilename)
: dtABC::Application(configFilename)
{
}

As mentioned earlier, sub-classes of dtABC::Application usually take a config file. This file is normally passed directly to the constructor of the dtABC::Application base class. It is a simple XML file that sets up basic window parameters (like size, position, and window title).


Next is the destructor. There is nothing special we want to do here, so it should be empty.

HelloWorldApp::~HelloWorldApp()
{
}

Importing a 3D Model and Setting a Camera

Now let's setup our scene. By convention, the Config() function is used for this step.

There are two thing we want to accomplish here. First, load up a 3D model displaying some geometry. Second, attach a motion model to our camera so we can move it based on mouse input. The particular mesh we'll be using here is a piece of terrain mesh. Here is the code necessary to load it up.

void HelloWorldApp::Config()
{
   // Call the parent class, in case something important is happening there
   Application::Config();

   GetWindow()->SetWindowTitle("HelloWorldApp");

   // Adjust the Camera position by instantiating a transform object to
   // store the camera position and attitude.
   dtCore::Transform camPosition(0.f, -100.f, 10.f, 0.f, 0.f, 0.f);
   GetCamera()->SetTransform(camPosition);

   // Setting a motion model for the camera
   mMotionModel = new dtCore::OrbitMotionModel(GetKeyboard(), GetMouse());

   // Setting the camera as a target for the motion model. The terrain object
   // will be static at 0,0,0 and the camera will move using
   // the right clicked mouse.
   mMotionModel->SetTarget(GetCamera());

   // Allocate a dtCore::Object. This class will be your basic container
   // for 3D meshes.
   mTerrainObject = new dtCore::Object("Terrain");

   // Load the model file, in this case an Open Scene Graph model (.ive)
   mTerrainObject->LoadFile("models/terrain_simple.ive");

   // Add the Object to the scene. Since the object is a RefPtr, we must
   // pull the internal point out to pass it to the Scene.
   AddDrawable(mTerrainObject.get());

The three steps in more detail are:

  1. Allocate memory to contain a dtCore::Object. The constructor takes a string which will serve as a name for this particular mesh.
  2. Load the mesh from the models/terrain_simple.ive file on disk.
  3. Add the newly loaded mesh into our scene. Object will not get rendered until they added to the scene.

Next, we need to setup our camera. Even with a mesh loaded and properly added to the scene, we will not be able to see it unless the camera is placed in front of it. Add the following code to Config to setup the camera.

   // Adjust the Camera position by instantiating a transform object to
   // store the camera position and attitude.
   dtCore::Transform camPosition(0.f, -100.f, 10.f, 0.f, 0.f, 0.f);
   GetCamera()->SetTransform(camPosition);

This code will move the camera position to (0.0, -100.0, 10.0 ), giving us a nice view of the mesh.

Finally in Config, let's add a little interactivity to our example. Delta3D has a few stock motion models that can be used to move things in the scene based on user input. One of the most basic is OrbitMotionModel which gives the standard 3D "world-in-hand" type of control. It is simple to use:

   // Setting a motion model for the camera
   mMotionModel = new dtCore::OrbitMotionModel(GetKeyboard(), GetMouse());

   // Setting the camera as a target for the motion model. The terrain object
   // will be static at 0,0,0 and the camera will move using
   // the right clicked mouse.
   mMotionModel->SetTarget(GetCamera());


Now your app will have the ability to move the camera in response to using the mouse. Left-clicking and dragging will rotate the world, middle-clicking and dragging will zoom in and out, and right-clicking and dragging will translate the camera. Here's the full Config implementation:

void HelloWorldApp::Config()
{
   Application::Config();
 
   GetWindow()->SetWindowTitle("HelloWorldApp");

   // Adjust the Camera position by instantiating a transform object to
   // store the camera position and attitude.
   dtCore::Transform camPosition(0.f, -100.f, 10.f, 0.f, 0.f, 0.f);
   GetCamera()->SetTransform(camPosition);

   // Setting a motion model for the camera
   mMotionModel = new dtCore::OrbitMotionModel(GetKeyboard(), GetMouse());

   // Setting the camera as a target for the motion model. The terrain object
   // will be static at 0,0,0 and the camera will move using
   // the right clicked mouse.
   mMotionModel->SetTarget(GetCamera());

   // Allocate a dtCore::Object. This class will be your basic container
   // for 3D meshes.
   mTerrainObject = new dtCore::Object("Terrain");
   
   // Load the model file, in this case an Open Scene Graph model (.ive)
   mTerrainObject->LoadFile("models/terrain_simple.ive");

   // Add the Object to the scene. Since the object is a RefPtr, we must
   // pull the internal point out to pass it to the Scene.
   AddDrawable(mTerrainObject.get());
}

main()

Last but not least, let's implement the main function. The application will begin and end its life here.

#include "HelloWorldApp.h"
#include <dtCore/globals.h>

int main(int arc, char **argv)
{
   // Setup the data file search paths for the config file and the models files.
   // This is best done in main prior to configuring app. That way the paths
   // are ensured to be correct when loading data.
   dtCore::SetDataFilePathList( "..;" +
                               dtCore::GetDeltaDataPathList() + ";" +
                               dtCore::GetDeltaRootPath() + "/examples/data/;"); 
	
   //Instantiate the application and look for the config file
   dtCore::RefPtr<HelloWorldApp> app = new HelloWorldApp("config.xml");
	
   app->Config(); //configuring the application
   app->Run(); // running the simulation loop
   
   return 0;
}


Conceptually, the main doesn't do much. The main() function's main function (pardon the pun!) is to allocate a new instance of our example class HelloWorldApp, configure it, and start the simulation.

The line
dtCore::SetDataFilePathList();
is important. Anytime Delta3D is told to search for a file on disk (e.g. loading a config file or a mesh) it will use whatever paths you set here.

It is good practice to keep all your runtime data in a single directory, so you can set it once and forget about it. In this application our data is in the same directory as Delta3D's example, so we need to add that directory. The entire string is semi-colon delimited.

Project Files

We'll need to create a CMake script file so CMake knows about our project. Note, we're using CMake 2.6 and later here. Here's a simple CMakeLists.txt we can use that references our 3 files and creates an executable:

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

#Convert to CMake standard path string
FILE(TO_CMAKE_PATH "$ENV{DELTA_ROOT}" DELTA_ROOT_CMAKE)

SET(CMAKE_MODULE_PATH ${DELTA_ROOT_CMAKE}/CMakeModules) #where the Find*.cmake files are

PROJECT(HelloWorldApp)

FIND_PACKAGE(dtABC REQUIRED)
FIND_PACKAGE(dtCore REQUIRED)
FIND_PACKAGE(dtUtil REQUIRED)

INCLUDE_DIRECTORIES(${DTABC_INCLUDE_DIRECTORIES}
                    ${DTCORE_INCLUDE_DIRECTORIES}
                    ${DTUTIL_INCLUDE_DIRECTORIES}
                   )

ADD_EXECUTABLE(HelloWorldApp main.cpp
                             HelloWorldApp.h
                             HelloWorldApp.cpp
               )

TARGET_LINK_LIBRARIES(HelloWorldApp ${DTABC_LIBRARIES}
                                    ${DTCORE_LIBRARIES}
                                    ${DTUTIL_LIBRARIES}
                      )

Load this CMakeLists.txt into CMake and give an output folder such as "build". This "build" folder will contain all of our CMake generated files, plus all the compiler output.

Click on the "Configure" button and let CMake start processing the file. If you have the DELTA_ROOT environment variable defined, it should find all the required files automatically. If all the requirements have been met, you can now click on the "Generate" button to write out the project files.

Running

Now let's compile and run the app! You should see an screen similar to this: Hello world image.jpg

Now if you right click the mouse you will be able to move the camera around the loaded geometry.

That's the end of the Delta3D Hello World tutorial. To better learn the application, play with it a little: search the web for others 3D models and change the motion model used to see how it will behave. Remember that you may need to adjust the camera position depending on the model used to get a good initial view!

Complete files to download:HelloWorld5.zip