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

  • 简介

这节课NeHe教我们怎么在场景中实现3D光晕的效果,光晕会在摄像机镜头对准太阳的时候就会出现,实现的原理是在光源与摄像机视点之间绘制一系列贴好纹理的四边形,并且让这些四边形正对着视点(Billboard)

  • 实现

在OSG中的实现与OpenGL中有一些不同,在OpenGL中很容易得到屏幕上某一点的深度值从而判断遮挡,在OSG中需要在获取到OpenGL RC的时候才能获取屏幕中像素的深度值,需要在相机里面进行操作。我尝试使用一个PRE_RENDER的相机先绘制其他模型,判断遮挡然后再根据是否遮挡绘制光源节点,在运行的时候发现需要拖动窗口才能得到正确的效果,目前尚未找到原因,希望知道的读者指点一下。有鉴于此,在计算遮挡的时候我使用了OSG中线求交器,通过判断从试点到光源连线是否与场景中模型相交来判断遮挡。

判断遮挡的代码如下:

		osg::Vec3 eyePos = camera->getInverseViewMatrix().getTrans();
		
		osgUtil::LineSegmentIntersector *intersector = new osgUtil::LineSegmentIntersector(eyePos, g_LightPosition);
		osgUtil::IntersectionVisitor intersectVisitor(intersector);
		g_Root->accept(intersectVisitor);

		if(intersector->containsIntersections())

我们需要绘制一系列的模拟光晕的四边形:

osg::Node*    createBigGlow(const osg::Vec4& color, osg::Vec3 p, float scale)
osg::Node*    createGlow(const osg::Vec4& color, osg::Vec3 p, float scale)
osg::Node*    createStreaks(const osg::Vec4& color, osg::Vec3 p, float scale)
osg::Node*    createHalo(const osg::Vec4& color, osg::Vec3 p, float scale)

由于需要得到视点位置等一些与相机有关的参数,因此将添加光晕的节点放在了相机的PreDrawCallback中,同时在Switch节点中判断当前光源是否被圆柱体遮挡:


	virtual void  operator() (const osg::Camera &camera) const  
	{
		if(_isAdded)
			return;
		_isAdded = true;

		g_SwitchNode = new osg::Switch;
		g_SwitchNode->setUpdateCallback(new SwitchNodeCallback);

		osg::Vec3 eyePos = camera.getInverseViewMatrix().getTrans();

		GLfloat Length = 0.0f;
		osg::Vec3 vLightSourceToCamera = eyePos - g_LightPosition;
		Length = vLightSourceToCamera.length();
		osg::Matrix viewMatrix = camera.getViewMatrix();
		osg::Vec3 diretion = osg::Vec3(viewMatrix(2, 0), viewMatrix(2,1), -viewMatrix(2,2));
		osg::Vec3 ptIntersect = diretion * Length;				
		ptIntersect += eyePos;
		osg::Vec3 vLightSourceToIntersect = ptIntersect - g_LightPosition;	
		Length = vLightSourceToIntersect.length();
		vLightSourceToIntersect.normalize();

		osg::Group *renderGroup = new osg::Group;
		osg::Vec3 pt;
......
}

绘制光晕的位置与NeHe课程中一样。

此外在本课中与NeHe课程不同的另一个地方是:NeHe中使用的二次曲面生成的圆柱体上下地面是不存在的,但是在OSG中的Cylinder却包含上下地面,因此为了让光源可以出现,对圆柱体的位置和旋转方式进行了一些修改:

	osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
	zoomMT->setMatrix(osg::Matrix::translate(0, 0, -20));

	osg::MatrixTransform *rotXMT = new osg::MatrixTransform;
	osg::MatrixTransform *rotYMT = new osg::MatrixTransform;
	rotYMT->addUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(3, 0, 0), osg::Y_AXIS, 0.3));
	zoomMT->addChild(rotXMT);
	rotXMT->addChild(rotYMT);
	rotYMT->addChild(createCylinderNode());

此外在OSG中相机操作和OpenGL不太相同,因此交互部分的代码尚未实现,希望读者可以进一步完善。

编译运行程序:

用OpenSceneGraph实现的NeHe OpenGL教程 - 第四十四课_第1张图片

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

#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 <osg/AnimationPath>
#include <osg/Viewport>
#include <osg/BlendFunc>
#include <osg/Texture2D>

#include <osgUtil/IntersectVisitor>


osg::Vec3		g_LightPosition;
osgViewer::Viewer	    *g_View = NULL;

bool isLightPositionOccluder;

osg::Group *g_Root;
osg::Switch *g_SwitchNode;

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
osg::Node*	createBigGlow(const osg::Vec4& color, osg::Vec3 p, float scale)
{
	osg::Vec3 q[4];

	q[0].x() = (p.x() - scale);										
	q[0].y() = (p.y() - scale);

	q[1].x() = (p.x() - scale);
	q[1].y() = (p.y() + scale);

	q[2].x() = (p.x() + scale);
	q[2].y() = (p.y() - scale);

	q[3].x() = (p.x() + scale);
	q[3].y() = (p.y() + scale);

	osg::MatrixTransform *posMT = new osg::MatrixTransform;
	posMT->setMatrix(osg::Matrix::translate(p));

	osg::MatrixTransform *rotMT = new osg::MatrixTransform;
	
	osg::Geode *geode = new osg::Geode;
	osg::Geometry *geometry = new osg::Geometry;
	osg::Vec2Array *texArray = new osg::Vec2Array;
	osg::Vec2Array *vertexArray = new osg::Vec2Array;
	osg::Vec4Array *colorArray = new osg::Vec4Array;

	colorArray->push_back(color);

	vertexArray->push_back(osg::Vec2(q[0].x(), q[0].y()));
	vertexArray->push_back(osg::Vec2(q[1].x(), q[1].y()));
	vertexArray->push_back(osg::Vec2(q[2].x(), q[2].y()));
	vertexArray->push_back(osg::Vec2(q[3].x(), q[3].y()));

	texArray->push_back(osg::Vec2(0.0f, 0.0f));
	texArray->push_back(osg::Vec2(0.0f, 1.0f));
	texArray->push_back(osg::Vec2(1.0f, 0.0f));
	texArray->push_back(osg::Vec2(1.0f, 1.0f));

	geometry->setVertexArray(vertexArray);
	geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	geometry->setTexCoordArray(0, texArray, osg::Array::BIND_PER_VERTEX);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
	geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, false);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));
	
	osg::Texture2D *texture2D = new osg::Texture2D;
	texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
	texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
	texture2D->setImage(osgDB::readImageFile("Data/BigGlow3.bmp"));
	
	osg::BlendFunc *blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE);

	geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D);
	geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);
	geode->addDrawable(geometry);

	posMT->addChild(rotMT);
	rotMT->addChild(geode);

	return posMT;
}


osg::Node*	createGlow(const osg::Vec4& color, osg::Vec3 p, float scale)
{
	osg::Vec3 q[4];

	q[0].x() = (p.x() - scale);										
	q[0].y() = (p.y() - scale);

	q[1].x() = (p.x() - scale);
	q[1].y() = (p.y() + scale);

	q[2].x() = (p.x() + scale);
	q[2].y() = (p.y() - scale);

	q[3].x() = (p.x() + scale);
	q[3].y() = (p.y() + scale);

	osg::MatrixTransform *posMT = new osg::MatrixTransform;
	posMT->setMatrix(osg::Matrix::translate(p));

	osg::MatrixTransform *rotMT = new osg::MatrixTransform;

	osg::Geode *geode = new osg::Geode;
	osg::Geometry *geometry = new osg::Geometry;
	osg::Vec2Array *texArray = new osg::Vec2Array;
	osg::Vec2Array *vertexArray = new osg::Vec2Array;
	osg::Vec4Array *colorArray = new osg::Vec4Array;

	colorArray->push_back(color);

	vertexArray->push_back(osg::Vec2(q[0].x(), q[0].y()));
	vertexArray->push_back(osg::Vec2(q[1].x(), q[1].y()));
	vertexArray->push_back(osg::Vec2(q[2].x(), q[2].y()));
	vertexArray->push_back(osg::Vec2(q[3].x(), q[3].y()));

	texArray->push_back(osg::Vec2(0.0f, 0.0f));
	texArray->push_back(osg::Vec2(0.0f, 1.0f));
	texArray->push_back(osg::Vec2(1.0f, 0.0f));
	texArray->push_back(osg::Vec2(1.0f, 1.0f));

	geometry->setVertexArray(vertexArray);
	geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	geometry->setTexCoordArray(0, texArray, osg::Array::BIND_PER_VERTEX);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
	geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, false);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));

	osg::Texture2D *texture2D = new osg::Texture2D;
	texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
	texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
	texture2D->setImage(osgDB::readImageFile("Data/HardGlow2.bmp"));

	osg::BlendFunc *blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE);

	geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D);
	geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);
	geode->addDrawable(geometry);

	posMT->addChild(rotMT);
	rotMT->addChild(geode);

	return posMT;
}


osg::Node*	createStreaks(const osg::Vec4& color, osg::Vec3 p, float scale)
{
	osg::Vec3 q[4];

	q[0].x() = (p.x() - scale);										
	q[0].y() = (p.y() - scale);

	q[1].x() = (p.x() - scale);
	q[1].y() = (p.y() + scale);

	q[2].x() = (p.x() + scale);
	q[2].y() = (p.y() - scale);

	q[3].x() = (p.x() + scale);
	q[3].y() = (p.y() + scale);

	osg::MatrixTransform *posMT = new osg::MatrixTransform;
	posMT->setMatrix(osg::Matrix::translate(p));

	osg::MatrixTransform *rotMT = new osg::MatrixTransform;

	osg::Geode *geode = new osg::Geode;
	osg::Geometry *geometry = new osg::Geometry;
	osg::Vec2Array *texArray = new osg::Vec2Array;
	osg::Vec2Array *vertexArray = new osg::Vec2Array;
	osg::Vec4Array *colorArray = new osg::Vec4Array;

	colorArray->push_back(color);

	vertexArray->push_back(osg::Vec2(q[0].x(), q[0].y()));
	vertexArray->push_back(osg::Vec2(q[1].x(), q[1].y()));
	vertexArray->push_back(osg::Vec2(q[2].x(), q[2].y()));
	vertexArray->push_back(osg::Vec2(q[3].x(), q[3].y()));

	texArray->push_back(osg::Vec2(0.0f, 0.0f));
	texArray->push_back(osg::Vec2(0.0f, 1.0f));
	texArray->push_back(osg::Vec2(1.0f, 0.0f));
	texArray->push_back(osg::Vec2(1.0f, 1.0f));

	geometry->setVertexArray(vertexArray);
	geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	geometry->setTexCoordArray(0, texArray, osg::Array::BIND_PER_VERTEX);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
	geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, false);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));

	osg::Texture2D *texture2D = new osg::Texture2D;
	texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
	texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
	texture2D->setImage(osgDB::readImageFile("Data/Streaks4.bmp"));

	osg::BlendFunc *blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE);

	geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D);
	geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);
	geode->addDrawable(geometry);

	posMT->addChild(rotMT);
	rotMT->addChild(geode);

	return posMT;
}


osg::Node*	createHalo(const osg::Vec4& color, osg::Vec3 p, float scale)
{
	osg::Vec3 q[4];

	q[0].x() = (p.x() - scale);										
	q[0].y() = (p.y() - scale);

	q[1].x() = (p.x() - scale);
	q[1].y() = (p.y() + scale);

	q[2].x() = (p.x() + scale);
	q[2].y() = (p.y() - scale);

	q[3].x() = (p.x() + scale);
	q[3].y() = (p.y() + scale);

	osg::MatrixTransform *posMT = new osg::MatrixTransform;
	posMT->setMatrix(osg::Matrix::translate(p));

	osg::MatrixTransform *rotMT = new osg::MatrixTransform;

	osg::Geode *geode = new osg::Geode;
	osg::Geometry *geometry = new osg::Geometry;
	osg::Vec2Array *texArray = new osg::Vec2Array;
	osg::Vec2Array *vertexArray = new osg::Vec2Array;
	osg::Vec4Array *colorArray = new osg::Vec4Array;

	colorArray->push_back(color);

	vertexArray->push_back(osg::Vec2(q[0].x(), q[0].y()));
	vertexArray->push_back(osg::Vec2(q[1].x(), q[1].y()));
	vertexArray->push_back(osg::Vec2(q[2].x(), q[2].y()));
	vertexArray->push_back(osg::Vec2(q[3].x(), q[3].y()));

	texArray->push_back(osg::Vec2(0.0f, 0.0f));
	texArray->push_back(osg::Vec2(0.0f, 1.0f));
	texArray->push_back(osg::Vec2(1.0f, 0.0f));
	texArray->push_back(osg::Vec2(1.0f, 1.0f));

	geometry->setVertexArray(vertexArray);
	geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	geometry->setTexCoordArray(0, texArray, osg::Array::BIND_PER_VERTEX);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
	geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, false);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));

	osg::Texture2D *texture2D = new osg::Texture2D;
	texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
	texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
	texture2D->setImage(osgDB::readImageFile("Data/Halo3.bmp"));

	osg::BlendFunc *blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE);

	geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D);
	geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);
	geode->addDrawable(geometry);

	posMT->addChild(rotMT);
	rotMT->addChild(geode);

	return posMT;
}

//////////////////////////////////////////////////////////////////////////
//想法一中的判断遮挡方式:原理与NeHe课程中的一样
//
//class TestOccludeCallback : public osg::Camera::DrawCallback
//{
//public:
//	virtual void  operator() (const osg::Camera &camera) const  
//	{
//		osg::Matrix viewMatrix = camera.getViewMatrix();
//		osg::Matrix proMatrix = camera.getProjectionMatrix();
//		osg::Matrix vpMatrix = camera.getViewport()->computeWindowMatrix();
//
//		osg::Vec3 winPos = g_LightPosition * viewMatrix * proMatrix * vpMatrix;
//
//		double flareZ = winPos.z();
//
//		osg::Image *image = new osg::Image;
//		image->readPixels(winPos.x(), winPos.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT);
//		float *bufferZ = reinterpret_cast<float*>(image->data());
//
//		if (*bufferZ < flareZ)
//			isLightPositionOccluder = true;
//		else
//			isLightPositionOccluder = false;
//	}
//};


osg::Node*	createCylinderNode()
{
	osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
	zoomMT->setMatrix(osg::Matrix::translate(0, 0, -2));

	osg::Geode *cylinder = new osg::Geode;
	osg::ShapeDrawable *cylinderDrawable = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0,0,0), 0.5, 4.0));
	cylinderDrawable->setColor(osg::Vec4(0,0,1,1));
	cylinder->addDrawable(cylinderDrawable);
	
	zoomMT->addChild(cylinder);

	return zoomMT;
}

//想法一:在绘制场景之前,先使用PRE_RENDER的方式
//绘制圆柱体,同时进行遮挡判断
//TODO:需要调整窗口位置才能正确显示,目前未找到原因???
//osg::Camera*	createRenderToTextureCamera(int w, int h)
//{
//	osg::Camera *rtt = new osg::Camera;
//	rtt->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f, 0.5));	
//	rtt->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//	rtt->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
//	rtt->setViewport(0, 0, w, h);
//	rtt->setRenderOrder(osg::Camera::PRE_RENDER);
//	rtt->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
//	rtt->setProjectionMatrixAsPerspective(45.0f, static_cast<double>(640)/static_cast<double>(480), 1.0f, 1000.0f );
//	rtt->setViewMatrixAsLookAt(osg::Vec3d(0, 0, 0), osg::Vec3d(0, 0, -1), osg::Vec3d(0, 1, 0));
//
//	osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
//	zoomMT->setMatrix(osg::Matrix::translate(0, 0, -20));
//
//	osg::MatrixTransform *rotXMT = new osg::MatrixTransform;
//	osg::MatrixTransform *rotYMT = new osg::MatrixTransform;
//	rotYMT->addUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(3, 0, 0), osg::Y_AXIS, 0.3));
//
//	zoomMT->addChild(rotXMT);
//	rotXMT->addChild(rotYMT);
//	rotYMT->addChild(createCylinderNode());
//
//	rtt->addChild(zoomMT);
//
//	rtt->setPostDrawCallback(new TestOccludeCallback);
//
//	return rtt;
//}


class SwitchNodeCallback : public osg::NodeCallback
{
public:
	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
	{
		osg::Switch *s = dynamic_cast<osg::Switch*>(node);
		if (!s)
			return;
		if(!g_View)
			return;
		osg::Camera *camera = g_View->getCamera();
		if(!camera)
			return;

		osg::Vec3 eyePos = camera->getInverseViewMatrix().getTrans();
		
		osgUtil::LineSegmentIntersector *intersector = new osgUtil::LineSegmentIntersector(eyePos, g_LightPosition);
		osgUtil::IntersectionVisitor intersectVisitor(intersector);
		g_Root->accept(intersectVisitor);

		if(intersector->containsIntersections())
			g_SwitchNode->setAllChildrenOff();
		else
			g_SwitchNode->setAllChildrenOn();
	}
};


class LensFlareCallback : public osg::Camera::DrawCallback
{
public:
	LensFlareCallback() : _isAdded(false){}

	virtual void  operator() (const osg::Camera &camera) const  
	{
		if(_isAdded)
			return;
		_isAdded = true;

		g_SwitchNode = new osg::Switch;
		g_SwitchNode->setUpdateCallback(new SwitchNodeCallback);

		osg::Vec3 eyePos = camera.getInverseViewMatrix().getTrans();

		GLfloat Length = 0.0f;
		osg::Vec3 vLightSourceToCamera = eyePos - g_LightPosition;
		Length = vLightSourceToCamera.length();
		osg::Matrix viewMatrix = camera.getViewMatrix();
		osg::Vec3 diretion = osg::Vec3(viewMatrix(2, 0), viewMatrix(2,1), -viewMatrix(2,2));
		osg::Vec3 ptIntersect = diretion * Length;				
		ptIntersect += eyePos;
		osg::Vec3 vLightSourceToIntersect = ptIntersect - g_LightPosition;	
		Length = vLightSourceToIntersect.length();
		vLightSourceToIntersect.normalize();

		osg::Group *renderGroup = new osg::Group;
		osg::Vec3 pt;

		renderGroup->addChild(createBigGlow(osg::Vec4(0.60f, 0.60f, 0.8f, 1.0f), g_LightPosition, 16.0f));
		renderGroup->addChild(createStreaks(osg::Vec4(0.60f, 0.60f, 0.8f, 1.0f), g_LightPosition, 16.0f));
		renderGroup->addChild(createGlow(osg::Vec4(0.8f, 0.8f, 1.0f, 0.5f), g_LightPosition, 3.5f));

		pt = vLightSourceToIntersect * (Length * 0.1f);				// Lets compute a point that is 20%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createGlow(osg::Vec4(0.9f, 0.6f, 0.4f, 0.5f), pt, 0.6f));

		pt = vLightSourceToIntersect * (Length * 0.15f);			// Lets compute a point that is 30%
		pt += g_LightPosition;										// away from the light source in the	
		renderGroup->addChild(createHalo(osg::Vec4(0.8f, 0.5f, 0.6f, 0.5f), pt, 1.7f));

		pt = vLightSourceToIntersect * (Length * 0.175f);			// Lets compute a point that is 35%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createHalo(osg::Vec4(0.9f, 0.2f, 0.1f, 0.5f), pt, 0.83f));

		pt = vLightSourceToIntersect * (Length * 0.285f);			// Lets compute a point that is 57%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createHalo(osg::Vec4(0.7f, 0.7f, 0.4f, 0.5f), pt, 1.6f));

		pt = vLightSourceToIntersect * (Length * 0.2755f);			// Lets compute a point that is 55.1%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createGlow(osg::Vec4(0.9f, 0.9f, 0.2f, 0.5f), pt, 0.8f));

		pt = vLightSourceToIntersect * (Length * 0.4775f);			// Lets compute a point that is 95.5%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createGlow(osg::Vec4(0.93f, 0.82f, 0.73f, 0.5f), pt, 1.0f));

		pt = vLightSourceToIntersect * (Length * 0.49f);			// Lets compute a point that is 98%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createHalo(osg::Vec4(0.7f, 0.6f, 0.5f, 0.5f), pt, 1.4f));

		pt = vLightSourceToIntersect * (Length * 0.65f);			// Lets compute a point that is 130%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createGlow(osg::Vec4(0.7f, 0.8f, 0.3f, 0.5f), pt, 1.8f));


		pt = vLightSourceToIntersect * (Length * 0.63f);			// Lets compute a point that is 126%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createGlow(osg::Vec4(0.4f, 0.3f, 0.2f, 0.5f), pt, 1.4f));


		pt = vLightSourceToIntersect * (Length * 0.8f);				// Lets compute a point that is 160%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createHalo(osg::Vec4(0.7f, 0.5f, 0.5f, 0.5f), pt, 1.4f));


		pt = vLightSourceToIntersect * (Length * 0.7825f);			// Lets compute a point that is 156.5%
		pt += g_LightPosition;										// away from the light source in the
		renderGroup->addChild(createGlow(osg::Vec4(0.8f, 0.5f, 0.1f, 0.5f), pt, 0.6f));


		pt = vLightSourceToIntersect * (Length * 1.0f);
		pt += g_LightPosition;	
		renderGroup->addChild(createHalo(osg::Vec4(0.5f, 0.5f, 0.7f, 0.5f), pt, 1.7f));


		pt = vLightSourceToIntersect * (Length * 0.975f);
		pt += g_LightPosition;	
		renderGroup->addChild(createGlow(osg::Vec4(0.4f, 0.1f, 0.9f, 0.5f), pt, 2.0f));

		g_SwitchNode->addChild(renderGroup);

		g_Root->addChild(g_SwitchNode);
	}

	mutable bool _isAdded;
};


//////////////////////////////////////////////////////////////////////////
class ManipulatorSceneHandler : public osgGA::GUIEventHandler
{
public:
	ManipulatorSceneHandler()
	{
	}

public:
	virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
	{
		osgViewer::View *viewer = dynamic_cast<osgViewer::View*>(&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::FRAME):
			{
				osg::Vec3 eye, center, up;
				viewer->getCamera()->getViewMatrixAsLookAt(eye, center, up);
				g_LightPosition.z() = eye.z() - 50.0f;
			}	
			break;
		case(osgGA::GUIEventAdapter::KEYDOWN):
			{	
				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_W)
				{
					//TODO:OSG中相机的变换和OpenGL中不一致
				}
				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_S)
				{

				}
				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_A)
				{

				}
				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_D)
				{

				}
			}
			break;

		default: break;
		}
		return false;
	}
};


//////////////////////////////////////////////////////////////////////////



class ViewerWidget : public QWidget, public osgViewer::Viewer
{
public:
	ViewerWidget(osg::Node *scene = NULL)
	{
		QWidget* renderWidget = getRenderWidget( createGraphicsWindow(0,0,640,480), 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.5) );
		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), 1.0f, 1000.0f );
		camera->setViewMatrixAsLookAt(osg::Vec3d(0, 0, 0), osg::Vec3d(0, 0, -1), osg::Vec3d(0, 1, 0));
		camera->setClearDepth(1.0f);
		
		camera->setPreDrawCallback(new LensFlareCallback);
		
		g_View = this;

		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 = 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;
	g_Root = root;

	osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
	zoomMT->setMatrix(osg::Matrix::translate(0, 0, -20));

	osg::MatrixTransform *rotXMT = new osg::MatrixTransform;
	osg::MatrixTransform *rotYMT = new osg::MatrixTransform;
	rotYMT->addUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(3, 0, 0), osg::Y_AXIS, 0.3));
	zoomMT->addChild(rotXMT);
	rotXMT->addChild(rotYMT);
	rotYMT->addChild(createCylinderNode());


	root->addChild(zoomMT);
	return root;
}



int main( int argc, char** argv )
{
	QApplication app(argc, argv);
	ViewerWidget* viewWidget = new ViewerWidget(buildScene());
	viewWidget->setGeometry( 100, 100, 640, 481 );
	viewWidget->show();
	return app.exec();
}

你可能感兴趣的:(C++,qt,OpenGL,nehe,OSG)