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

  • 简介

NeHe教程这节课向我们介绍了怎样在场景中绘制阴影效果,正如NeHe课程中所说,这节课是OpenGL中的一个高级主题。NeHe课程中实现阴影的效果采用的是一种称为阴影锥(ShadowVolume)的方法,更确切地说采用的是ShadowVolume中的z-pass方法,通过使用模板缓冲区完成阴影的绘制。关于阴影锥的介绍可以参考

Efficent Shadow Volume Rendering 此外ZwqXin在他的博客中有一系列关于阴影技术的文章,读者可以参考。

  • 实现

关于阴影锥实现的Z-pass算法简单介绍一下,一般包括以下几个步骤

  1. Disable writes to the depth and color buffers. 禁用深度缓冲和颜色缓冲的写入
  2. Use back-face culling. 开启背面拣选
  3. Set the stencil operation to increment on depth pass (only count shadows in front of the object). 在阴影锥绘制的对应区域增加模板缓冲区的值
  4. Render the shadow volumes (because of culling, only their front faces are rendered).绘制阴影锥(由于禁止写入颜色缓冲区,这时候只会修改模板缓冲区的值)
  5. Use front-face culling. 开启正面拣选
  6. Set the stencil operation to decrement on depth pass.  在正面拣选的阴影锥对应的区域减少模板缓冲区的值
  7. Render the shadow volumes (only their back faces are rendered). 绘制阴影锥(禁用了写入颜色缓冲区,只会修改模板缓冲区的值,会减少一部分之前绘制在模板缓冲区中的值,剩下的部分即为阴影)
  8. 绘制一个覆盖整个屏幕区域的几何体,同时开启模板测试,让颜色缓冲区可写,在模板测试通过的地方绘制出阴影

清楚了原理之后开始实现:

首先绘制我们的场景中的几何体:

osg::Geode*	drawLight();
osg::Geode*	drawRoom();
osg::Geode*	drawSphere();
osg::Geode* DrawGLObject(ShadowedObject o);

接下来将这些部分添加到场景中,注意场景中光源的位置需要动态进行计算(因为我们的操作会随时改变两个旋转矩阵的值),在LightPosUpdateCallback和RotYAxisCallback中完成计算

	osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
	zoomMT->setMatrix(osg::Matrix::translate(0, 0, -20.0));
	osg::Light *light = new osg::Light;
	light->setAmbient(osg::Vec4(0.2f, 0.2f, 0.2f, 1.0f));
	light->setDiffuse(osg::Vec4(0.6f, 0.6f, 0.6f, 1.0f));
	light->setSpecular(osg::Vec4(-0.2f, -0.2f, -0.2f, 1.0f));
	light->setPosition(osg::Vec4(0.0f, 5.0f,-4.0f, 1.0f));
	light->setLightNum(1);
	osg::LightSource *lightSource = new osg::LightSource;
	lightSource->setLight(light);
	lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
	zoomMT->addChild(lightSource);
	osg::MatrixTransform *sphereTrans = new osg::MatrixTransform;
	sphereTrans->setMatrix(osg::Matrix::translate(-4.0f,-5.0f,-6.0f));
	sphereTrans->addChild(drawSphere());
	zoomMT->addChild(sphereTrans);

//////////////////////////////////////////////////////////////////////////
	osg::MatrixTransform *zoomMT2 = new osg::MatrixTransform;
	zoomMT2->setName("ZOOM");
	zoomMT2->setMatrix(osg::Matrix::translate(0,0,-20));
	
	osg::Geode *roomGeode = drawRoom();
	zoomMT2->addChild(roomGeode);

	osg::MatrixTransform *objTransMT = new osg::MatrixTransform;
	objTransMT->setName("TRANSLATE");
	zoomMT2->addChild(objTransMT);

	objTransMT->setMatrix(osg::Matrix::translate(-2.0f,-2.0f,-5.0f));
	osg::MatrixTransform *objRotXMT = new osg::MatrixTransform;
	objRotXMT->setName("XROT");
	g_rotX = objRotXMT;
	objRotXMT->addUpdateCallback(new RotAxisCallback(osg::X_AXIS));
	osg::MatrixTransform *objRotYMT = new osg::MatrixTransform;
	g_rotY = objRotYMT;
	objRotYMT->addUpdateCallback(new RotYAxisCallback(osg::Y_AXIS));
	objRotYMT->setName("YROT");
	objTransMT->addChild(objRotXMT);
	objRotXMT->addChild(objRotYMT);
	objRotYMT->addChild(DrawGLObject(obj));
	objRotYMT->addChild(CastShadow(&obj, lp));

	osg::MatrixTransform *lightMT = new osg::MatrixTransform;
	lightMT->addUpdateCallback(new LightPosUpdateCallback);
	lightMT->addChild(drawLight());
	objRotYMT->addChild(lightMT);
在旋转节点的回调中我们动态计算光源的位置:

	//实时获取灯光的位置
		{
			osg::NodePath nodePathToRotateY = nv->getNodePath();	
			osg::Node *yRot = nodePathToRotateY.back();
			nodePathToRotateY.pop_back();
			osg::Node *xRot = nodePathToRotateY.back();
			nodePathToRotateY.pop_back();
			osg::Node *trans = nodePathToRotateY.back();
			osg::NodePath nodePathRot;
			nodePathRot.push_back(xRot);
			nodePathRot.push_back(yRot);
			osg::Matrix rotModelViewMatrix = computeLocalToWorld(nodePathRot);
			osg::Matrix rotInverseModelViewerMatrix = osg::Matrix::inverse(rotModelViewMatrix);
			osg::Vec4 tmp = osg::Vec4(LightPos[0], LightPos[1], LightPos[2], LightPos[3]) * rotInverseModelViewerMatrix;
			lp[0] = tmp[0];
			lp[1] = tmp[1];
			lp[2] = tmp[2];
			lp[3] = tmp[3];

			osg::NodePath nodePathRotAndTrans;
			nodePathRotAndTrans.push_back(trans);
			nodePathRotAndTrans.push_back(xRot);
			nodePathRotAndTrans.push_back(yRot);		
			osg::Matrix currentModelViewMatrix2 = computeLocalToWorld(nodePathRotAndTrans);
			osg::Matrix currentInvModelViewerMatrix2 = osg::Matrix::inverse(currentModelViewMatrix2);
			osg::Vec4 tmp2 = osg::Vec4(0.0f, 0.0, 0.0, 1.0) * currentInvModelViewerMatrix2;
			wlp[0] = tmp2[0];									
			wlp[1] = tmp2[1];									
			wlp[2] = tmp2[2];
			wlp[3] = tmp2[3];
			lp[0] +=  wlp[0];
			lp[1] +=  wlp[1];									
			lp[2] +=  wlp[2];	
               }	
接下来最重要的工作是绘制阴影体,我们也使用了NeHe课程中的方法。通过对模型中各个面寻找它们的邻接面,以及通过平面方程与光源位置计算几何体中正对光源的面与背对光源的面。之后找到阴影的交线(正对光源面与背对光源面的交线以及边界线),通过延长交线得到阴影锥。具体步骤比较复杂,代码可以查看源码中相关部分,原理如下图所示:

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


图中ab和bc以及ac边就是上文中所说的阴影线,adeb和befc以及fcad就是通过延长光线构建的阴影锥的几个面

接下来我们需要绘制这个阴影锥,使用之前所说的几个步骤:

首先正面绘制:

	//Pass1
	osg::Geode *shadowPassGeode1 = new osg::Geode;
	osg::Geometry *geomety1 = createShadowPass(o, lp);
	osg::Vec3Array *color1 = new osg::Vec3Array;
	color1->push_back(osg::Vec3(1.0, 0.0, 0.0));
	geomety1->setColorArray(color1, osg::Array::BIND_OVERALL);
	shadowPassGeode1->addDrawable(geomety1);

	osg::Depth *depth1 = new osg::Depth(osg::Depth::LEQUAL);
	depth1->setWriteMask(false);
	osg::Stencil *passStencil1 = new osg::Stencil();
	passStencil1->setFunction(osg::Stencil::ALWAYS, 1, 0xffffffff);
	passStencil1->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::INCR);
	osg::ColorMask *colorMask1 = new osg::ColorMask;
	colorMask1->setMask(false, false, false, false);
	osg::FrontFace *frontFace1 = new osg::FrontFace(osg::FrontFace::COUNTER_CLOCKWISE);
	osg::CullFace *cullFace1 = new osg::CullFace(osg::CullFace::BACK);

	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(depth1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(passStencil1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(colorMask1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(frontFace1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(cullFace1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
其次进行反面绘制:

	 //Pass2
	osg::Geode *shadowPassGeode2 = new osg::Geode;
	osg::Geometry *geomety2 = createShadowPass(o, lp);
	shadowPassGeode2->addDrawable(geomety2);

	osg::Depth *depth2 = new osg::Depth(osg::Depth::LEQUAL);
	depth2->setWriteMask(false);
	osg::Stencil *passStencil2 = new osg::Stencil;
	passStencil2->setFunction(osg::Stencil::ALWAYS, 1, 0xffffffff);
	passStencil2->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::DECR);
	osg::ColorMask *colorMask2 = new osg::ColorMask;
	colorMask2->setMask(false, false, false, false);
	osg::FrontFace *frontFace2 = new osg::FrontFace(osg::FrontFace::CLOCKWISE);
	osg::CullFace *cullFace2 = new osg::CullFace(osg::CullFace::BACK);

	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(depth2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(passStencil2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(colorMask2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(frontFace2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(cullFace2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
最后进行模板缓冲区测试绘制一个全屏的四边形:

	osg::MatrixTransform *mt = new osg::MatrixTransform;
	mt->setMatrix(osg::Matrix::identity());
	mt->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
	osg::Geode *geode = new osg::Geode;
	osg::Geometry *geometry = new osg::Geometry;
	osg::Vec3Array *vertexArray = new osg::Vec3Array;
	osg::Vec4Array *colorArray = new osg::Vec4Array;
	colorArray->push_back(osg::Vec4(0.0f, 0.0f, 0.0f, 0.4f));
	vertexArray->push_back(osg::Vec3(-0.1f, 0.1f,-0.10f));
	vertexArray->push_back(osg::Vec3(-0.1f,-0.1f,-0.10f));
	vertexArray->push_back(osg::Vec3(0.1f, 0.1f,-0.10f));
	vertexArray->push_back(osg::Vec3(0.1f,-0.1f,-0.10f));
	
	geometry->setVertexArray(vertexArray);
	geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));

	osg::BlendFunc *blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
	osg::Stencil *stencil = new osg::Stencil;
	stencil->setFunction(osg::Stencil::NOTEQUAL, 0, 0xffffffff);
	stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
	osg::Depth *depth3 = new osg::Depth(osg::Depth::LEQUAL);
	depth3->setWriteMask(false);
	
	geometry->getOrCreateStateSet()->setAttributeAndModes(depth3, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
	geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
	geometry->getOrCreateStateSet()->setAttributeAndModes(stencil, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
	geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, false);
	geode->addDrawable(geometry);
	mt->addChild(geode);
最后将所有部分添加到场景中,编译运行程序:

本文实现的效果和NeHe中略有偏差,我暂时未找到原因,在此抛砖引玉,希望读者指点一二。

用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十七课_第2张图片

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

#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/FrontFace>
#include <osg/Stencil>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/ColorMask>
#include <osg/Material>
#include <osg/CullFace>
#include <osg/LightSource>
#include <osg/ShapeDrawable>
#include <osgGA/TrackballManipulator>

typedef float GLvector4f[4];
GLvector4f lp = {2,7,1,1};
GLvector4f wlp;

osg::MatrixTransform *g_rotX = NULL;
osg::MatrixTransform *g_rotY = NULL;

float LightPos[] = { 0.0f, 5.0f,-4.0f, 1.0f};
float LightAmb[] = { 0.2f, 0.2f, 0.2f, 1.0f};	
float LightDif[] = { 0.6f, 0.6f, 0.6f, 1.0f};
float LightSpc[] = {-0.2f, -0.2f, -0.2f, 1.0f};

float MatAmb[] = {0.4f, 0.4f, 0.4f, 1.0f};
float MatDif[] = {0.2f, 0.6f, 0.9f, 1.0f};
float MatSpc[] = {0.0f, 0.0f, 0.0f, 1.0f};
float MatShn[] = {0.0f};

struct Point3f
{
	float x, y, z;
};

struct Plane
{
	float a, b, c, d;
};

struct Face
{
	unsigned		vertexIndices[3];				//三个顶点序号
	Point3f			normals[3];				
	unsigned		neighborIndices[3];			//三个相邻的面序号
	Plane			planeEquation;
	bool				visible;
};

struct ShadowedObject
{
	GLuint		nFaces;					//几何体的面数
	GLuint		nVertices;					//几何体顶点数
	Point3f		pVertices[100];
	Face			pFaces[200];
};


ShadowedObject	obj;
inline int ReadObject(char *st, ShadowedObject *o)
{
	FILE *file;
	unsigned int i;

	file = fopen(st, "r");
	if (!file) return false;
	
	fscanf(file, "%d", &(o->nVertices));
	for (i=1;i<=o->nVertices;i++){
		fscanf(file, "%f", &(o->pVertices[i].x));
		fscanf(file, "%f", &(o->pVertices[i].y));
		fscanf(file, "%f", &(o->pVertices[i].z));
	}

	fscanf(file, "%d", &(o->nFaces));
	for (i=0;i<o->nFaces;i++){
		fscanf(file, "%d", &(o->pFaces[i].vertexIndices[0]));
		fscanf(file, "%d", &(o->pFaces[i].vertexIndices[1]));
		fscanf(file, "%d", &(o->pFaces[i].vertexIndices[2]));

		fscanf(file, "%f", &(o->pFaces[i].normals[0].x));
		fscanf(file, "%f", &(o->pFaces[i].normals[0].y));
		fscanf(file, "%f", &(o->pFaces[i].normals[0].z));
		fscanf(file, "%f", &(o->pFaces[i].normals[1].x));
		fscanf(file, "%f", &(o->pFaces[i].normals[1].y));
		fscanf(file, "%f", &(o->pFaces[i].normals[1].z));
		fscanf(file, "%f", &(o->pFaces[i].normals[2].x));
		fscanf(file, "%f", &(o->pFaces[i].normals[2].y));
		fscanf(file, "%f", &(o->pFaces[i].normals[2].z));
	}
	return true;
}


void SetConnectivity(ShadowedObject *o)
{
	for(int i=0;i<o->nFaces-1;i++)
		for(int j=i+1;j<o->nFaces;j++)
			for(int ki=0;ki<3;ki++)
				if(!o->pFaces[i].neighborIndices[ki]){

					for(int kj=0;kj<3;kj++){
						Face pFaceA = o->pFaces[i];
						Face pFaceB = o->pFaces[j];
						
						int vertA1 = pFaceA.vertexIndices[ki];
						int vertA2 = pFaceA.vertexIndices[( ki+1 )%3];

						int vertB1 = pFaceB.vertexIndices[kj];
						int vertB2 = pFaceB.vertexIndices[( kj+1 )%3];

						if (( vertA1 == vertB1 && vertA2 == vertB2 ) || ( vertA1 == vertB2 && vertA2 == vertB1 ))
						{
							pFaceA.neighborIndices[ki] = j + 1;
							pFaceB.neighborIndices[kj] = i + 1;
						}
					}
				}
}

inline void CalcPlane(ShadowedObject o, Face *face)
{
	Point3f v[4];

	for (int i = 0; i < 3; ++i)
	{
		v[i+1].x = o.pVertices[face->vertexIndices[i]].x;
		v[i+1].y = o.pVertices[face->vertexIndices[i]].y;
		v[i+1].z = o.pVertices[face->vertexIndices[i]].z;
	}

	face->planeEquation.a = v[1].y*(v[2].z-v[3].z) + v[2].y*(v[3].z-v[1].z) + v[3].y*(v[1].z-v[2].z);
	face->planeEquation.b = v[1].z*(v[2].x-v[3].x) + v[2].z*(v[3].x-v[1].x) + v[3].z*(v[1].x-v[2].x);
	face->planeEquation.c = v[1].x*(v[2].y-v[3].y) + v[2].x*(v[3].y-v[1].y) + v[3].x*(v[1].y-v[2].y);
	face->planeEquation.d =-( v[1].x*(v[2].y*v[3].z - v[3].y*v[2].z) +
		v[2].x*(v[3].y*v[1].z - v[1].y*v[3].z) +
		v[3].x*(v[1].y*v[2].z - v[2].y*v[1].z) );
}

osg::Geode* DrawGLObject(ShadowedObject o)
{
	osg::Geode *geode = new osg::Geode;
	osg::Geometry *geometry = new osg::Geometry;

	osg::Vec3Array *vertexArray = new osg::Vec3Array;
	osg::Vec3Array *normalArray = new osg::Vec3Array;
	geometry->setVertexArray(vertexArray);
	geometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);

	for (int i = 0; i < o.nFaces; ++i)
	{
		for (int j = 0; j < 3; ++j)
		{
			vertexArray->push_back(osg::Vec3(o.pVertices[o.pFaces[i].vertexIndices[j]].x, 
								o.pVertices[o.pFaces[i].vertexIndices[j]].y, o.pVertices[o.pFaces[i].vertexIndices[j]].z));
			normalArray->push_back(osg::Vec3(o.pFaces[i].normals[j].x, o.pFaces[i].normals[j].y, o.pFaces[i].normals[j].z));
		}
	}

	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertexArray->size()));
	
	osg::Material *material = new osg::Material;
	material->setAmbient(osg::Material::FRONT, osg::Vec4(MatAmb[0], MatAmb[1], MatAmb[2], MatAmb[3]));
	material->setDiffuse(osg::Material::FRONT, osg::Vec4(MatDif[0], MatDif[1],MatDif[2],MatDif[3]));
	material->setSpecular(osg::Material::FRONT, osg::Vec4(MatSpc[0],MatSpc[1],MatSpc[2],MatSpc[3]));
	material->setShininess(osg::Material::FRONT, MatShn[0]);
	geometry->getOrCreateStateSet()->setAttributeAndModes(material);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHT0, osg::StateAttribute::OFF);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::ON);

	geode->addDrawable(geometry);
	return geode;
}


class ShadowGeometryPassUpdateCallback : public osg::Drawable::UpdateCallback
{
public:

	virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable)
	{
		osg::Geometry *geometry = dynamic_cast<osg::Geometry*>(drawable);
		if(!geometry)
			return;
		
		osg::Vec3Array *vertexArray = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
		if (!vertexArray)
			return;

		Point3f v1, v2;
		if (vertexArray->size() == 0)
		{
			for (int i = 0; i < obj.nFaces; ++i)
			{
				if (obj.pFaces[i].visible)
				{
					for (int j = 0; j < 3; ++j)
					{
						int k = obj.pFaces[i].neighborIndices[j];
						if (!k || (!obj.pFaces[k-1].visible))
						{		
							int p1 = obj.pFaces[i].vertexIndices[j];
							int jj = (j+1) % 3;
							int p2 = obj.pFaces[i].vertexIndices[jj];

							v1.x = (obj.pVertices[p1].x - lp[0]) * 10;
							v1.y = (obj.pVertices[p1].y - lp[1]) * 10;
							v1.z = (obj.pVertices[p1].z - lp[2]) * 10;

							v2.x = (obj.pVertices[p2].x - lp[0])*10;
							v2.y = (obj.pVertices[p2].y - lp[1])*10;
							v2.z = (obj.pVertices[p2].z - lp[2])*10;

							vertexArray->push_back(osg::Vec3(obj.pVertices[p1].x, obj.pVertices[p1].y, obj.pVertices[p1].z));
							vertexArray->push_back(osg::Vec3(obj.pVertices[p1].x + v1.x,obj.pVertices[p1].y + v1.y,obj.pVertices[p1].z + v1.z));
							vertexArray->push_back(osg::Vec3(obj.pVertices[p2].x,obj.pVertices[p2].y,obj.pVertices[p2].z));
							vertexArray->push_back(osg::Vec3(obj.pVertices[p2].x + v2.x,obj.pVertices[p2].y + v2.y,obj.pVertices[p2].z + v2.z));
						}	
					}
				}
			}
			geometry->setVertexArray(vertexArray);
			geometry->setPrimitiveSet(0, new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));
			vertexArray->dirty();
		}
		else
		{
			vertexArray->clear();
			for (int i = 0; i < obj.nFaces; ++i)
			{
				if (obj.pFaces[i].visible)
				{
					for (int j = 0; j < 3; ++j)
					{
						int k = obj.pFaces[i].neighborIndices[j];
						if (!k || (!obj.pFaces[k-1].visible))
						{		
							int p1 = obj.pFaces[i].vertexIndices[j];
							int jj = (j+1) % 3;
							int p2 = obj.pFaces[i].vertexIndices[jj];

							v1.x = (obj.pVertices[p1].x - lp[0]) * 10;
							v1.y = (obj.pVertices[p1].y - lp[1]) * 10;
							v1.z = (obj.pVertices[p1].z - lp[2]) * 10;

							v2.x = (obj.pVertices[p2].x - lp[0])*10;
							v2.y = (obj.pVertices[p2].y - lp[1])*10;
							v2.z = (obj.pVertices[p2].z - lp[2])*10;

							vertexArray->push_back(osg::Vec3(obj.pVertices[p1].x, obj.pVertices[p1].y, obj.pVertices[p1].z));
							vertexArray->push_back(osg::Vec3(obj.pVertices[p1].x + v1.x,obj.pVertices[p1].y + v1.y,obj.pVertices[p1].z + v1.z));
							vertexArray->push_back(osg::Vec3(obj.pVertices[p2].x,obj.pVertices[p2].y,obj.pVertices[p2].z));
							vertexArray->push_back(osg::Vec3(obj.pVertices[p2].x + v2.x,obj.pVertices[p2].y + v2.y,obj.pVertices[p2].z + v2.z));
						}	
					}
				}
			}
			geometry->setVertexArray(vertexArray);
			geometry->setPrimitiveSet(0, new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));
			vertexArray->dirty();
		}
	}

};




osg::Geometry*	createShadowPass(ShadowedObject *o, float *lp)
{
	Point3f v1, v2;

	osg::Geometry *passGeometry = new osg::Geometry;
	osg::Vec3Array *vertexArray = new osg::Vec3Array;
	passGeometry->setUpdateCallback(new ShadowGeometryPassUpdateCallback);
	osg::Vec3Array *colorArray = new osg::Vec3Array;
	colorArray->push_back(osg::Vec3(0.7f, 0.4f, 0.0f));
	passGeometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	passGeometry->setUseDisplayList(false);
	passGeometry->setUseVertexBufferObjects(true);

	for (int i = 0; i < o->nFaces; ++i)
	{
		if (o->pFaces[i].visible)
		{
			for (int j = 0; j < 3; ++j)
			{
				int k = o->pFaces[i].neighborIndices[j];
				if (!k || (!o->pFaces[k-1].visible))
				{		
					int p1 = o->pFaces[i].vertexIndices[j];
					int jj = (j+1) % 3;
					int p2 = o->pFaces[i].vertexIndices[jj];

					v1.x = (o->pVertices[p1].x - lp[0]) * 10;
					v1.y = (o->pVertices[p1].y - lp[1]) * 10;
					v1.z = (o->pVertices[p1].z - lp[2]) * 10;

					v2.x = (o->pVertices[p2].x - lp[0])*10;
					v2.y = (o->pVertices[p2].y - lp[1])*10;
					v2.z = (o->pVertices[p2].z - lp[2])*10;

					vertexArray->push_back(osg::Vec3(o->pVertices[p1].x, o->pVertices[p1].y, o->pVertices[p1].z));
					vertexArray->push_back(osg::Vec3(o->pVertices[p1].x + v1.x,o->pVertices[p1].y + v1.y,o->pVertices[p1].z + v1.z));
					vertexArray->push_back(osg::Vec3(o->pVertices[p2].x,o->pVertices[p2].y,o->pVertices[p2].z));
					vertexArray->push_back(osg::Vec3(o->pVertices[p2].x + v2.x,o->pVertices[p2].y + v2.y,o->pVertices[p2].z + v2.z));
				}	
			}
		}
	}
	passGeometry->setVertexArray(vertexArray);
	passGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));

	return passGeometry;
}


osg::Group*  CastShadow(ShadowedObject *o, float *lp)
{
	osg::Group *group = new osg::Group;
	group->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
	//Pass1

	osg::Geode *shadowPassGeode1 = new osg::Geode;
	osg::Geometry *geomety1 = createShadowPass(o, lp);
	osg::Vec3Array *color1 = new osg::Vec3Array;
	color1->push_back(osg::Vec3(1.0, 0.0, 0.0));
	geomety1->setColorArray(color1, osg::Array::BIND_OVERALL);
	shadowPassGeode1->addDrawable(geomety1);

	osg::Depth *depth1 = new osg::Depth(osg::Depth::LEQUAL);
	depth1->setWriteMask(false);
	osg::Stencil *passStencil1 = new osg::Stencil();
	passStencil1->setFunction(osg::Stencil::ALWAYS, 1, 0xffffffff);
	passStencil1->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::INCR);
	osg::ColorMask *colorMask1 = new osg::ColorMask;
	colorMask1->setMask(false, false, false, false);
	osg::FrontFace *frontFace1 = new osg::FrontFace(osg::FrontFace::COUNTER_CLOCKWISE);
	osg::CullFace *cullFace1 = new osg::CullFace(osg::CullFace::BACK);

	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(depth1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(passStencil1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(colorMask1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(frontFace1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setAttributeAndModes(cullFace1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode1->getOrCreateStateSet()->setMode(GL_LIGHTING, false);

	 //Pass2
	osg::Geode *shadowPassGeode2 = new osg::Geode;
	osg::Geometry *geomety2 = createShadowPass(o, lp);
	shadowPassGeode2->addDrawable(geomety2);

	osg::Depth *depth2 = new osg::Depth(osg::Depth::LEQUAL);
	depth2->setWriteMask(false);
	osg::Stencil *passStencil2 = new osg::Stencil;
	passStencil2->setFunction(osg::Stencil::ALWAYS, 1, 0xffffffff);
	passStencil2->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::DECR);
	osg::ColorMask *colorMask2 = new osg::ColorMask;
	colorMask2->setMask(false, false, false, false);
	osg::FrontFace *frontFace2 = new osg::FrontFace(osg::FrontFace::CLOCKWISE);
	osg::CullFace *cullFace2 = new osg::CullFace(osg::CullFace::BACK);

	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(depth2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(passStencil2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(colorMask2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(frontFace2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setAttributeAndModes(cullFace2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
	shadowPassGeode2->getOrCreateStateSet()->setMode(GL_LIGHTING, false);

	osg::MatrixTransform *mt = new osg::MatrixTransform;
	mt->setMatrix(osg::Matrix::identity());
	mt->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
	osg::Geode *geode = new osg::Geode;
	osg::Geometry *geometry = new osg::Geometry;
	osg::Vec3Array *vertexArray = new osg::Vec3Array;
	osg::Vec4Array *colorArray = new osg::Vec4Array;
	colorArray->push_back(osg::Vec4(0.0f, 0.0f, 0.0f, 0.4f));
	vertexArray->push_back(osg::Vec3(-0.1f, 0.1f,-0.10f));
	vertexArray->push_back(osg::Vec3(-0.1f,-0.1f,-0.10f));
	vertexArray->push_back(osg::Vec3(0.1f, 0.1f,-0.10f));
	vertexArray->push_back(osg::Vec3(0.1f,-0.1f,-0.10f));
	
	geometry->setVertexArray(vertexArray);
	geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));

	osg::BlendFunc *blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
	osg::Stencil *stencil = new osg::Stencil;
	stencil->setFunction(osg::Stencil::NOTEQUAL, 0, 0xffffffff);
	stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
	osg::Depth *depth3 = new osg::Depth(osg::Depth::LEQUAL);
	depth3->setWriteMask(false);
	
	geometry->getOrCreateStateSet()->setAttributeAndModes(depth3, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
	geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
	geometry->getOrCreateStateSet()->setAttributeAndModes(stencil, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
	geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, false);
	geode->addDrawable(geometry);
	mt->addChild(geode);

	group->addChild(shadowPassGeode1);
	group->addChild(shadowPassGeode2);
	group->addChild(mt);

	return group;
}

osg::Geode*	drawLight()
{
	osg::ShapeDrawable *shapeDrawable = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(), 0.2));
	osg::Geode *sphereGeode = new osg::Geode;
	sphereGeode->addDrawable(shapeDrawable);
	shapeDrawable->setColor(osg::Vec4(0.7f, 0.4f, 0.0f, 1.0f));
	return sphereGeode;
}

osg::Geode*	drawRoom()
{
	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;

	vertexArray->push_back(osg::Vec3(-10.0f,-10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f,-10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(10.0f,-10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(10.0f,-10.0f,-20.0f));

	vertexArray->push_back(osg::Vec3(-10.0f, 10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f, 10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(10.0f, 10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(10.0f, 10.0f, 20.0f));

	vertexArray->push_back(osg::Vec3(-10.0f, 10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f,-10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(10.0f,-10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(10.0f, 10.0f,-20.0f));

	vertexArray->push_back(osg::Vec3(10.0f, 10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(10.0f,-10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f,-10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f, 10.0f, 20.0f));

	vertexArray->push_back(osg::Vec3(-10.0f, 10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f,-10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f,-10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(-10.0f, 10.0f,-20.0f));

	vertexArray->push_back(osg::Vec3(10.0f, 10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(10.0f,-10.0f,-20.0f));
	vertexArray->push_back(osg::Vec3(10.0f,-10.0f, 20.0f));
	vertexArray->push_back(osg::Vec3(10.0f, 10.0f, 20.0f));

	for (int i = 0; i < 4; ++i)
	{
		normalArray->push_back(osg::Vec3(0.0f, 1.0f, 0.0f));
	}
	for (int i = 0; i < 4; ++i)
	{
		normalArray->push_back(osg::Vec3(0.0f,-1.0f, 0.0f));
	}
	for (int i = 0; i < 4; ++i)
	{
		normalArray->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
	}
	for (int i = 0; i < 4; ++i)
	{
		normalArray->push_back(osg::Vec3(0.0f, 0.0f,-1.0f));
	}
	for (int i = 0; i < 4; ++i)
	{
		normalArray->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
	}
	for (int i = 0; i < 4; ++i)
	{
		normalArray->push_back(osg::Vec3(-1.0f, 0.0f, 0.0f));
	}
	colorArray->push_back(osg::Vec3(0.2, 0.2, 0.2));

	geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
	geometry->setVertexArray(vertexArray);

	//osg3.2.0 no bind_per_primitive
	geometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertexArray->size()));

	osg::Material *material = new osg::Material;
	material->setAmbient(osg::Material::FRONT, osg::Vec4(MatAmb[0], MatAmb[1], MatAmb[2], MatAmb[3]));
	material->setDiffuse(osg::Material::FRONT, osg::Vec4(MatDif[0], MatDif[1],MatDif[2],MatDif[3]));
	material->setSpecular(osg::Material::FRONT, osg::Vec4(MatSpc[0],MatSpc[1],MatSpc[2],MatSpc[3]));
	material->setShininess(osg::Material::FRONT, MatShn[0]);
	geometry->getOrCreateStateSet()->setAttributeAndModes(material);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHT0, osg::StateAttribute::OFF);
	geometry->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::ON);

	osg::CullFace *cullFace = new osg::CullFace(osg::CullFace::BACK);
	geometry->getOrCreateStateSet()->setAttributeAndModes(cullFace);


	geode->addDrawable(geometry);

	return geode;
}

osg::Geode*	drawSphere()
{
	osg::ShapeDrawable *shapeDrawable = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(), 2));
	osg::Geode *sphereGeode = new osg::Geode;

	osg::Material *material = new osg::Material;
	material->setAmbient(osg::Material::FRONT, osg::Vec4(MatAmb[0], MatAmb[1], MatAmb[2], MatAmb[3]));
	material->setDiffuse(osg::Material::FRONT, osg::Vec4(MatDif[0], MatDif[1],MatDif[2],MatDif[3]));
	material->setSpecular(osg::Material::FRONT, osg::Vec4(MatSpc[0],MatSpc[1],MatSpc[2],MatSpc[3]));
	material->setShininess(osg::Material::FRONT, MatShn[0]);

	shapeDrawable->getOrCreateStateSet()->setAttributeAndModes(material);
	shapeDrawable->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
	shapeDrawable->getOrCreateStateSet()->setMode(GL_LIGHT0, osg::StateAttribute::OFF);
	shapeDrawable->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::ON);
	
	sphereGeode->addDrawable(shapeDrawable);

	return sphereGeode;
}



class RotAxisCallback : public osg::NodeCallback
{
public:
	RotAxisCallback(const osg::Vec3& axis, double rotSpeed = 0.0, double currentAngle = 0.0)
		: _rotAxis(axis), _rotSpeed(rotSpeed), _currentAngle(currentAngle){ }

	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
	{
		osg::MatrixTransform *rotMT = dynamic_cast<osg::MatrixTransform*>(node);
		if (!rotMT)
			return;
		_currentAngle += _rotSpeed;
		rotMT->setMatrix(osg::Matrix::rotate(_currentAngle, _rotAxis));
		
		traverse(node, nv);
	}

	void setRotateSpeed(double speed)
	{
		_rotSpeed = speed;
	}

	double getRotateSpeed() const
	{
		return _rotSpeed;
	}

	double getCurrentAngle() const
	{
		return _currentAngle;
	}

private:
	osg::Vec3		_rotAxis;
	double			_currentAngle;
	double			_rotSpeed;
};


class RotYAxisCallback : public osg::NodeCallback
{
public:
	RotYAxisCallback(const osg::Vec3& axis, double rotSpeed = 0.0, double currentAngle = 0.0)
		: _rotAxis(axis), _rotSpeed(rotSpeed), _currentAngle(currentAngle){ }

	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
	{
		osg::MatrixTransform *rotMT = dynamic_cast<osg::MatrixTransform*>(node);
		if (!rotMT)
			return;
		_currentAngle += _rotSpeed;
		rotMT->setMatrix(osg::Matrix::rotate(_currentAngle, _rotAxis));
//////////////////////////////////////////////////////////////////////////
				//实时获取灯光的位置
		{
			osg::NodePath nodePathToRotateY = nv->getNodePath();	
			osg::Node *yRot = nodePathToRotateY.back();
			nodePathToRotateY.pop_back();
			osg::Node *xRot = nodePathToRotateY.back();
			nodePathToRotateY.pop_back();
			osg::Node *trans = nodePathToRotateY.back();
			osg::NodePath nodePathRot;
			nodePathRot.push_back(xRot);
			nodePathRot.push_back(yRot);
			osg::Matrix rotModelViewMatrix = computeLocalToWorld(nodePathRot);
			osg::Matrix rotInverseModelViewerMatrix = osg::Matrix::inverse(rotModelViewMatrix);
			osg::Vec4 tmp = osg::Vec4(LightPos[0], LightPos[1], LightPos[2], LightPos[3]) * rotInverseModelViewerMatrix;
			lp[0] = tmp[0];
			lp[1] = tmp[1];
			lp[2] = tmp[2];
			lp[3] = tmp[3];

			osg::NodePath nodePathRotAndTrans;
			nodePathRotAndTrans.push_back(trans);
			nodePathRotAndTrans.push_back(xRot);
			nodePathRotAndTrans.push_back(yRot);		
			osg::Matrix currentModelViewMatrix2 = computeLocalToWorld(nodePathRotAndTrans);
			osg::Matrix currentInvModelViewerMatrix2 = osg::Matrix::inverse(currentModelViewMatrix2);
			osg::Vec4 tmp2 = osg::Vec4(0.0f, 0.0, 0.0, 1.0) * currentInvModelViewerMatrix2;
			wlp[0] = tmp2[0];									
			wlp[1] = tmp2[1];									
			wlp[2] = tmp2[2];
			wlp[3] = tmp2[3];
			lp[0] +=  wlp[0];
			lp[1] +=  wlp[1];									
			lp[2] +=  wlp[2];									
			
			for(int i = 0; i < obj.nFaces; ++i)
			{
				float side = obj.pFaces[i].planeEquation.a * lp[0] +
					obj.pFaces[i].planeEquation.b * lp[1] +
					obj.pFaces[i].planeEquation.c * lp[2] +
					obj.pFaces[i].planeEquation.d * lp[3];
				if (side > 0.0)
					obj.pFaces[i].visible = true;
				else
					obj.pFaces[i].visible = false;
			}
		}

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

		traverse(node, nv);
	}

	void setRotateSpeed(double speed)
	{
		_rotSpeed = speed;
	}

	double getRotateSpeed() const
	{
		return _rotSpeed;
	}

	double getCurrentAngle() const
	{
		return _currentAngle;
	}

private:
	osg::Vec3		_rotAxis;
	double			_currentAngle;
	double			_rotSpeed;
};



class LightPosUpdateCallback : public osg::NodeCallback
{
public:
	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
	{
		osg::MatrixTransform *posMT = dynamic_cast<osg::MatrixTransform*>(node);
		if (!posMT)
			return;
		posMT->setMatrix(osg::Matrix::translate(lp[0], lp[1], lp[2]));

		traverse(node, nv);
	}
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class ManipulatorSceneHandler : public osgGA::GUIEventHandler
{
public:
	ManipulatorSceneHandler()
	{
	}

	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::FRAME):
			{
				return false;
			}

		case(osgGA::GUIEventAdapter::KEYDOWN):
			{
				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)
				{
					if (!g_rotY)
						return false;

					RotYAxisCallback *rotCallback = dynamic_cast<RotYAxisCallback*>(g_rotY->getUpdateCallback());
					if (!rotCallback)
						return false;

					double speed = rotCallback->getRotateSpeed();
					speed -= 0.02;
					rotCallback->setRotateSpeed(speed);
				}

				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)
				{
					if (!g_rotY)
						return false;

					RotYAxisCallback *rotCallback = dynamic_cast<RotYAxisCallback*>(g_rotY->getUpdateCallback());
					if (!rotCallback)
						return false;

					double speed = rotCallback->getRotateSpeed();
					speed += 0.02;
					rotCallback->setRotateSpeed(speed);
				}

				if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)
				{
					if (!g_rotX)
						return false;

					RotAxisCallback *rotCallback = dynamic_cast<RotAxisCallback*>(g_rotX->getUpdateCallback());
					if (!rotCallback)
						return false;

					double speed = rotCallback->getRotateSpeed();
					speed -= 0.02;
					rotCallback->setRotateSpeed(speed);
				}

				if (ea.getKey()== osgGA::GUIEventAdapter::KEY_Down)
				{
					if (!g_rotX)
						return false;

					RotAxisCallback *rotCallback = dynamic_cast<RotAxisCallback*>(g_rotX->getUpdateCallback());
					if (!rotCallback)
						return false;

					double speed = rotCallback->getRotateSpeed();
					speed += 0.02;
					rotCallback->setRotateSpeed(speed);
				}
			}
		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.0f, 0.0f, 0.0f, 0.5f) );
		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, 0), osg::Vec3d(0, 0, -1), osg::Vec3d(0, 1, 0));

		camera->setClearStencil(0);
		camera->setClearDepth(1.0f);
		camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 

		this->setSceneData( scene );
		setLightingMode(osg::View::NO_LIGHT);
		addEventHandler(new ManipulatorSceneHandler);
		//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();
		ds->setMinimumNumStencilBits(1);
		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;
};

void initObject()
{
	if (!ReadObject("Data/Object2.txt", &obj))
		return;

	SetConnectivity(&obj);

	for (unsigned int i=0;i<obj.nFaces;i++)
		CalcPlane(obj, &(obj.pFaces[i]));

	for(int i = 0; i < obj.nFaces; ++i)
	{
		float side = obj.pFaces[i].planeEquation.a * lp[0] +
			obj.pFaces[i].planeEquation.b * lp[1] +
			obj.pFaces[i].planeEquation.c * lp[2] +
			obj.pFaces[i].planeEquation.d * lp[3];
		if (side > 0.0)
			obj.pFaces[i].visible = true;
		else
			obj.pFaces[i].visible = false;
	}
}


osg::Node*	buildScene()
{
	initObject();

	osg::Group *root = new osg::Group;
	root->setName("ROOT");
	root->getOrCreateStateSet()->setMode(GL_LIGHT0, osg::StateAttribute::OFF);

//////////////////////////////////////////////////////////////////////////
	osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
	zoomMT->setMatrix(osg::Matrix::translate(0, 0, -20.0));
	osg::Light *light = new osg::Light;
	light->setAmbient(osg::Vec4(0.2f, 0.2f, 0.2f, 1.0f));
	light->setDiffuse(osg::Vec4(0.6f, 0.6f, 0.6f, 1.0f));
	light->setSpecular(osg::Vec4(-0.2f, -0.2f, -0.2f, 1.0f));
	light->setPosition(osg::Vec4(0.0f, 5.0f,-4.0f, 1.0f));
	light->setLightNum(1);
	osg::LightSource *lightSource = new osg::LightSource;
	lightSource->setLight(light);
	lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
	zoomMT->addChild(lightSource);
	osg::MatrixTransform *sphereTrans = new osg::MatrixTransform;
	sphereTrans->setMatrix(osg::Matrix::translate(-4.0f,-5.0f,-6.0f));
	sphereTrans->addChild(drawSphere());
	zoomMT->addChild(sphereTrans);

//////////////////////////////////////////////////////////////////////////
	osg::MatrixTransform *zoomMT2 = new osg::MatrixTransform;
	zoomMT2->setName("ZOOM");
	zoomMT2->setMatrix(osg::Matrix::translate(0,0,-20));
	
	osg::Geode *roomGeode = drawRoom();
	zoomMT2->addChild(roomGeode);

	osg::MatrixTransform *objTransMT = new osg::MatrixTransform;
	objTransMT->setName("TRANSLATE");
	zoomMT2->addChild(objTransMT);

	objTransMT->setMatrix(osg::Matrix::translate(-2.0f,-2.0f,-5.0f));
	osg::MatrixTransform *objRotXMT = new osg::MatrixTransform;
	objRotXMT->setName("XROT");
	g_rotX = objRotXMT;
	objRotXMT->addUpdateCallback(new RotAxisCallback(osg::X_AXIS));
	osg::MatrixTransform *objRotYMT = new osg::MatrixTransform;
	g_rotY = objRotYMT;
	objRotYMT->addUpdateCallback(new RotYAxisCallback(osg::Y_AXIS));
	objRotYMT->setName("YROT");
	objTransMT->addChild(objRotXMT);
	objRotXMT->addChild(objRotYMT);
	objRotYMT->addChild(DrawGLObject(obj));
	objRotYMT->addChild(CastShadow(&obj, lp));

	osg::MatrixTransform *lightMT = new osg::MatrixTransform;
	lightMT->addUpdateCallback(new LightPosUpdateCallback);
	lightMT->addChild(drawLight());
	objRotYMT->addChild(lightMT);

	
	root->addChild(zoomMT);
	root->addChild(zoomMT2);
	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();
}


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