simpleAnimationViewer

Introduction

This an example of how to animate an X3D model by accessing to the vertex arrays of the X3DTK::GL::IndexedFaceSet node of the GL scene graph. Here we want to deform the model globally. This is realized by deforming directly the surface defined by the X3DTK::GL::IndexedFaceSet of the GL scene graph. At each time step, the tree is traversed and the vertices of the X3DTK::GL::IndexedFaceSet nodes are moved. So we create a GL::SimpleAnimator processor. For more details about the processor creation, go to glNormalViewer.

Some important functions and classes:

GL::SimpleAnimatorStateVariables

To animate the model, we need to store the time as a state variable of the traversal, as well as the bounding box of the scene, necessary to the deformation function. That is why we derive X3DTK::StateVariables in X3DTK::GL::SimpleAnimatorStateVariables to share these informations to all the component visitors.

GL::SimpleAnimatorGeometry3DVisitor

We have to visit the X3DTK::GL::IndexedFaceSet nodes. To be general, we have to process the different possible types of vertex arrays, implying that the code is redundant. There are 8 cases: 4 vertex formats plus the fact that the vertices can be duplicated. Indeed sometimes the model requires that the GL vertices are duplicated. It means that for a vertex of the X3DTK::X3D::IndexedFaceSet node, there are one or more vertices for the X3DTK::GL::IndexedFaceSet node. That is why, to find the relation between the X3D vertices and the GL vertices, we use the X3DToGLIndex.

GL::SimpleAnimator

This is the facade of the processor.

SimpleAnimationScene

We customize X3DTK::SimpleX3DGLScene by adding methods relative to the animation of the model.

Code

GL_SimpleAnimatorStateVariables.h

#ifndef GLSIMPLEANIMATORGLOBALVARIABLES_H
#define GLSIMPLEANIMATORGLOBALVARIABLES_H

#include <X3DTK/kernel.h>

namespace X3DTK {
namespace GL {

// StateVariables for the SimpleAnimator processor.

class SimpleAnimatorStateVariables : public StateVariables
{
public:
  SimpleAnimatorStateVariables();

  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

GL_SimpleAnimatorStateVariables.cpp

#include "GL_SimpleAnimatorStateVariables.h"

namespace X3DTK {
namespace GL {

SimpleAnimatorStateVariables::SimpleAnimatorStateVariables()
: StateVariables(), _time(0.0f)
{
}

void SimpleAnimatorStateVariables::setBBoxSize(const SFVec3f &size)
{
  _bboxSize = size;
}

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

}
}

GL_SimpleAnimatorGeometry3DVisitor.h

#ifndef GLSIMPLEANIMATORGEOMETRY3DVISITOR_H
#define GLSIMPLEANIMATORGEOMETRY3DVISITOR_H

#include "GL_SimpleAnimatorStateVariables.h"

#include <X3DTK/GL/scenegraph.h>

namespace X3DTK {
namespace GL {

class IndexedFaceSet;

// Visitor for the Geometry3D component of the SimpleAnimator processor.

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

  static void enterIndexedFaceSet(IndexedFaceSet *I);
};

}
}

#endif

GL_SimpleAnimatorGeometry3DVisitor.cpp

#include "GL_SimpleAnimatorGeometry3DVisitor.h"

#include <iostream>
#include <cmath>

using namespace std;

namespace X3DTK {
namespace GL {

SimpleAnimatorGeometry3DVisitor::SimpleAnimatorGeometry3DVisitor()
: Geometry3DVisitor()
{
  // Enter functions.
  define(Recorder<IndexedFaceSet>::getEnterFunction(&SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet));
}

void SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet(IndexedFaceSet *I)
{
  // StateVariables assignation.
  SimpleAnimatorStateVariables *stateVariables = Singleton<SimpleAnimatorStateVariables>::getInstance();

  // Parameters for the animation.
  SFVec3f size = stateVariables->getBBoxSize();
  float mz = size.z;
  float mxy = (size.x < size.y ? size.y : size.x);
  
  float a = mxy*mxy*mz*0.1f*cosf(stateVariables->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();
   
    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();

    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();

    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();

    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 to have a smooth rendering.  
  I->computeNormals();
}

}
}

GL_SimpleAnimator.h

#ifndef GLSIMPLEANIMATOR_H
#define GLSIMPLEANIMATOR_H

#include "GL_SimpleAnimatorStateVariables.h"

#include <X3DTK/GL/scenegraph.h>

namespace X3DTK {
namespace GL {

// SimpleAnimator processor.

class SimpleAnimator : public X3DOnePassProcessor
{
public:
  SimpleAnimator();
  virtual ~SimpleAnimator();
  
  void setBBoxSize(const SFVec3f &size);
  virtual void animate(SFNode N, float time);
};

}
}

#endif

GL_SimpleAnimator.cpp

#include "GL_SimpleAnimator.h"
#include "GL_SimpleAnimatorGeometry3DVisitor.h"

namespace X3DTK {
namespace GL {

SimpleAnimator::SimpleAnimator()
: X3DOnePassProcessor()
{
  setGraphTraversal(new DFSGraphTraversal());
  setComponentVisitor(new SimpleAnimatorGeometry3DVisitor());
}

SimpleAnimator::~SimpleAnimator()
{
  Singleton<SimpleAnimatorStateVariables>::removeInstance();
}

void SimpleAnimator::setBBoxSize(const SFVec3f &size)
{
  Singleton<SimpleAnimatorStateVariables>::getInstance()->setBBoxSize(size);
}

void SimpleAnimator::animate(SFNode N, float time)
{
  // Setting the time.
  Singleton<SimpleAnimatorStateVariables>::getInstance()->setTime(time);
  getGraphTraversal()->traverse(N);
}

}
}

SimpleAnimationScene.h

#ifndef SIMPLEANIMATIONSCENE_H
#define SIMPLEANIMATIONSCENE_H

#include "GL_SimpleAnimator.h"

#include <X3DTK/simplex3dglscene.h>
#include <X3DTK/X3D/worldcoordtranslator.h>

namespace X3DTK {

// Class providing the animation and the loading of an X3D model.

class SimpleAnimationScene : public SimpleX3DGLScene
{
public:
  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 = Singleton<GL::SimpleAnimator>::getInstance();
  _translator = Singleton<X3D::WorldCoordTranslator>::getInstance();
}

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.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();
  void about();
  QString helpString() const;
  void help() const;
  
private:
  X3DTK::SimpleAnimationScene scene;
  X3DTK::BBox BB;
  char *x3dfile;
};

#endif

Viewer.cpp

#include "Viewer.h"
#include <math.h>
#include <iostream>
#include <qfiledialog.h>
#include <qmessagebox.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();

  // QGLViewer settings.
  setSceneBoundingBox(scene.getBBoxMin().f_data(), scene.getBBoxMax().f_data());
  setSceneRadius(2.0f*sceneRadius());
  showEntireScene();
}

void Viewer::init()
{
#ifdef GL_RESCALE_NORMAL
  glEnable(GL_RESCALE_NORMAL);
#endif
  about();
  loadFile();
}

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

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

void Viewer::about()
{
  QMessageBox::about(this, "about the simpleAnimationViewer", "this is an example showing how to animate a simple X3D scene.Type 'h' to display help");
}

QString Viewer::helpString() const
{
  QString message("");
  
  message += "<b>S</b>" + QString(" starts the animation<br>");
  message += "<b>P</b>" + QString(" pauses the animation<br>");
  message += "<b>L</b>" + QString(" loads a new file<br>");
  
  message += QGLViewer::helpString();
  
  return message;
}

void Viewer::help() const
{
  QMessageBox *mb = new QMessageBox("help", helpString(), QMessageBox::NoIcon,QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton,QMessageBox::NoButton, NULL, "Help", false,Qt::WStyle_DialogBorder | Qt::WType_Dialog | Qt::WDestructiveClose);
  mb->show();
}

Generated on Fri Jul 30 12:02:33 2004 for X3DToolKit by doxygen 1.3.6