H3DAPI FAQ

From H3D.org

Jump to: navigation, search

Contents

About H3D

What are the advantages of H3D API over Ghost or OpenHaptics?

The short answer is: H3D sits, in a sense, on top of OpenHaptics giving the user a higher level environment in which to program haptics.

But the long answer is probably of more interest.

Firstly, Ghost is the original haptic API written by SensAble. It uses a scene graph structure (i.e. a hierarchical representation of a scene with "Transform", "Group", etc nodes to break the world up into smaller sub-components). Ghost, however, does not perform any graphical rendering - it simply has callbacks to allow for the users own graphical rendering.

OpenHaptics is the new API from SensAble that does not have a scene graph. It sits at the same level as OpenGL (and tries to resemble OpenGL as much as possible).

OpenHaptics is more powerful than Ghost as far as haptic rendering is concerned, but since it does not offer a scene graph, it is not as quick or efficient to work with. The best analogy I can think of would be to compare the differences between writing an application directly in OpenGL, or to use OpenInventor (a scene graph API).

As with Ghost, OpenHaptics does not touch the graphical side of an application.

With either of these two products, you can (easily) say "I want a haptic sphere here" and everything works nicely. However, if you want to SEE the sphere there as well, then you have to do the graphical rendering of the sphere yourself. You would also probably want to render a representation of the stylus, and then make sure that the graphical stylus and sphere are in the same coordinate space as the haptic stylus and sphere.

This is where H3D comes in -- it is a scene graph API that performs both graphic and haptic rendering from a single scene description. You tell H3D that you want a sphere here, and that it should be both graphically and haptically rendered, and it will take care of the rest.

I can't argue any proof that scene graph based APIs are better than other techniques - but most OpenGL application developers believe this and use tools such as OpenInventor to make complex applications more manageable. On the flip-side, most computer games don't use a scene-graph API because they have such strict requirements on performance -- a game isn't a success if it doesn't squeeze out every last possible bit of performance from a graphics card. Scene graph APIs, whilst easier to use, take a minor performance penalty -- a clear tradeoff on speed of development.

So back to your question: " what the possible advantages might be to a developer to use H3DAPI over the others?"

H3D, as of version 2.0, uses HAPI and HAPI can use OpenHaptics, so if you chose to use H3D API you could also be using OpenHaptics. How much of OpenHaptics you are exposed to depends on what you want to do -- one way of looking at H3D is that it hides the complexities of OpenHaptics from you if you don't want to be concerned with it, but still lets you get your hands dirty if you do. Earlier versions of H3DAPI depends entirely on OpenHaptics. For all versions of H3DAPI it is required to have OpenHaptics in order to use devices from SensAble.

The advantages of H3D over just using OpenHaptics are:

  • you get a scene graph API
  • you get graphics and haptics automatically (thus no need to mess around creating a graphic sphere for every haptic sphere you want to have).
  • you get support haptics devices from several manufacturers.
  • open source, so you can modify the behaviour if needed.

Ghost is a scene graph API, so no advantage there - though I personally believe that the Ghost scene graph design is completely wrong from an OOP viewpoint. H3D, however, will give you graphics which Ghost doesn't do.

An alternative to H3D might be to use Ghost together with OpenInventor. The problem that arises here, though, is duplication of the scene-graph. In this scenario you would be required to have one scene graph in Ghost, and another in OpenInventor. This raises two problems: 1) you have to keep the two in sync which is no easy task; and 2) you have data redundancy.. every huge triangle set you have in one must be duplicated in the other.

H3D uses the VRML / X3D scene graph design which means that not only are we guaranteed a good design for our scene graph, users who are already familiar with X3D (of which there are many) are already familiar with the design of our API. It also means that loading X3D files is a natural part of the API.

In addition to this, H3D gives you an even higher level method of programming or prototyping. H3D supports Python, a high level scripting language. This means that users who are writing simple programs, or want to prototype ideas, can write a program entirely in Python script code and use X3D files for the geometry. In this approach you can in fact write quite useful programs without ever needing to touch a line of C++.

So H3D is a higher-level API than OpenHaptics that should reduce the development time when developing haptic applications.

Where you wouldn't obviously chose H3D is a situation where you already have a finished graphical application that you simply want to add haptics to as an afterthought. In this case switching to H3D would require you to rewrite the entire application which is not the ideal approach. Since you already have graphical rendering. In this case one would have to choose between using HAPI which has haptics rendering features or go down to OpenHaptics directly and implement haptics rendering manually.

TODO: Update this section with comments about OpenHaptics 3.0.

Installing & Compiling H3D

How do I install H3DAPI/HAPI?

Follow the instructions in the the section H3DAPI Installation and/or the section HAPI Installation. Alternatively you could use the ReadMe file that comes with the source distribution.

I get an error saying that "HL/HL.h" or "HD/HD.h" is missing when compiling. What should I do?

H3DAPI 2.0

This means that something is seriosly wrong. CMake should have managed to detect if these files exist on the system. Start CMake (the GUI on Windows/Mac and ccmake on linux), check advanced settings and find out what OPENHAPTICS_INCLUDE_DIR claims to have found those files. Check that include directory to be sure that the files exist. Also check HD_LIBRARY and HL_LIBRARY to be sure that they point to files that does exist. If the files have been removed or CMake have done something seriosly wrong erase these paths from the settings and rerun CMake. Make sure that CMake set "HAVE_OPENHAPTICS" in HAPI.h to true if all libraries and include files exists but to false if one or many are missing. If the problem persists post in the forum.

If you would like to order OpenHaptics please contact sales@sensegraphics.com. You may also get a free academic edition OpenHaptics software from http://dsc.sensable.com/

H3DAPI 1.5 or earlier

This means that you either do not have OpenHaptics or that the 3DTOUCH_BASE environment variable does not exist or is set to the wrong directory. If you have OpenHaptics make sure that you have an environment variable named 3DTOUCH_BASE that points to the directory where OpenHaptics is installed. On Windows this is normally something like "c:\program files\sensable\3dtouch".

If you do not have OpenHaptics, but want to compile it and use the graphical parts of H3D API you will have to remove the preprocessor definition HAVE_OPENHAPTICS from your project file or makefile. If you do this and recompile it will work, but you will not have any haptics.

If you would like to order OpenHaptics please contact sales@sensegraphics.com. You may also get a free academic edition OpenHaptics software from http://dsc.sensable.com/

Running H3D API

How do I start H3D API?

H3D API can be used both as an API to implement you own C++ applications, and as a loader of applications built in X3D and Python. In the former case you will have to implement your own executable with an entry-point. In the latter case the H3D system provides two executables that can be used to load the X3D file that defines your VR world. H3DLoad is a command-line tool that in its simplest use loads a specified X3D file. H3DViewer is a GUI in which different files can be loaded and several parameters of the H3D system can be interactively updated.

How do I calibrate the display and/or haptic devices to fit my system?

Calibration is essential for the correct visual display and correct co-location and co-registration of haptics and graphics. Use Calib, which is a tool included in the Candy package. Also read Calibrating haptic devices on the immersive workbench

Why does my haptic device move around or change calibration?

The default in X3D is that navigation changes the viewpoint. In a haptic workstation the viewpoint should be defined by the position of the user relative the screen. Therefore, when X3D applies navigation and changes the viewpoint the haptic device will appear to change its position and orientation.

There are two ways to fix this: change the navigation scheme so that the object(s) are transformed instead of the viewpoint, or set the followViewpoint field to "true". For the former there is a script in the Candy package.

How do I specify multiple devices?

Read Haptic device settings in H3D.

How do I use my settings in H3DViewers settings dialog for H3DLoad?

The settings dialog allows you to configure a lot of properties for you scene. These can be used to optimize the haptics and graphics rendering amongst other things. These settings are configured by fields in specific option nodes. Option nodes are subclasses of H3DOptionNode. In the latest release these option nodes exists:

  • CollisionOptions - Options related to events in the scene which require node collision functions to be called.
  • DebugOptions - Various settings that can be useful when debugging.
  • DefaultAppearance - Override the default appearance setting of the X3D specification.
  • GeometryBoundTreeOptions - Bound trees are used for fast collision detection and to fast find which graphic primitives should be rendered haptically.
  • GraphicsCachingOptions - Set options for graphics caching.
  • HapticsOptions - Control how haptics rendering is done.
  • OpenHapticsOptions - Specific options that can be used if OpenHapticsRenderer is used.

For more info about each field in the option nodes see documentation.

To use the options node add them to the options field of another node, such as X3DGeometryNode. If it is desired that the option should be globally add a GlobalSettings node and add options to that node.

Note that StereoInfo used to control some properties of stereo rendering is not an options node but simply a bindable node. Use that node as a child in a group.

C++

My program crashes, why?

The staffs at SenseGraphics have little time to provide free support for H3D API or associated libraries, however you can get professional support for a fee. The community might be able to help you but do so on a voluntary basis. To get help from your peers, use the forum, be polite and provide as much information as possible about your problem. Try, for example, to reduce the complexity of your code to find the least common denominator for the bug.

I have written my own node with an H3DNodeDatabase interface. How can I use them in my X3D-files and in Python?

When you have written your own nodes you would probably like to be able to use them in X3D-files. There are two ways of doing this. The first is to include your nodes in your executable that you use to run your program. E.g. if you are using the H3DLoad program that is distributed with the H3D API, you can add your new files to the H3DLoad project file (or Makefile). This will make them available when running H3DLoad.

A more flexible way is to compile your nodes into a DLL or shared library. This is very useful if you have made a toolkit with nodes for a specific purpose, e.g. user interface widgets. Your nodes can be easily used by anyone that has H3D API installed. They just need to import your dll in the X3D-file as shown below and have the new nodes available.

<Group>
<ImportLibrary library="c:\H3D\bin\UINodes.dll" />  
// Below this line all nodes specified in UINodes.dll are available.
.
.
 
</Group>

What is this Inst<> thing I keep seeing in all the node constructors?

Inst is short for instantiated and the Inst<> template is used to make sure that the value of the parameter in the constructor is not a NULL pointer. An example:

class MyNode: public Node {
  MyNode( Inst< SFBound > _bound = 0 ):
    bound( _bound ) { 
    ... 
  }
};


If an SFBound field is given as argument to this constructor it will behave as it would even if the Inst< SFBound > declaration was not present. If however the value given to the constructor is NULL then the Inst template will create a new object of its template parameter type(in this case SFBound) and that will be used as the value for _bound.

This is good to have since we want to be able to specialize the behaviour of the SFBound class in subclasses of MyNode and give an instance of the specialized SFBound as an argument to the constructor to use this specialized functionallity. In order to do this the argument to the constructor must be a pointer. This gives the possibility for the user to give a NULL pointer as argument, but in order for the node to work all fields must be initialized and not be NULL. So the Inst<> template makes sure that the field gets initialized properly even if the argument given to the constructor is NULL.

What basic field types are available in H3D API?

  • Single valued field types
    • SFFloat
    • SFDouble
    • SFInt32
    • SFVec2f
    • SFVec3f
    • SFVec4f
    • SFVec2d
    • SFVec3d
    • SFVec4d
    • SFBool
    • SFString
    • SFColor
    • SFColorRGBA
    • SFRotation
    • SFMatrix3f
    • SFMatrix4f
    • SFTime
    • SFNode
  • Multi valued field types
    • MFFloat
    • MFDouble
    • MFInt32
    • MFVec2f
    • MFVec3f
    • MFVec4f
    • MFVec2d
    • MFVec3d
    • MFVec4d
    • MFBool
    • MFString
    • MFColor
    • MFColorRGBA
    • MFRotation
    • MFMatrix3f
    • MFMatrix4f
    • MFTime
    • MFNode

There are also a number of field type template modifiers that can be used to modify the default behaivior of these fields. All of these field types are also available in Python. For more information about the different field types see the X3D specification.

What if I want a field to contain another type than the ones already available?

If you want to have a field that contains an instance of another type than the ones already available you can use the SField<> and MField<> templates. The SField< Type > template is used to specify fields that contain a single value and the MField< Type > template is used for multiple values of the same type. E.g. if you have written your own class named MyClass and want a field that contains it you can get your field type by:

typedef SField<MyClass> SFMyClass;

Now you have an SFMyClass field type that can be used. However if you want to be able to specify the value of the field in an x3d file, and not only directly in your C++ code you will have to define the function setValueFromString.

class SFMyClass: public SField< MyClass > {
   virtual void setValueFromString( const string &s ) {
      // code to convert the string to MyClass instance.
      ...
    }
 };

How can I make the update function execute as soon as it receives an event?

The normal model for field value updates is lazy evaluation. That means that the value of the field is not updated unless someone asks for its value. In some cases however, we want the update() function to always execute as soon as an event occurs. A good example of this is if we have a field that is used to react to button clicks. In order to get the wanted behaviour the AutoUpdate modifier template can be used.

class ButtonHandler: AutoUpdate< SFBool > {
  virtual void update() {
     bool b = static_cast< SFBool * >(event.ptr)->getValue();  
     if( b ) {
        // button pressed, do stuff
     }  
     return b;
  }
};

This will make the update function execute as soon as an event is received. If we had omitted the AutoUpdate part we would have to have some code somewhere else that asks for the value of the ButtonHandler instance or the update function would never execute.


Compile Error: Instantiate.h : error C2440: '<function-style-cast>

When compiling in visual studio. This error usually occurs when compiling a version of a binary which is dependent on H3DAPI and contains new nodes. The reason for this error is most likely that a constructor of a base class has changed somehow. Check which file included Instantiate.h and check the constructor and the call to the base class constructor. Correct this and the error will most likely be taken care of.

Python

How do I use Python in H3D API?

The PythonScript node is a binding to the Python scripting language, which can be used to e.g. modify scenes and handle events. In order to use Python you will have to add one of these nodes to the scenegraph. The PythonScript node specifies an url to where the actual Python code is located. So if you have written a simle Python file named Hello.py which contains

print "Hello"

You can get this code to execute by adding a PythonScript node to your scenegraph. This can be done by specifying it directly in an x3d file, e.g.

<Scene>
<PythonScript url="Hello.py" />
</Scene>

If you use H3DLoad on the x3d file the Python code should execute and "Hello" should be printed to the command prompt.

How do I get access to the H3D API specific types from Python?

In order to get access to H3D API specific types like Vec3f, Rotation etc and Field types you have to import the Python module named H3DInterface. This contains all H3D specific Python bindings. It can be imported by writing

from H3DInterface import *

in your Python file.

What is included in the H3DInterface Python module?

The H3DInterface Python module is described here

I get the message "ImportError: No module named H3DInterface PythonScript::initialiseParser() ERROR importing H3DInterface, check your PYTHON PATH" when trying to use the PythonScript node. What is wrong?

H3DAPI 2.0

H3DInterface module should be found since it (by default) is hard coded into the C++ code. You could try to fix the problem by doing the same as in the answer for earlier versions of H3DAPI 1.5.

H3DAPI 1.5 or earlier

Your PYTHONPATH environment variable does not point to a directory containing H3DInterface.py or you do not have a PYTHONPATH environment variable at all. In order for Python to work properly in H3D API you will have to set the PYTHONPATH environment variable to the directory that contains H3DInterface.py and normally this directory is the H3DAPI/pylib directory.

I get the message "ValueError: Python object not a Field type. " when trying to use my specialized field class. What is wrong?

Probably you have defined an __init__ function in your specialized field, e.g.

class NewField( SFBool ):
  def __init__( self ):
    self.scale = 1

In Python you always have to run the base class constructor explicitly in order for the object to be of the base class type, so the class definition above will actually not be an SFBool type even though it is specified as that. In order to get it to work you will have to call the base class __init__ function explicitly, e.g.

class NewField( SFBool ):
  def __init__( self ):
    SFBool.__init__(self)
    self.scale = 1

So a good thing to remember when coding Python is that if you define an __init__ function, make sure that you call the base class __init__ function in it.

X3D

How do I use the SpaceWareSensor node?

Simple Usage

The SpaceWareSensor node is a node providing access to the values from a SpaceMouse from 3DConnexion. A simple example for its usage is given below:

<Group>
  <SpaceWareSensor DEF="SW"/>
  <Transform DEF="XF" >
  <Shape>
    <Appearance>
      <Material/>
    </Appearance>
    <Box size="0.1 0.1 0.1" />
  </Shape>
  </Transform>
  <ROUTE fromNode="SW" fromField="accumulatedRotation" toNode="XF"
  toField="rotation" />
</Group>

This will render a Box that can be rotated using a SpaceMouse. It might be a little fast depending on the settings in the driver for the SpaceMouse. To slow down the rotation the rotationScale field can be used. A value of 0.5 will make the Box rotate at half the speed.

Use for Nagivation in H3DAPI 1.5 or earlier

If you always want to be able to rotate the scene with a SpaceMouse without making any changes to the x3d file you can make your own loader that creates the SpaceWareSensor and adds it to the scene automatically. The default loader (H3DLoad.cpp) sets up keyboard and mouse to rotate the scene. The following example sets up the SpaceWareSensor instead.

#include "X3D.h"
#include "Group.h"
#include "Transform.h"
#include "Scene.h"
#include "SpaceWareSensor.h"
#include "DEFNodes.h"
 
using namespace std;
using namespace H3D;
 
H3D_API_EXCEPTION( QuitAPIException );
 
class QuitAPIField: public AutoUpdate< SFString > {
   virtual void update() {
    string s = static_cast< SFString * >(routes_in[0])->getValue();
    if( s[0] == 27 ) {
      throw QuitAPIException();
    }
  }
};
 
 
int main(int argc, char* argv[]) {
 
  if (argc < 2){
    cerr << "Usage: " << argv[0] << " <X3D file>" << endl;
    return 1;
  }
 
  const char* xml_file = argv[1];
  try {
    AutoRef< SpaceWareSensor > sw( new SpaceWareSensor );
    X3D::DEFNodes dn;
    QuitAPIField *quit_api = new QuitAPIField;
    AutoRef< Group     > g( new Group );
    AutoRef< Transform > t( new Transform );
    g->children->push_back( t.get() );
    cerr << "Loading " << xml_file << endl;
    t->children->push_back( X3D::createX3DFromURL( xml_file, 
                                                   &dn ) );
    // The SpaceWareSensor node needs to be in the scenegraph
    // in order to update its values.
    t->children->push_back( sw.get() );
    // set up routes to rotate the model
    sw->accumulatedRotation->route( t->rotation );
 
    // create a Viewpoint if it does not exist.
    if( !Viewpoint::getActive() ) {
      Viewpoint *vp = new Viewpoint;
      vp->position->setValue( Vec3f( 0, 0, 0.6 ) );
    }
 
    Scene scene;
    // create a window to display
    GLWindow *glwindow = new GLWindow;
    glwindow->fullscreen->setValue( false );
    glwindow->mirrored->setValue( false );
    glwindow->renderMode->setValue( "MONO" );
    scene.window->push_back( glwindow );
    scene.sceneRoot->setValue( g.get() );
    Scene::mainLoop();
  }
  catch (const QuitAPIException &) {
  }
  catch (const Exception::H3DException &e) {
    cerr << e << endl;
  }
}

Use for Navigation in H3DAPI 2.0 or later

NOTE that for H3DAPI 2.0 or later H3DLoad does not set up keyboard and mouse to rotate the scene but the navigation paradigm from the X3D specification is used instead. This means that the viewpoint is moved around. By default the navigation is EXAMINE which means that it looks like the world is rotated around the center. With H3DAPI 2.0 or later it is possible to choose navigation with SpaceWareSensor by pressing F4 after loading a file with H3DLoad.

What parts of the X3D standard are implemented?

Completed components:

  • Core
  • Time
  • Rendering
  • Shape
  • Geometry2D
  • Text
  • Sound
  • Lighting
  • Interpolation

Partly finished components:

  • Networking component - Anchor, LoadSensor not implemented
  • Grouping component - StaticGroup, WorldInfo not implemented
  • Geometry3D component - ElevationGrid, Extrusion not implemented
  • Texturing component - MovieTexture not implemented.
  • Environmental effects component - Fog not implemented

Error Messages

This section explains common error messages outputed to the console and different ways of solving them.

WARNING: Could not load dynamic library "SomeLibrary" specified in Unnamed ImportLibrary (The specified module could not be found. )

The dynamic library specified in an ImportLibrary node could not be loaded. To solve this check the following.

  • Is the url field in the ImportLibrary node set to the correct path to the library. There may be several different versions of this dll on the system. Check so that it points to the one you want to load.

The following applies to windows systems.

  • Is the dll you are trying to load compiled with the same compiler as H3DLoad/H3DViewer.
  • Is "SomeLibrary" compiled against the H3DApi libraries that H3DLoad/H3DViewer is compiled against.
  • Are you trying to load a version of "SomeLibrary" compiled with the "Debug" configuration using H3DLoad/H3DViewer compiled with the "Release" configuration. Or the other way around.
  • If you load the x3d-file from console like the following "H3DLoad myfile.x3d" make sure that the command H3DLoad actually points to the version of H3DLoad you want to use. To make sure, give full path to H3DLoad.exe.
Personal tools
go to