23.2. Viewer Collision Detection

This feature prevents the camera from passing through walls or floors, making viewer manipulation much more comfortable and realistic. To use this class, first create a standard viewer and then an SoXtCollisionViewer , SoWinCollisionViewer SoWinCollisionViewer , or SoQtCollisionViewer for this viewer. Collision detection will be activated immediately. The minimum distance between the camera and the object can be adjusted. A user callback function can be set to receive notification when a collision is detected. See SoXtCollisionViewer (or the SoQt or SoWin SoWin equivalent) for more information.

This feature is fast, even for large scenes, but only gives an approximately correct answer. Collisions are only detected “straight ahead” of the camera and some collisions may be missed if the camera is moving quickly or turning.

Viewer collision detection

Figure 23.1. Viewer collision detection



Example 23.1. How to use the Collision Viewer

Source code from: $OIVHOME/src/Inventor/examples/Features/Collision/CollisionViewer/CollisionViewer.cxx.

#include <Inventor/SoXt/viewers/SoWinCollisionViewer.h>
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtWalkViewer.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoPerspectiveCamera.h>
#include <Inventor/nodes/SoSeparator.h>

//---------------------------------------------------------------------
// Global objects
SoWinCollisionViewer *collision_viewer;

//---------------------------------------------------------------------
// Function declarations
void onCollision(void*, SoWinCollisionViewer*);

//*********************************************************************
// Main function
int
main(int argc, char **argv)
{
  // Window initialization --------------------------------------------
  Widget myWindow = SoXt::init(argv[0]);
  if (myWindow == NULL) exit(1);
  
  // Which file to open -----------------------------------------------
  char filename [1024];
  if (argc == 1)
    strcpy(filename, "Barcelona.iv");
  else
    strcpy(filename, argv[1]);
  
  // Scene graph initialization ---------------------------------------
  SoInput my_scene_input;
  if (!my_scene_input.openFile(filename)) return;
  SoSeparator *root = SoDB::readAll(&my_scene_input);
  if (root == NULL) return;
  my_scene_input.closeFile();
  
  root->ref();
  
  // Set up viewer ----------------------------------------------------
  SoXtWalkViewer *my_viewer = new SoXtWalkViewer(myWindow);
  my_viewer->setSceneGraph(root);
  my_viewer->setTitle("Collision Walk Viewer");
  my_viewer->show();
  
  // Adding collision prevention --------------------------------------
  collision_viewer = new SoWinCollisionViewer(my_viewer);
  collision_viewer->addCallback (onCollision, NULL);
  
  // Main loop --------------------------------------------------------
  SoXt::show(myWindow);
  SoXt::mainLoop();
  
  return 0;
}

//*********************************************************************
// Function called when there is a collision
void
onCollision(void*, SoWinCollisionViewer*)
{
  #ifdef WIN32
    PlaySound("Collision.wav", NULL, SND_FILENAME + SND_ASYNC);
  #else
    printf("%c", 7);
    fflush(stdout);
  #endif
}