用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十课

52 篇文章 36 订阅
  • 简介

这节课讨论的是蒙板技术。所谓蒙板技术可能很多人在2D绘图程序中已经使用过了。例如,我们希望在背景图片上绘制一个人物(精灵)。因为人物的图片是矩形的,而人物本身又是不规则图形,所以矩形图片中会有一些空白的部分。如果我们不将这些空白的部分去掉,直接绘制人物图片的话,程序的效果肯定会很差。这时我们就需要使用蒙板技术了,首先要产生一个和人物图片一样的黑白掩码图片,然后先让这幅黑白掩码图片与背景图片进行异或操作,然后再将真正的人物图像与背景图片进行与操作。这样在背景图片上就会显示出一个“干净”的人物了。在3D程序中使用的蒙板技术和2D类似,主要是用在纹理映射上,其原理是相同的。

这节课中的蒙版的方式是采用OpenGL中的混合(Blend)的方法实现的,主要用到了osg中osg::BlendFunc这个类来实现,这节课相当于第八课混合的一种应用,需要理解OpenGL中混合的作用原理。

  • 实现

首先我们先创建背景,也就是一张一直在滚动的纹理图片,设置代码如下:

	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);
代码和之前课程的很多代码都相似,主要一个不同的地方是需要设置纹理的WRAP方式,我们让纹理在几何体上重复贴图。

纹理的坐标需要在程序运行中动态的变化以实现向上的滚动,这个实现是在TextureLogoCallback这个更新回调中进行的

class TextureLogoCallback : public osg::Drawable::UpdateCallback
{
public:
	void update(osg::NodeVisitor*, osg::Drawable* drawable)
	{
	   ......
	}
};
接着需要创建两个场景,当按下空格键的时候在二者之间切换。对于其中的任一场景,当按下M键的时候需要在打开和关闭Mask之间切换,为了做到这一效果,本课使用的是Switch节点的方式。Switch节点在 第十八课中也有应用,具体代码如下:

osg::Switch* createScene1()
{
   ......
}

osg::Group* createScene2()
{
	osg::Switch *toggleMask34 = new osg::Switch;
	toggleMask34->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
   ......
}
在创建场景的过程中,为了实现Mask的效果,最重要的部分是设置混合参数的地方。查看NeHeOpenGL中的设置方式,对于Mask纹理图片需要设置:

	//geometry3是贴有Mask的几何体
        geometry3->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture3);
	osg::BlendFunc *blendFunc3 = new osg::BlendFunc(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO);
	geometry3->getOrCreateStateSet()->setAttributeAndModes(blendFunc3);
对于需要绘制的几何体本身也要设置混合方式:

	//geometry4是需要绘制的几何体
        geometry4->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture4);
	osg::BlendFunc *blendFuc4 = new osg::BlendFunc(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
	geometry4->getOrCreateStateSet()->setAttributeAndModes(blendFuc4);
这样在OpenGL混合的作用之下,可以实现蒙版的效果。

最后在键盘交互中(自定义的EventHandler)实现Switch的切换:

		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();
						}
					}
				}
			}
编译运行程序:


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

#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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值