Martin,

Martin Beckett wrote:
Cory Riddell wrote:
  
When the handler detects an x,y, or z keypress, it figures out the
current camera position and the desired camera positions. It then
calculates a path between the two and breaks it up into a number of
discrete steps. These intermediate positions are stored in a vector. On
each FRAME event, I pop_back() a position and set the camera to it. The
result is a pretty slick effect where the camera glides from the current
location to the desired 'home' position.
    

The animation is a nice idea.
I have users that are better suspicious of computers and they often 'get lost' in a 3D scene so anything that makes it more obvious what is happening is a good idea.
Do you have a code fragment demonstrating this?
  

Sure (although it is extremely rough right now). In my event handler, I handle a KEYUP event and test for 'x', 'y', and 'z' keys. They are all very similar. My 'x' code looks like:
  if (ea.getKey() == 'x') {
      // reposition the camera so that the vector from the camera to the center of the vessel is parallel to
      //   the x-axis
      osg::Vec3d eye, center, up;
      osgGA::MatrixManipulator* mm = viewer->getCameraManipulator();
      mm->getHomePosition(eye, center, up);
      double centerZ = center.z();
      osg::Matrix m = mm->getInverseMatrix();
      m.getLookAt(eye, center, up);           
      double radius = eye.length();
      populateCameraRepositionArrays(eye, osg::Vec3(radius, 0, centerZ), m_eyePts,
                                     center, osg::Vec3(radius-1, 0, centerZ), m_centerPts,
                                     up, osg::Vec3(0, 0, 1), m_upPts);
  }

m_eyePts, m_centerPts, and m_upPts are osg::Vec3Arrays. The 0th elements contain the final positions and the nth elements the starting positions. The populateCameraRepositionArrays() is a non-member help function that calculates all the intermediate steps. It looks like:

  /** Compute a sequence of points from an initial position to a final position. These are used to smoothly
   * reposition a camera to a predefined position. */
  void populateCameraRepositionArrays(const osg::Vec3& initEye, const osg::Vec3& finalEye, osg::Vec3Array* eyePts,
                                      const osg::Vec3& initCenter, const osg::Vec3& finalCenter, osg::Vec3Array* centerPts,
                                      const osg::Vec3& initUp, const osg::Vec3& finalUp, osg::Vec3Array* upPts)
  {
      centerPts->clear();
      eyePts->clear();
      upPts->clear();

      double eyeX1(finalEye.x()), eyeY1(finalEye.y()), eyeZ1(finalEye.z());
      double centerX1(finalCenter.x()), centerY1(finalCenter.y()), centerZ1(finalCenter.z());
      double upX1(finalUp.x()), upY1(finalUp.y()), upZ1(finalUp.z());
      double eyeDeltaX(initEye.x()-eyeX1), eyeDeltaY(initEye.y()-eyeY1), eyeDeltaZ(initEye.z()-eyeZ1);
      double centerDeltaX(initCenter.x()-centerX1), centerDeltaY(initCenter.y()-centerY1), centerDeltaZ(initCenter.z()-centerZ1);
      double upDeltaX(initUp.x()-upX1), upDeltaY(initUp.y()-upY1), upDeltaZ(initUp.z()-upZ1);
 
      double inc = 1.0 / AUTO_MOVE_STEPS;
      for (int i=0; i<AUTO_MOVE_STEPS; ++i) {
          double t = i * inc;
          eyePts->push_back(osg::Vec3(eyeX1+eyeDeltaX*t, eyeY1+eyeDeltaY*t, eyeZ1+eyeDeltaZ*t));
          centerPts->push_back(osg::Vec3(centerX1+centerDeltaX*t, centerY1+centerDeltaY*t, centerZ1+centerDeltaZ*t));
          upPts->push_back(osg::Vec3(upX1+upDeltaX*t, upY1+upDeltaY*t, upZ1+upDeltaZ*t));
      }
  }

This is just moving the camera along a chord from the initial positions to the final positions. I'm going to make it an arc later. It's using the parametric line equation:
  | x1 + (x2 - x1) * t |
  | y1 + (y2 - y1) * t |  <-- this is supposed to look like a vector
  | z1 + (z2 - z1) * t |
where
  0 <= t < 1


My FRAME event handler looks like:
  case osgGA::GUIEventAdapter::FRAME:
      {
          if (!m_centerPts->empty()) {
              osg::Vec3 eye, center, up;
              osgGA::MatrixManipulator* mm = viewer->getCameraManipulator();
              osg::Matrix m = mm->getInverseMatrix();

              center = m_centerPts->back();
              m_centerPts->pop_back();
              eye = m_eyePts->back();
              m_eyePts->pop_back();
              up = m_upPts->back();
              m_upPts->pop_back();

              if (!m_centerPts->empty()) {
                  // avoid the final setting because it generates exceptions
                  m.makeLookAt(eye, center, up);
                  viewer->getCameraManipulator()->setByInverseMatrix(m);
              }
          }
      }
      break;

Like I said, it's pretty rough, but it works. I'm going to add a time component to prevent the animation from completing too quickly on fast machines (remember computers that used to have a turbo button to run the cpu at 4.77 MHz?).

Cory



_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to