OpenSceneGraph实现的NeHe OpenGL教程 - 第四课

    xiaoxiao2026-04-12  4

    简介

    本课要实现的效果是让三角形绕自身的轴线Y轴进行旋转, 四边形绕自身X轴进行旋转。

    在osg中实现这种效果有很多种方法可以做到,无论哪种方法总体的思路是定时地去修改场景中的空间变换节点,本文采用最简单的一种方式进行修改:使用场景中节点的回调来修改空间变换节点从而达到旋转的效果。

    实现

    首先我们先定义一个场景节点的Callback类,OSG中的节点主要使用回调(Callback)来完成用户临时定义的、需要每帧执行的工作。这是一种方便的扩展节点功能的方式,根据回调功能被调用的时机,OSG节点回调包括更新回调(UpdateCallback)和人机交互事件回调(EventCallback)两种,前者在每一帧系统遍历到当前节点时自动调用,后者则通过用户操作键盘、鼠标、改变窗口等动作发生,触发事件回调。此处我们需要的是一个节点的更新回调,定义如下:

    [cpp]  view plain  copy   class RotateCallback : public osg::NodeCallback   {      public:       RotateCallback(osg::Vec3d rotateAxis, double rotateSpeed) :          osg::NodeCallback(),         _rotateAxis(rotateAxis),          _rotateSpeed(rotateSpeed),         _rotateAngle(0.0)         {           //Nop         }               virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)       {               osg::MatrixTransform *currentMT = dynamic_cast<osg::MatrixTransform*>(node);               if (currentMT)               {                   //获取当前的平移位置                   osg::Vec3d currentTranslate = currentMT->getMatrix().getTrans();                   osg::Matrix newMatrix = osg::Matrix::rotate(_rotateAngle, _rotateAxis) * osg::Matrix::translate(currentTranslate);                   currentMT->setMatrix(newMatrix);                   _rotateAngle += _rotateSpeed;               }                  traverse(node, nv);       }         private:       osg::Vec3d _rotateAxis;         //旋转轴       double        _rotateSpeed;     //旋转速度       double        _rotateAngle;     //当前旋转的角度   };   节点回调类都继承于osg::NodeCallback,我们需要做的是重载它里面的operator()方法来实现自定义的代码,定义好之后将回调加入到三角形和四边形的空间变化节点之中:

    [cpp]  view plain  copy   osg::MatrixTransform *triangleMT = new osg::MatrixTransform;   triangleMT->setMatrix(osg::Matrix::translate(-1.5, 0.0, -6.0));      RotateCallback *triangleRotateCallback = new RotateCallback(osg::Y_AXIS, 0.2);   triangleMT->addUpdateCallback(triangleRotateCallback);   以及

    [cpp]  view plain  copy   osg::MatrixTransform *quadMT = new osg::MatrixTransform;   quadMT->setMatrix(osg::Matrix::translate(1.5, 0.0, -6.0));      RotateCallback *quadRotateCallback = new RotateCallback(osg::X_AXIS, 0.15);   quadMT->addUpdateCallback(quadRotateCallback);   编译并运行程序即看到动态的效果

    附:本课源码(源码中可能存在错误和不足,仅供参考)

    [cpp]  view plain  copy   #include "../osgNeHe.h"      #include <QtCore/QTimer>   #include <QtGui/QApplication>   #include <QtGui/QVBoxLayout>      #include <osgViewer/Viewer>   #include <osgDB/ReadFile>   #include <osgQt/GraphicsWindowQt>      #include <osg/MatrixTransform>   #include <osg/NodeVisitor>         class ViewerWidget : public QWidget, public osgViewer::Viewer   {   public:       ViewerWidget(osg::Node *scene = NULL)       {           QWidget* renderWidget = getRenderWidget( createGraphicsWindow(0,0,100,100), scene);              QVBoxLayout* layout = new QVBoxLayout;           layout->addWidget(renderWidget);           layout->setContentsMargins(0, 0, 0, 1);           setLayout( layout );              connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );           _timer.start( 10 );       }          QWidget* getRenderWidget( osgQt::GraphicsWindowQt* gw, osg::Node* scene )       {           osg::Camera* camera = this->getCamera();           camera->setGraphicsContext( gw );              const osg::GraphicsContext::Traits* traits = gw->getTraits();              camera->setClearColor( osg::Vec4(0.0, 0.0, 0.0, 1.0) );           camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );           camera->setProjectionMatrixAsPerspective(45.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 0.1f, 100.0f );           camera->setViewMatrixAsLookAt(osg::Vec3d(0, 0, 1), osg::Vec3d(0, 0, 0), osg::Vec3d(0, 1, 0));              this->setSceneData( scene );              return gw->getGLWidget();       }          osgQt::GraphicsWindowQt* createGraphicsWindow( int x, int y, int w, int h, const std::string& name=""bool windowDecoration=false )       {           osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();           osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;           traits->windowName = name;           traits->windowDecoration = windowDecoration;           traits->x = x;           traits->y = y;           traits->width = w;           traits->height = h;           traits->doubleBuffer = true;           traits->alpha = ds->getMinimumNumAlphaBits();           traits->stencil = ds->getMinimumNumStencilBits();           traits->sampleBuffers = ds->getMultiSamples();           traits->samples = ds->getNumMultiSamples();              return new osgQt::GraphicsWindowQt(traits.get());       }          virtual void paintEvent( QPaintEvent* event )       {            frame();        }      protected:          QTimer _timer;   };            //   //RotateCallback      class RotateCallback : public osg::NodeCallback   {      public:       RotateCallback(osg::Vec3d rotateAxis, double rotateSpeed) :          osg::NodeCallback(),         _rotateAxis(rotateAxis),          _rotateSpeed(rotateSpeed),         _rotateAngle(0.0)         {           //Nop         }               virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)       {               osg::MatrixTransform *currentMT = dynamic_cast<osg::MatrixTransform*>(node);               if (currentMT)               {                   //获取当前的平移位置                   osg::Vec3d currentTranslate = currentMT->getMatrix().getTrans();                   osg::Matrix newMatrix = osg::Matrix::rotate(_rotateAngle, _rotateAxis) * osg::Matrix::translate(currentTranslate);                   currentMT->setMatrix(newMatrix);                   _rotateAngle += _rotateSpeed;               }                  traverse(node, nv);       }         private:       osg::Vec3d _rotateAxis;         //旋转轴       double        _rotateSpeed;     //旋转速度       double        _rotateAngle;     //当前旋转的角度   };            osg::Node*  buildScene()   {       osg::Group *root = new osg::Group;          osg::MatrixTransform *triangleMT = new osg::MatrixTransform;       triangleMT->setMatrix(osg::Matrix::translate(-1.5, 0.0, -6.0));          RotateCallback *triangleRotateCallback = new RotateCallback(osg::Y_AXIS, 0.2);       triangleMT->addUpdateCallback(triangleRotateCallback);          osg::Geometry *triangleGeometry = new osg::Geometry;       osg::Vec3Array *triangleVertexArray = new osg::Vec3Array;       triangleVertexArray->push_back(osg::Vec3(0.0f, 1.0f, 0.0f));       triangleVertexArray->push_back(osg::Vec3(-1.0f,-1.0f, 0.0f));       triangleVertexArray->push_back(osg::Vec3(1.0f,-1.0f, 0.0f));       triangleGeometry->setVertexArray(triangleVertexArray);          osg::Vec4Array *triangleColorArray = new osg::Vec4Array;       triangleColorArray->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));       triangleColorArray->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));       triangleColorArray->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));       triangleGeometry->setColorArray(triangleColorArray);       triangleGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);          triangleGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 3));       osg::Geode *triangleGeode = new osg::Geode;          triangleGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);       triangleGeode->addDrawable(triangleGeometry);       triangleMT->addChild(triangleGeode);          //四边形部分       osg::MatrixTransform *quadMT = new osg::MatrixTransform;       quadMT->setMatrix(osg::Matrix::translate(1.5, 0.0, -6.0));          RotateCallback *quadRotateCallback = new RotateCallback(osg::X_AXIS, 0.15);       quadMT->addUpdateCallback(quadRotateCallback);          osg::Geometry *quadGeometry = new osg::Geometry;       osg::Vec3Array *quadVertexArray = new osg::Vec3Array;       quadVertexArray->push_back(osg::Vec3(-1.0f, 1.0f, 0.0f));       quadVertexArray->push_back(osg::Vec3(1.0f, 1.0f, 0.0f));       quadVertexArray->push_back(osg::Vec3(1.0f,-1.0f, 0.0f));       quadVertexArray->push_back(osg::Vec3(-1.0f,-1.0f, 0.0f));       quadGeometry->setVertexArray(quadVertexArray);          osg::Vec4Array *quadColorArray = new osg::Vec4Array;       quadColorArray->push_back(osg::Vec4(0.5f,0.5f,1.0f,1.0f));       quadGeometry->setColorArray(quadColorArray);       quadGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);          osg::DrawElementsUByte *vertexIndices = new osg::DrawElementsUByte(osg::PrimitiveSet::QUADS, 4);       vertexIndices->push_back(0);       vertexIndices->push_back(1);       vertexIndices->push_back(2);       vertexIndices->push_back(3);       quadGeometry->addPrimitiveSet(vertexIndices);       osg::Geode *quadGeode = new osg::Geode;       quadGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);       quadGeode->addDrawable(quadGeometry);       quadMT->addChild(quadGeode);          root->addChild(triangleMT);       root->addChild(quadMT);          return root;   }            int main( int argc, char** argv )   {       QApplication app(argc, argv);       ViewerWidget* viewWidget = new ViewerWidget(buildScene());       viewWidget->setGeometry( 100, 100, 640, 480 );       viewWidget->show();       return app.exec();   }  
    转载请注明原文地址: https://ju.6miu.com/read-1308754.html
    最新回复(0)