OpenSceneGraph实现的NeHe OpenGL教程 - 第二十课
来源:互联网 发布:unity3d 屏幕破碎特效 编辑:程序博客网 时间:2024/05/16 10:21
简介
这节课讨论的是蒙板技术。所谓蒙板技术可能很多人在2D绘图程序中已经使用过了。例如,我们希望在背景图片上绘制一个人物(精灵)。因为人物的图片是矩形的,而人物本身又是不规则图形,所以矩形图片中会有一些空白的部分。如果我们不将这些空白的部分去掉,直接绘制人物图片的话,程序的效果肯定会很差。这时我们就需要使用蒙板技术了,首先要产生一个和人物图片一样的黑白掩码图片,然后先让这幅黑白掩码图片与背景图片进行异或操作,然后再将真正的人物图像与背景图片进行与操作。这样在背景图片上就会显示出一个“干净”的人物了。在3D程序中使用的蒙板技术和2D类似,主要是用在纹理映射上,其原理是相同的。
这节课中的蒙版的方式是采用OpenGL中的混合(Blend)的方法实现的,主要用到了osg中osg::BlendFunc这个类来实现,这节课相当于第八课混合的一种应用,需要理解OpenGL中混合的作用原理。
实现
首先我们先创建背景,也就是一张一直在滚动的纹理图片,设置代码如下:
[cpp] view plain copy
- osg::Geometry *quadGeometry = new osg::Geometry;
- //顶点位置坐标
- osg::Vec3Array *quadVertexArray = new osg::Vec3Array;
- quadVertexArray->push_back(osg::Vec3(-1.1f, -1.1f, 0.0f));
- quadVertexArray->push_back(osg::Vec3(1.1f, -1.1f, 0.0f));
- quadVertexArray->push_back(osg::Vec3(1.1f,1.1f, 0.0f));
- quadVertexArray->push_back(osg::Vec3(-1.1f,1.1f, 0.0f));
- quadGeometry->setVertexArray(quadVertexArray);
- //顶点纹理坐标
- osg::Vec2Array *quadTextureArray = new osg::Vec2Array;
- quadTextureArray->push_back(osg::Vec2(0,0));
- quadTextureArray->push_back(osg::Vec2(3,0));
- quadTextureArray->push_back(osg::Vec2(3,3));
- quadTextureArray->push_back(osg::Vec2(0,3));
- //纹理贴图
- osg::Texture2D *quadTexture = new osg::Texture2D;
- quadTexture->setImage(osgDB::readImageFile("Data/Logo.bmp"));
- quadTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- quadTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- //设置WRAP方式是重复S和T方向
- quadTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
- quadTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
- quadGeometry->setTexCoordArray(0, quadTextureArray);
- quadGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
- quadGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, quadTexture);
- quadGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- quadGeometry->setUseDisplayList(false);
- //动态改变纹理坐标的回调
- quadGeometry->setUpdateCallback(new TextureLogoCallback);
纹理的坐标需要在程序运行中动态的变化以实现向上的滚动,这个实现是在TextureLogoCallback这个更新回调中进行的
[cpp] view plain copy
- class TextureLogoCallback : public osg::Drawable::UpdateCallback
- {
- public:
- void update(osg::NodeVisitor*, osg::Drawable* drawable)
- {
- ......
- }
- };
[cpp] view plain copy
- osg::Switch* createScene1()
- {
- ......
- }
- osg::Group* createScene2()
- {
- osg::Switch *toggleMask34 = new osg::Switch;
- toggleMask34->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
- ......
- }
[cpp] view plain copy
- //geometry3是贴有Mask的几何体
- geometry3->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture3);
- osg::BlendFunc *blendFunc3 = new osg::BlendFunc(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO);
- geometry3->getOrCreateStateSet()->setAttributeAndModes(blendFunc3);
[cpp] view plain copy
- //geometry4是需要绘制的几何体
- geometry4->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture4);
- osg::BlendFunc *blendFuc4 = new osg::BlendFunc(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
- geometry4->getOrCreateStateSet()->setAttributeAndModes(blendFuc4);
最后在键盘交互中(自定义的EventHandler)实现Switch的切换:
[cpp] view plain copy
- case(osgGA::GUIEventAdapter::KEYDOWN):
- {
- static int index = 1;
- if (index > 1)
- {
- index = 0;
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Space)
- {
- g_scene->setSingleChildOn(index);
- ++index;
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_M)
- {
- if (index == 0) //第二个场景
- {
- if (g_scene2->getValue(0) == true) { //Mask启用
- g_scene2->setSingleChildOn(1);
- }else{ //Mask未启用
- g_scene2->setAllChildrenOn();
- }
- }
- else //第一个场景
- {
- if (g_scene1->getValue(0) == true) { //Mask启用
- g_scene1->setSingleChildOn(1);
- }else{ //Mask未启用
- g_scene1->setAllChildrenOn();
- }
- }
- }
- }
附:本课源码(源码中可能存在错误和不足,仅供参考)
[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/Texture2D>
- #include <osg/Switch>
- #include <osg/BlendFunc>
- #include <osg/AnimationPath>
- osg::Switch *g_scene, *g_scene1, *g_scene2;
- class SceneEventHandler : public osgGA::GUIEventHandler
- {
- public:
- SceneEventHandler(){}
- 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;
- switch(ea.getEventType())
- {
- case(osgGA::GUIEventAdapter::KEYDOWN):
- {
- static int index = 1;
- if (index > 1)
- {
- index = 0;
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Space)
- {
- g_scene->setSingleChildOn(index);
- ++index;
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_M)
- {
- if (index == 0) //第二个场景
- {
- if (g_scene2->getValue(0) == true) { //Mask启用
- g_scene2->setSingleChildOn(1);
- }else{ //Mask未启用
- g_scene2->setAllChildrenOn();
- }
- }
- else //第一个场景
- {
- if (g_scene1->getValue(0) == true) { //Mask启用
- g_scene1->setSingleChildOn(1);
- }else{ //Mask未启用
- g_scene1->setAllChildrenOn();
- }
- }
- }
- }
- 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, 0.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));
- addEventHandler(new SceneEventHandler);
- 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;
- };
- //纹理坐标更新
- class TextureLogoCallback : public osg::Drawable::UpdateCallback
- {
- public:
- void update(osg::NodeVisitor*, osg::Drawable* drawable)
- {
- osg::Geometry *geometry = dynamic_cast<osg::Geometry*>(drawable);
- if (!geometry)
- {
- return;
- }
- osg::Vec2Array *textureArray = dynamic_cast<osg::Vec2Array *>(geometry->getTexCoordArray(0));
- if (!textureArray)
- {
- return;
- }
- static float roll = 0;
- roll += 0.002f;
- if (roll > 1.0f)
- roll -= 1.0f;
- textureArray->at(0).set(0,-roll + 0);
- textureArray->at(1).set(3,-roll + 0);
- textureArray->at(2).set(3,-roll + 3);
- textureArray->at(3).set(0,-roll + 3);
- textureArray->dirty();
- }
- };
- class TextureImageCallback : public osg::Drawable::UpdateCallback
- {
- public:
- void update(osg::NodeVisitor*, osg::Drawable* drawable)
- {
- osg::Geometry *geometry = dynamic_cast<osg::Geometry*>(drawable);
- if (!geometry)
- {
- return;
- }
- osg::Vec2Array *textureArray = dynamic_cast<osg::Vec2Array *>(geometry->getTexCoordArray(0));
- if (!textureArray)
- {
- return;
- }
- static float rolling = 0.0;
- rolling += 0.002f;
- if (rolling > 1.0f)
- rolling -= 1.0f;
- textureArray->at(0).set(-rolling + 0, 0);
- textureArray->at(1).set(rolling + 4, 0);
- textureArray->at(2).set(rolling + 4, 4);
- textureArray->at(3).set(rolling + 0, 4);
- textureArray->dirty();
- }
- };
- osg::Switch* createScene1()
- {
- osg::Switch *toggleMask12 = new osg::Switch;
- toggleMask12->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
- //叶节点1
- osg::Geode *geode1 = new osg::Geode;
- osg::Geometry *geometry1 = new osg::Geometry;
- osg::Vec3Array *vertexArray1 = new osg::Vec3Array;
- vertexArray1->push_back(osg::Vec3(-1.1f, -1.1f, 0.0f));
- vertexArray1->push_back(osg::Vec3(1.1f, -1.1f, 0.0f));
- vertexArray1->push_back(osg::Vec3(1.1f,1.1f, 0.0f));
- vertexArray1->push_back(osg::Vec3(-1.1f,1.1f, 0.0f));
- geometry1->setVertexArray(vertexArray1);
- osg::Vec2Array *textureArray1 = new osg::Vec2Array;
- textureArray1->push_back(osg::Vec2(0,0));
- textureArray1->push_back(osg::Vec2(4,0));
- textureArray1->push_back(osg::Vec2(4,4));
- textureArray1->push_back(osg::Vec2(0,4));
- osg::Texture2D *texture1 = new osg::Texture2D;
- texture1->setImage(osgDB::readImageFile("Data/Mask1.bmp"));
- texture1->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- texture1->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- texture1->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
- texture1->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
- geometry1->setTexCoordArray(0, textureArray1);
- geometry1->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
- geometry1->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture1);
- geometry1->setUseDisplayList(false);
- osg::BlendFunc *blendFunc1 = new osg::BlendFunc(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO);
- geometry1->getOrCreateStateSet()->setAttributeAndModes(blendFunc1);
- geometry1->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- geometry1->setUpdateCallback(new TextureImageCallback);
- geode1->addDrawable(geometry1);
- //叶节点2
- osg::Geode *geode2 = new osg::Geode;
- osg::Geometry *geometry2 = new osg::Geometry;
- osg::Vec3Array *vertexArray2 = new osg::Vec3Array;
- vertexArray2->push_back(osg::Vec3(-1.1f, -1.1f, 0.0f));
- vertexArray2->push_back(osg::Vec3(1.1f, -1.1f, 0.0f));
- vertexArray2->push_back(osg::Vec3(1.1f,1.1f, 0.0f));
- vertexArray2->push_back(osg::Vec3(-1.1f,1.1f, 0.0f));
- geometry2->setVertexArray(vertexArray2);
- osg::Vec2Array *textureArray2 = new osg::Vec2Array;
- textureArray2->push_back(osg::Vec2(0,0));
- textureArray2->push_back(osg::Vec2(4,0));
- textureArray2->push_back(osg::Vec2(4,4));
- textureArray2->push_back(osg::Vec2(0,4));
- osg::Texture2D *texture2 = new osg::Texture2D;
- texture2->setImage(osgDB::readImageFile("Data/Image1.bmp"));
- texture2->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- texture2->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- texture2->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
- texture2->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
- geometry2->setTexCoordArray(0, textureArray2);
- geometry2->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
- geometry2->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2);
- osg::BlendFunc *blendFuc2 = new osg::BlendFunc(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
- geometry2->getOrCreateStateSet()->setAttributeAndModes(blendFuc2);
- geometry2->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- geometry2->setUseDisplayList(false);
- geometry2->setUpdateCallback(new TextureImageCallback);
- geode2->addDrawable(geometry2);
- toggleMask12->addChild(geode1);
- toggleMask12->addChild(geode2);
- toggleMask12->setAllChildrenOn();
- g_scene1 = toggleMask12;
- return toggleMask12;
- }
- osg::Group* createScene2()
- {
- osg::Switch *toggleMask34 = new osg::Switch;
- toggleMask34->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
- osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
- zoomMT->setMatrix(osg::Matrix::translate(0, 0, -0.9));
- osg::MatrixTransform *rotateMT = new osg::MatrixTransform;
- rotateMT->setMatrix(osg::Matrix::rotate(0, osg::Z_AXIS));
- rotateMT->addUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(), osg::Z_AXIS, 1.5));
- //叶节点3
- osg::Geode *geode3 = new osg::Geode;
- osg::Geometry *geometry3 = new osg::Geometry;
- osg::Vec3Array *vertexArray3 = new osg::Vec3Array;
- vertexArray3->push_back(osg::Vec3(-1.1f, -1.1f, 0.0f));
- vertexArray3->push_back(osg::Vec3(1.1f, -1.1f, 0.0f));
- vertexArray3->push_back(osg::Vec3(1.1f,1.1f, 0.0f));
- vertexArray3->push_back(osg::Vec3(-1.1f,1.1f, 0.0f));
- geometry3->setVertexArray(vertexArray3);
- osg::Vec2Array *textureArray3 = new osg::Vec2Array;
- textureArray3->push_back(osg::Vec2(0,0));
- textureArray3->push_back(osg::Vec2(1,0));
- textureArray3->push_back(osg::Vec2(1,1));
- textureArray3->push_back(osg::Vec2(0,1));
- osg::Texture2D *texture3 = new osg::Texture2D;
- texture3->setImage(osgDB::readImageFile("Data/Mask2.bmp"));
- texture3->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- texture3->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- geometry3->setTexCoordArray(0, textureArray3);
- geometry3->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
- geometry3->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture3);
- osg::BlendFunc *blendFunc3 = new osg::BlendFunc(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO);
- geometry3->getOrCreateStateSet()->setAttributeAndModes(blendFunc3);
- geometry3->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- geode3->addDrawable(geometry3);
- //叶节点4
- osg::Geode *geode4 = new osg::Geode;
- osg::Geometry *geometry4 = new osg::Geometry;
- osg::Vec3Array *vertexArray4 = new osg::Vec3Array;
- vertexArray4->push_back(osg::Vec3(-1.1f, -1.1f, 0.0f));
- vertexArray4->push_back(osg::Vec3(1.1f, -1.1f, 0.0f));
- vertexArray4->push_back(osg::Vec3(1.1f,1.1f, 0.0f));
- vertexArray4->push_back(osg::Vec3(-1.1f,1.1f, 0.0f));
- geometry4->setVertexArray(vertexArray4);
- osg::Vec2Array *textureArray4 = new osg::Vec2Array;
- textureArray4->push_back(osg::Vec2(0,0));
- textureArray4->push_back(osg::Vec2(1,0));
- textureArray4->push_back(osg::Vec2(1,1));
- textureArray4->push_back(osg::Vec2(0,1));
- osg::Texture2D *texture4 = new osg::Texture2D;
- texture4->setImage(osgDB::readImageFile("Data/Image2.bmp"));
- texture4->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- texture4->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- geometry4->setTexCoordArray(0, textureArray4);
- geometry4->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
- geometry4->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture4);
- osg::BlendFunc *blendFuc4 = new osg::BlendFunc(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
- geometry4->getOrCreateStateSet()->setAttributeAndModes(blendFuc4);
- geometry4->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- geode4->addDrawable(geometry4);
- zoomMT->addChild(rotateMT);
- rotateMT->addChild(toggleMask34);
- toggleMask34->addChild(geode3);
- toggleMask34->addChild(geode4);
- toggleMask34->setAllChildrenOn();
- g_scene2 = toggleMask34;
- return zoomMT;
- }
- osg::Node* buildScene()
- {
- osg::Group *root = new osg::Group;
- osg::MatrixTransform *quadMT = new osg::MatrixTransform;
- quadMT->setMatrix(osg::Matrix::translate(0.0, 0.0, -1.0));
- osg::Geometry *quadGeometry = new osg::Geometry;
- //顶点位置坐标
- osg::Vec3Array *quadVertexArray = new osg::Vec3Array;
- quadVertexArray->push_back(osg::Vec3(-1.1f, -1.1f, 0.0f));
- quadVertexArray->push_back(osg::Vec3(1.1f, -1.1f, 0.0f));
- quadVertexArray->push_back(osg::Vec3(1.1f,1.1f, 0.0f));
- quadVertexArray->push_back(osg::Vec3(-1.1f,1.1f, 0.0f));
- quadGeometry->setVertexArray(quadVertexArray);
- //顶点纹理坐标
- osg::Vec2Array *quadTextureArray = new osg::Vec2Array;
- quadTextureArray->push_back(osg::Vec2(0,0));
- quadTextureArray->push_back(osg::Vec2(3,0));
- quadTextureArray->push_back(osg::Vec2(3,3));
- quadTextureArray->push_back(osg::Vec2(0,3));
- //纹理贴图
- osg::Texture2D *quadTexture = new osg::Texture2D;
- quadTexture->setImage(osgDB::readImageFile("Data/Logo.bmp"));
- quadTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- quadTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- //设置WRAP方式是重复S和T方向
- quadTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
- quadTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
- quadGeometry->setTexCoordArray(0, quadTextureArray);
- quadGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
- quadGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, quadTexture);
- quadGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- quadGeometry->setUseDisplayList(false);
- //动态改变纹理坐标的回调
- quadGeometry->setUpdateCallback(new TextureLogoCallback);
- osg::Geode *quadGeode = new osg::Geode;
- quadGeode->addDrawable(quadGeometry);
- quadMT->addChild(quadGeode);
- osg::Switch *toggleScene = new osg::Switch;
- toggleScene->addChild(createScene1());
- toggleScene->addChild(createScene2());
- toggleScene->setSingleChildOn(0);
- g_scene = toggleScene;
- root->addChild(quadMT);
- root->addChild(toggleScene);
- 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();
- }
0 0
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第一课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第三课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第四课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第五课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第六课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第七课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第八课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第九课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十一课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十二课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十三课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十四课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十五课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十六课
- mybatis入门基础(四)----输入映射和输出映射
- IT--linux--进程--后台
- Android图片框架Picasso LRU缓存详解
- 利用CSOM向列表添加文件夹
- 向大神之路前进
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十课
- Spotify的大规模敏捷之路——使用一种新型的矩阵组织:部落、分队、分会和协会
- JVM的Server与Client运行模式区别与切换
- HDU 1498 50 years, 50 colors (二分图)
- Dungeon Master(BFS)
- 10步让你成为更优秀的程序员
- nginx 如何使用rewrite
- 1007 正整数分组
- C++类型转换之static_cast和dynamic_cast