NeHe教程在这节课向我们介绍了轨迹球技术。轨迹球技术可以让用户使用鼠标直接旋转物体,这是所有交互式3D软件必须提供的最基本的功能。在OSG中已经提供了功能强大的漫游器,包括TrackballManipulator、FirstPersonManipulator、DriveManipulator等等,具体实现的代码可以参看osgGA库中的源码部分。
首先创建场景中的两个几何体:
osg::Geode* createSphereGeode() osg::Geode* createTorusGeode(float MinorRadius, float MajorRadius)
osg::MatrixTransform *torusMT = new osg::MatrixTransform; torusMT->setMatrix(osg::Matrix::translate(-1.5, 0.0, -6.0)); torusMT->addChild(createTorusGeode(0.3,1.0)); osg::MatrixTransform *sphereMT = new osg::MatrixTransform; sphereMT->setMatrix(osg::Matrix::translate(1.5, 0.0, -6.0)); sphereMT->addChild(createSphereGeode()); root->addChild(torusMT); root->addChild(sphereMT);
this->setCameraManipulator(new osgGA::TrackballManipulator);
附:本课源码(源码中可能存在着错误和不足之处,仅供参考)
#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/ShapeDrawable> #include <osgGA/TrackballManipulator> osg::Geode* createSphereGeode() { osg::Geode *sphereGeode = new osg::Geode; osg::ShapeDrawable *shapeDrawable = new osg::ShapeDrawable; shapeDrawable->setShape(new osg::Sphere(osg::Vec3(), 1.3)); shapeDrawable->setColor(osg::Vec4(1.0f,0.75f,0.75f, 1.0f)); sphereGeode->addDrawable(shapeDrawable); return sphereGeode; } osg::Geode* createTorusGeode(float MinorRadius, float MajorRadius) { osg::Geode *geode = new osg::Geode; osg::Geometry *geometry = new osg::Geometry; osg::Vec3Array *vertexArray = new osg::Vec3Array; osg::Vec3Array *normalArray = new osg::Vec3Array; osg::Vec3Array *colorArray = new osg::Vec3Array; colorArray->push_back(osg::Vec3(0.75f,0.75f,1.0f)); for (int i=0; i<20; i++ ) // Stacks { for (int j=-1; j<20; j++) // Slices { float wrapFrac = (j%20)/(float)20; float phi = 2* osg::PI*wrapFrac; float sinphi = float(sin(phi)); float cosphi = float(cos(phi)); float r = MajorRadius + MinorRadius*cosphi; normalArray->push_back(osg::Vec3(float(sin(2* osg::PI*(i%20+wrapFrac)/(float)20))*cosphi, sinphi, float(cos(2* osg::PI*(i%20+wrapFrac)/(float)20))*cosphi)); vertexArray->push_back(osg::Vec3(float(sin(2* osg::PI*(i%20+wrapFrac)/(float)20))*r,MinorRadius*sinphi,float(cos(2* osg::PI*(i%20+wrapFrac)/(float)20))*r)); normalArray->push_back(osg::Vec3(float(sin(2* osg::PI*(i+1%20+wrapFrac)/(float)20))*cosphi, sinphi, float(cos(2* osg::PI*(i+1%20+wrapFrac)/(float)20))*cosphi)); vertexArray->push_back(osg::Vec3(float(sin(2* osg::PI*(i+1%20+wrapFrac)/(float)20))*r,MinorRadius*sinphi,float(cos(2* osg::PI*(i+1%20+wrapFrac)/(float)20))*r)); } } geometry->setVertexArray(vertexArray); geometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size())); geode->addDrawable(geometry); return geode; } 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 ); //添加轨迹球 this->setCameraManipulator(new osgGA::TrackballManipulator); 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; }; osg::Node* buildScene() { osg::Group *root = new osg::Group; osg::MatrixTransform *torusMT = new osg::MatrixTransform; torusMT->setMatrix(osg::Matrix::translate(-1.5, 0.0, -6.0)); torusMT->addChild(createTorusGeode(0.3,1.0)); osg::MatrixTransform *sphereMT = new osg::MatrixTransform; sphereMT->setMatrix(osg::Matrix::translate(1.5, 0.0, -6.0)); sphereMT->addChild(createSphereGeode()); root->addChild(torusMT); root->addChild(sphereMT); 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(); }