Main Page Namespace List Class Hierarchy Compound List File List Namespace Members Compound Members File Members Related Pages
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
#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
#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()
{
defineNewEnterFunction<SimpleAnimatorGeometry3DVisitor, IndexedFaceSet>(&SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet);
globalVariables = GVManager::getInstanceOf<SimpleAnimatorGlobalVariables>();
}
SimpleAnimatorGeometry3DVisitor::~SimpleAnimatorGeometry3DVisitor()
{
}
void SimpleAnimatorGeometry3DVisitor::enterIndexedFaceSet(IndexedFaceSet *I) const
{
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;
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();
}
}
}
GLSimpleAnimator
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()
{
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)
{
globalVariables->setTime(time);
dfs->traverse(N);
}
}
}
SimpleAnimationScene
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)
{
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
#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);
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()
{
loadFile();
glEnable(GL_RESCALE_NORMAL);
}
void Viewer::animate()
{
scene.animate();
}
void Viewer::draw()
{
scene.draw();
}
Generated on Thu Jul 31 12:58:35 2003 for X3DToolKit by
1.3