Introduction
This an example of how to animate an X3D model by accessing to the vertex arrays of the X3DTK::GL::IndexedFaceSet
node. 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 processor creation, go to glNormalViewer.
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 {
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;
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()
{
defineEnterFunction(&SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet);
}
void SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet(IndexedFaceSet *I)
{
SimpleAnimatorStateVariables *stateVariables = GraphTraversal::getInstanceOf<SimpleAnimatorStateVariables>();
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;
if (I->getVertexFormat() == GL_N3F_V3F)
{
vector<N3F_V3F> &vertexArray = I->N3F_V3F_vertexArray();
if (I->getVerticesDuplicated())
{
const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
{
if ((*itIndexArray).size() > 0)
{
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));
for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
vertexArray[*itIndex].vertex = V->vertex;
}
}
}
else
{
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())
{
const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
{
if ((*itIndexArray).size() > 0)
{
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));
for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
vertexArray[*itIndex].vertex = V->vertex;
}
}
}
else
{
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())
{
const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
{
if ((*itIndexArray).size() > 0)
{
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));
for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
vertexArray[*itIndex].vertex = V->vertex;
}
}
}
else
{
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())
{
const vector<MFInt32> &X3DToGLIndex = I->getX3DToGLIndex();
for (vector<MFInt32>::const_iterator itIndexArray = X3DToGLIndex.begin(); itIndexArray != X3DToGLIndex.end(); ++itIndexArray)
{
if ((*itIndexArray).size() > 0)
{
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));
for (MFInt32::const_iterator itIndex = ++((*itIndexArray).begin()); itIndex != (*itIndexArray).end(); ++itIndex)
vertexArray[*itIndex].vertex = V->vertex;
}
}
}
else
{
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));
}
}
I->computeNormals();
}
}
}
GL_SimpleAnimator.h
#ifndef GLSIMPLEANIMATOR_H
#define GLSIMPLEANIMATOR_H
#include "GL_SimpleAnimatorStateVariables.h"
#include <X3DTK/GL/scenegraph.h>
namespace X3DTK {
namespace GL {
class SimpleAnimator : public X3DOnePassProcessor
{
public:
SimpleAnimator();
virtual ~SimpleAnimator();
void setBBoxSize(const SFVec3f &size);
virtual void animate(SFNode N, float time);
protected:
SimpleAnimatorStateVariables *stateVariables;
};
}
}
#endif
GL_SimpleAnimator.cpp
#include "GL_SimpleAnimator.h"
#include "GL_SimpleAnimatorGeometry3DVisitor.h"
namespace X3DTK {
namespace GL {
SimpleAnimator::SimpleAnimator()
: X3DOnePassProcessor()
{
stateVariables = GraphTraversal::getInstanceOf<SimpleAnimatorStateVariables>();
graphTraversal = new DFSGraphTraversal();
graphTraversal->setComponentVisitor(new SimpleAnimatorGeometry3DVisitor());
}
SimpleAnimator::~SimpleAnimator()
{
GraphTraversal::removeInstanceOf<SimpleAnimatorStateVariables>();
delete graphTraversal;
}
void SimpleAnimator::setBBoxSize(const SFVec3f &size)
{
stateVariables->setBBoxSize(size);
}
void SimpleAnimator::animate(SFNode N, float time)
{
stateVariables->setTime(time);
graphTraversal->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 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 = X3DProcessor::getInstanceOf<GL::SimpleAnimator>();
_translator = X3DProcessor::getInstanceOf<X3D::WorldCoordTranslator>();
}
void SimpleAnimationScene::load(const char *file, bool fileValidation)
{
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);
if (name.isEmpty())
return;
scene.load(name, false);
scene.init();
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()
{
scene.animate();
}
void Viewer::draw()
{
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 Wed Apr 7 12:15:26 2004 for X3DToolKit by
1.3.3