NeHe教程这节课向我们介绍了怎样在场景中绘制阴影效果,正如NeHe课程中所说,这节课是OpenGL中的一个高级主题。NeHe课程中实现阴影的效果采用的是一种称为阴影锥(ShadowVolume)的方法,更确切地说采用的是ShadowVolume中的z-pass方法,通过使用模板缓冲区完成阴影的绘制。关于阴影锥的介绍可以参考
Efficent Shadow Volume Rendering 此外ZwqXin在他的博客中有一系列关于阴影技术的文章,读者可以参考。
关于阴影锥实现的Z-pass算法简单介绍一下,一般包括以下几个步骤
清楚了原理之后开始实现:
首先绘制我们的场景中的几何体:
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课程中的方法。通过对模型中各个面寻找它们的邻接面,以及通过平面方程与光源位置计算几何体中正对光源的面与背对光源的面。之后找到阴影的交线(正对光源面与背对光源面的交线以及边界线),通过延长交线得到阴影锥。具体步骤比较复杂,代码可以查看源码中相关部分,原理如下图所示:
图中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中略有偏差,我暂时未找到原因,在此抛砖引玉,希望读者指点一二。
附:本课源码(源码中可能存在错误和不足,仅供参考)
#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(); }