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:
X3DTK::StateVariables
in X3DTK::GL::SimpleAnimatorStateVariables
to share these informations to all the component visitors.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
.X3DTK::SimpleX3DGLScene
by adding methods relative to the animation of the model.#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
#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; } } }
#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
#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(); } } }
#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
#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); } } }
#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
#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); } }
#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
#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(); }