Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

simple animation

Introduction

This is an example of how to write a processor GL::SimpleAnimator that will animate a GL scene. We want to deform the 3D model.

GL::SimpleAnimatorGlobalVariables

To provide a continuous animation, we have to store the time in the global variables of the traversal. So we derive GlobalVariables to get and set the time, as well as the bounding box computed when the model is loaded.

GL::SimpleAnimatorGeometry3DVisitor

This is the only component visitor to write. We access directly the vertex arrays of the GL::IndexedFaceSet that will be sent to the graphic card. We want to change the y coordinate of the vertex in function of time. Nevertheless, due to the X3D format, to be exhaustive we have to process eight very similar different cases. Indeed there are four vertex formats (GL_N3F_V3F, GL_C4F_N3F_V3F, GL_T2F_N3F_V3F, GL_T2F_C4F_N3F_V3F). Moreover for some reason, the vertices can be duplicated, meaning that in the vertex array, several vertices have the same coordinates but different normals for instance due to a discontinuity in the surface. In the case of duplicated vertices, we use the X3DToGLIndex to compute more efficiently the new vertex array. This array gives the connections between the X3D index and the GL index. For example, X3DToGLIndex[3] = {45, 61, 102}, means that the vertex at coordIndex 3 of the X3D::IndexedFaceSet, can be found at index 45, 61 and 102 of the GL vertex array. So to reduce computation time we compute the new position of the vertex at index 45 and copy it to the others 61 and 102. Another way to proceed is to have computed the vertex array before the rendering of the scene. So in that case, we just have to copy the new values to the GL vertex array.

GL::SimpleAnimator

This is the facade of the processor. It also contains the algorithm GL::DefaultDFS of traversal of the scene graph.

SimpleAnimationScene

We customize SimpleX3DGLScene to add controls for the animation, as well as the processor WorldCoordTranslator to ensure that all the cordinates are in the the world coordinates.

Code

GLSimpleAnimatorGlobalVariables

GLSimpleAnimatorGlobalVariables.h







//                            GLSimpleAnimatorGlobalVariables.h               //

#ifndef GLSIMPLEANIMATORGLOBALVARIABLES_H
#define GLSIMPLEANIMATORGLOBALVARIABLES_H

#include <X3DTK/kernel.h>

namespace X3DTK {
namespace GL {


class SimpleAnimatorGlobalVariables : public GlobalVariables
{
public:
  SimpleAnimatorGlobalVariables();
  virtual ~SimpleAnimatorGlobalVariables();

  void setBboxSize(const SFVec3f &size);
  void setTime(float time);

  float getTime() const {return _time;};
  inline SFVec3f getBboxSize() const {return _bboxSize;};
  
private: 
  float _time;
  SFVec3f _bboxSize;
};

}
}

#endif

GLSimpleAnimatorGlobalVariables.cpp

#include "GLSimpleAnimatorGlobalVariables.h"

namespace X3DTK {
namespace GL {

SimpleAnimatorGlobalVariables::SimpleAnimatorGlobalVariables()
: GlobalVariables(), _time(0.0f)
{
}

SimpleAnimatorGlobalVariables::~SimpleAnimatorGlobalVariables()
{
}

void SimpleAnimatorGlobalVariables::setBboxSize(const SFVec3f &size)
{
  _bboxSize = size;
}

void SimpleAnimatorGlobalVariables::setTime(float time)
{
  _time = time;
}

}
}

GLSimpleAnimatorGeometry3DVisitor

GLSimpleAnimatorGeometry3DVisitor.h







//                            GLSimpleAnimatorGeometry3DVisitor.h             //

#ifndef GLSIMPLEANIMATORGEOMETRY3DVISITOR_H
#define GLSIMPLEANIMATORGEOMETRY3DVISITOR_H

#include "GLSimpleAnimatorGlobalVariables.h"

#include <X3DTK/kernel.h>

namespace X3DTK {
namespace GL {

class IndexedFaceSet;


class SimpleAnimatorGeometry3DVisitor : public Geometry3DVisitor
{
public:
  SimpleAnimatorGeometry3DVisitor();
  virtual ~SimpleAnimatorGeometry3DVisitor();

  virtual void enterIndexedFaceSet(IndexedFaceSet *I) const;

protected:
  SimpleAnimatorGlobalVariables *globalVariables;
};

}
}

#endif

GLSimpleAnimatorGeometry3DVisitor.cpp

#include "GLSimpleAnimatorGeometry3DVisitor.h"

#include <iostream>
#include <cmath>

using namespace std;

namespace X3DTK {
namespace GL {

SimpleAnimatorGeometry3DVisitor::SimpleAnimatorGeometry3DVisitor()
: Geometry3DVisitor()
{
  // Enter functions.
  defineNewEnterFunction<SimpleAnimatorGeometry3DVisitor, IndexedFaceSet>(&SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet);

  // GlobalVariables assignation.
  globalVariables = GVManager::getInstanceOf<SimpleAnimatorGlobalVariables>();
}

SimpleAnimatorGeometry3DVisitor::~SimpleAnimatorGeometry3DVisitor()
{
}

void SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet(IndexedFaceSet *I) const
{
  //Parameters for the animation.
  SFVec3f size = globalVariables->getBboxSize();
  float mz = size.z;
  float mxy = (size.x < size.y ? size.y : size.x);
  
  float a = mxy*mxy*mz*0.1f*cosf(globalVariables->getTime());
  float b = mxy*mxy;
  float c = 1.0f;
  float d = a/b;

  //switching to the appropriate case. 8 cases: 4 vertex formats, plus the fact that 
  //the vertices can be duplicated when necessary. When duplicated, it means that two
  //vertices have the same coordinates, but different other properties like color...

  if (I->getVertexFormat() == GL_N3F_V3F)
  {
    vector<N3F_V3F> &vertexArray = I->N3F_V3F_vertexArray();
   
    if (I->getVerticesDuplicated())
    {
      //getting the list of vertices duplicated.
      const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
    
      for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
      {
        if ((*itIndexArray).size() > 0)
        {
          //computing the new coordinates for the first vertex.
          N3F_V3F *V = &vertexArray[(*itIndexArray).front()];
          V->vertex.y = V->vertex.y - d + a/(b + c*(V->vertex.x*V->vertex.x + V->vertex.z*V->vertex.z));
          
          //copying the coordinates for the others.
          for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
            vertexArray[*itIndex].vertex = V->vertex;
        }
      }
    }
    else
    {
      //the vertices are not duplicated.
      for (vector<N3F_V3F>::iterator itVertex = vertexArray.begin(); itVertex != vertexArray.end(); ++itVertex)
        (*itVertex).vertex.y = (*itVertex).vertex.y - d + a/(b + c*((*itVertex).vertex.x*(*itVertex).vertex.x + (*itVertex).vertex.z*(*itVertex).vertex.z));
    }  
  }
  
  if (I->getVertexFormat() == GL_C4F_N3F_V3F)
  {
    vector<C4F_N3F_V3F> &vertexArray = I->C4F_N3F_V3F_vertexArray();
    
    if (I->getVerticesDuplicated())
    {
      //getting the list of vertices duplicated.
      const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
    
      for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
      {
        if ((*itIndexArray).size() > 0)
        {
          //computing the new coordinates for the first vertex.
          C4F_N3F_V3F *V = &vertexArray[(*itIndexArray).front()];
          V->vertex.y = V->vertex.y - d + a/(b + c*(V->vertex.x*V->vertex.x + V->vertex.z*V->vertex.z));
          
          //copying the coordinates for the others.
          for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
            vertexArray[*itIndex].vertex = V->vertex;
        }
      }
    }
    else
    {
      //the vertices are not duplicated.
      for (vector<C4F_N3F_V3F>::iterator itVertex = vertexArray.begin(); itVertex != vertexArray.end(); ++itVertex)
        (*itVertex).vertex.y = (*itVertex).vertex.y - d + a/(b + c*((*itVertex).vertex.x*(*itVertex).vertex.x + (*itVertex).vertex.z*(*itVertex).vertex.z));
    } 
  }

  if (I->getVertexFormat() == GL_T2F_N3F_V3F)
  {
    vector<T2F_N3F_V3F> &vertexArray = I->T2F_N3F_V3F_vertexArray();
    
    if (I->getVerticesDuplicated())
    {
      //getting the list of vertices duplicated.
      const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
    
      for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
      {
        if ((*itIndexArray).size() > 0)
        {
          //computing the new coordinates for the first vertex.
          T2F_N3F_V3F *V = &vertexArray[(*itIndexArray).front()];
          V->vertex.y = V->vertex.y - d + a/(b + c*(V->vertex.x*V->vertex.x + V->vertex.z*V->vertex.z));
          
          //copying the coordinates for the others.
          for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
            vertexArray[*itIndex].vertex = V->vertex;
        }
      }
    }
    else
    {
      //the vertices are not duplicated.
      for (vector<T2F_N3F_V3F>::iterator itVertex = vertexArray.begin(); itVertex != vertexArray.end(); ++itVertex)
        (*itVertex).vertex.y = (*itVertex).vertex.y - d + a/(b + c*((*itVertex).vertex.x*(*itVertex).vertex.x + (*itVertex).vertex.z*(*itVertex).vertex.z));
    }   
  }

  if (I->getVertexFormat() == GL_T2F_C4F_N3F_V3F)
  {
    vector<T2F_C4F_N3F_V3F> &vertexArray = I->T2F_C4F_N3F_V3F_vertexArray();
    
    if (I->getVerticesDuplicated())
    {
      //getting the list of vertices duplicated.
      const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
    
      for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
      {
        if ((*itIndexArray).size() > 0)
        {
          //computing the new coordinates for the first vertex.
          T2F_C4F_N3F_V3F *V = &vertexArray[(*itIndexArray).front()];
          V->vertex.y = V->vertex.y - d + a/(b + c*(V->vertex.x*V->vertex.x + V->vertex.z*V->vertex.z));
          
          //copying the coordinates for the others.
          for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
            vertexArray[*itIndex].vertex = V->vertex;
        }
      }
    }
    else
    {
      //the vertices are not duplicated.
      for (vector<T2F_C4F_N3F_V3F>::iterator itVertex = vertexArray.begin(); itVertex != vertexArray.end(); ++itVertex)
        (*itVertex).vertex.y = (*itVertex).vertex.y - d + a/(b + c*((*itVertex).vertex.x*(*itVertex).vertex.x + (*itVertex).vertex.z*(*itVertex).vertex.z));
    } 
  }

  //recomputing the normals.  
  I->computeNormals();
}

}
}

GLSimpleAnimator

GLSimpleAnimator.h







//                            GLSimpleAnimator.h                              //

#ifndef GLSIMPLEANIMATOR_H
#define GLSIMPLEANIMATOR_H

#include "GLSimpleAnimatorGlobalVariables.h"

#include <X3DTK/kernel.h>

namespace X3DTK {
namespace GL {


class SimpleAnimator : public X3DTTAlgorithm
{
public:
  SimpleAnimator();
  virtual ~SimpleAnimator();
  
  void setBboxSize(const SFVec3f &size);
  virtual void animate(SFNode N, float time);
 
protected:
  SimpleAnimatorGlobalVariables *globalVariables;
  DFS *dfs;
};

}
}

#endif

GLSimpleAnimator.cpp

#include "GLSimpleAnimator.h"
#include "GLSimpleAnimatorGeometry3DVisitor.h"

namespace X3DTK {
namespace GL {

SimpleAnimator::SimpleAnimator()
: X3DTTAlgorithm()
{
  //Getting the global variables.
  globalVariables = GVManager::getInstanceOf<SimpleAnimatorGlobalVariables>();
    
  dfs = new DefaultDFS();
  dfs->setComponentVisitor(new SimpleAnimatorGeometry3DVisitor());
}

SimpleAnimator::~SimpleAnimator()
{
  delete dfs;
}

void SimpleAnimator::setBboxSize(const SFVec3f &size)
{
  globalVariables->setBboxSize(size);
}

void SimpleAnimator::animate(SFNode N, float time)
{
  // Setting the time.
  globalVariables->setTime(time);
  dfs->traverse(N);
}

}
}

SimpleAnimationScene

SimpleAnimationScene.h







//                            SimpleAnimationScene.h                          //

#ifndef SIMPLEANIMATIONSCENE_H
#define SIMPLEANIMATIONSCENE_H

#include <X3DTK/simplex3dglscene.h>
#include <X3DTK/worldcoordtranslator.h>
#include "GLSimpleAnimator.h"

namespace X3DTK {


class SimpleAnimationScene : public SimpleX3DGLScene
{
public:
  SimpleAnimationScene();
  virtual ~SimpleAnimationScene();
  
  virtual void load(const char *file, bool fileValidation = true);
  virtual void init();
  virtual void animate();

private:
  GL::SimpleAnimator *_glSimpleAnimator;
  X3D::WorldCoordTranslator *_translator;
  float _time;
};

}

#endif

SimpleAnimationScene.cpp

#include "SimpleAnimationScene.h"

#include <iostream>
using namespace std;

namespace X3DTK {

SimpleAnimationScene::SimpleAnimationScene()
: SimpleX3DGLScene(), _time(0.0f)
{
  _glSimpleAnimator = new GL::SimpleAnimator();
  _translator = new X3D::WorldCoordTranslator();
}

SimpleAnimationScene::~SimpleAnimationScene()
{
  delete _glSimpleAnimator;
}

void SimpleAnimationScene::load(const char *file, bool fileValidation)
{
  //Overloading the load method, to apply the WorldCoordTranslator processor to the scene.
  loadFile(file, fileValidation);
  _translator->translate(scene);
  computeBbox();
  buildGLScene();
}

void SimpleAnimationScene::init()
{
  _time = 0.0f;  
  if (scene != 0)
    _glSimpleAnimator->setBboxSize(scene->getBboxSize());
}

void SimpleAnimationScene::animate()
{
  _time += 0.03f;
  _glSimpleAnimator->animate(glscene, _time);
}

}

Viewer

Viewer.h







//                            Viewer.h                                        //

#ifndef VIEWER_H
#define VIEWER_H

#include <QGLViewer/qglviewer.h>
#include "SimpleAnimationScene.h"


class Viewer : public QGLViewer
{
public:
  Viewer(const char *file);
  ~Viewer();
  
protected :
  void loadFile();
  void keyPressEvent(QKeyEvent *e);
  void init();
  void animate();
  void draw();
  
private:
  X3DTK::SimpleAnimationScene scene;
  X3DTK::Bbox BB;
  char *x3dfile;
};

#endif

Viewer.cpp

#include "Viewer.h"

#include <math.h>
#include <iostream>
#include <qfiledialog.h>

using namespace X3DTK;
using namespace std;

Viewer::Viewer(const char *file)
{
  x3dfile = (char *)file;
}

Viewer::~Viewer()
{
  scene.release();
}

void Viewer::keyPressEvent(QKeyEvent *e)
{
  switch (e->key())
  {
    case Qt::Key_L : 
      loadFile(); break;
    case Qt::Key_S : 
      startAnimation(); break;  
    case Qt::Key_P : 
      stopAnimation(); break;  
    default: 
      QGLViewer::keyPressEvent(e);
  }
  updateGL();
}

void Viewer::loadFile()
{
  QString name = QFileDialog::getOpenFileName("", "X3D files (*.x3d *.X3D);;All files (*)", this);
  
  // In case of Cancel
  if (name.isEmpty())
    return;

  // Loads the file name.
  scene.load(name, false);
  scene.init();

  setSceneBoundingBox(scene.getBboxMin().f_data(), scene.getBboxMax().f_data());
  setSceneRadius(2.0f*sceneRadius());
  showEntireScene();
}

void Viewer::init()
{
  loadFile();
  glEnable(GL_RESCALE_NORMAL);
}

void Viewer::animate()
{
  //Animates the scene.
  scene.animate();
}

void Viewer::draw()
{
  //traverse the scene graph
  scene.draw();
}


Generated on Thu Jul 31 12:58:35 2003 for X3DToolKit by doxygen1.3