NeHe教程在这节课向我们介绍了OpenGL的扩展(ARB_MULTISAMPLE)多重采样技术。利用这种技术可以实现全屏反走样。这样可以使图形看起来更美观。
在OSG中多重采样是作为节点的StateSet来开启和关闭的,实现过程十分简单。
首先添加四边形到场景中,这一过程前面已经重复很多遍了,代码如下:
for(int i=-10;i<10;i++) { for(int j=-10;j<10;j++) { osg::MatrixTransform *transMT = new osg::MatrixTransform; transMT->addUpdateCallback(new TransCallback(i, j)); osg::MatrixTransform *rotMT = new osg::MatrixTransform; rotMT->addUpdateCallback(new RotCallback); osg::Geode *geode = new osg::Geode; osg::Geometry *geometry = new osg::Geometry; osg::Vec3Array *vertexArray = new osg::Vec3Array; osg::Vec3Array *colorArray = new osg::Vec3Array; colorArray->push_back(osg::Vec3(1, 0, 0)); vertexArray->push_back(osg::Vec3(i, j, 0.0)); colorArray->push_back(osg::Vec3(0, 1, 0)); vertexArray->push_back(osg::Vec3(i + 2.0f,j,0.0f)); colorArray->push_back(osg::Vec3(0,0,1)); vertexArray->push_back(osg::Vec3(i + 2.0f,j + 2.0f,0.0f)); colorArray->push_back(osg::Vec3(1,1,1)); vertexArray->push_back(osg::Vec3(i,j + 2.0f,0.0f)); geometry->setVertexArray(vertexArray); geometry->setColorArray(colorArray, osg::Array::BIND_PER_VERTEX); geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertexArray->size())); geode->addDrawable(geometry); transMT->addChild(rotMT); rotMT->addChild(geode); root->addChild(transMT); } }
traits->sampleBuffers = ds->getMultiSamples(); traits->samples = 4/*ds->getNumMultiSamples()*/;
class TransCallback : public osg::NodeCallback { public: TransCallback(float i, float j) : _i(i), _j(j){} virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(node); if(!mt) return; mt->setMatrix(osg::Matrix::translate(_i*2.0f,_j*2.0f,-5.0f)); traverse(node, nv); } float _i; float _j; };
osg::Multisample *ms = new osg::Multisample; ms->setHint(osg::Multisample::NICEST); root->getOrCreateStateSet()->setAttributeAndModes(ms, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Space) { if(!g_Root) return false; static bool flag = true; if (flag){ g_Root->getOrCreateStateSet()->setMode(GL_MULTISAMPLE_ARB, false); }else{ g_Root->getOrCreateStateSet()->setMode(GL_MULTISAMPLE_ARB, true); } flag = !flag; }
附:本课源码(源码中可能存在错误和不足之处,仅供参考)
#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/Multisample> osg::Group *g_Root = NULL; class ManipulatorSceneHandler : public osgGA::GUIEventHandler { public: ManipulatorSceneHandler() { } public: virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { osgViewer::Viewer *viewer = dynamic_cast<osgViewer::Viewer*>(&aa); if (!viewer) return false; if (!viewer->getSceneData()) return false; if (ea.getHandled()) return false; osg::Group *root = viewer->getSceneData()->asGroup(); switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN): { if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Space) { if(!g_Root) return false; static bool flag = true; if (flag){ g_Root->getOrCreateStateSet()->setMode(GL_MULTISAMPLE_ARB, false); }else{ g_Root->getOrCreateStateSet()->setMode(GL_MULTISAMPLE_ARB, true); } flag = !flag; } } break; default: break; } return false; } }; 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->addEventHandler(new ManipulatorSceneHandler); 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 = 4/*ds->getNumMultiSamples()*/; return new osgQt::GraphicsWindowQt(traits.get()); } virtual void paintEvent( QPaintEvent* event ) { frame(); } protected: QTimer _timer; }; class TransCallback : public osg::NodeCallback { public: TransCallback(float i, float j) : _i(i), _j(j){} virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(node); if(!mt) return; mt->setMatrix(osg::Matrix::translate(_i*2.0f,_j*2.0f,-5.0f)); traverse(node, nv); } float _i; float _j; }; class RotCallback : public osg::NodeCallback { public: virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { static float angle = 0.0; osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(node); if(!mt) return; mt->setMatrix(osg::Matrix::rotate(angle, osg::Z_AXIS)); angle += osg::DegreesToRadians(0.001f); traverse(node, nv); } }; osg::Node* buildScene() { osg::Group *root = new osg::Group; g_Root = root; osg::Multisample *ms = new osg::Multisample; ms->setHint(osg::Multisample::NICEST); root->getOrCreateStateSet()->setAttributeAndModes(ms, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); for(int i=-10;i<10;i++) { for(int j=-10;j<10;j++) { osg::MatrixTransform *transMT = new osg::MatrixTransform; transMT->addUpdateCallback(new TransCallback(i, j)); osg::MatrixTransform *rotMT = new osg::MatrixTransform; rotMT->addUpdateCallback(new RotCallback); osg::Geode *geode = new osg::Geode; osg::Geometry *geometry = new osg::Geometry; osg::Vec3Array *vertexArray = new osg::Vec3Array; osg::Vec3Array *colorArray = new osg::Vec3Array; colorArray->push_back(osg::Vec3(1, 0, 0)); vertexArray->push_back(osg::Vec3(i, j, 0.0)); colorArray->push_back(osg::Vec3(0, 1, 0)); vertexArray->push_back(osg::Vec3(i + 2.0f,j,0.0f)); colorArray->push_back(osg::Vec3(0,0,1)); vertexArray->push_back(osg::Vec3(i + 2.0f,j + 2.0f,0.0f)); colorArray->push_back(osg::Vec3(1,1,1)); vertexArray->push_back(osg::Vec3(i,j + 2.0f,0.0f)); geometry->setVertexArray(vertexArray); geometry->setColorArray(colorArray, osg::Array::BIND_PER_VERTEX); geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertexArray->size())); geode->addDrawable(geometry); transMT->addChild(rotMT); rotMT->addChild(geode); root->addChild(transMT); } } 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(); }