/* OpenSceneGraph example, osglight. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stdio.h" // callback to make the loaded model oscilate up and down. class ModelTransformCallback : public osg::NodeCallback { public: ModelTransformCallback(const osg::BoundingSphere& bs) { _firstTime = 0.0; _period = 4.0f; _range = bs.radius()*0.5f; } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::PositionAttitudeTransform* pat = dynamic_cast(node); const osg::FrameStamp* frameStamp = nv->getFrameStamp(); if (pat && frameStamp) { if (_firstTime==0.0) { _firstTime = frameStamp->getSimulationTime(); } double phase = (frameStamp->getSimulationTime()-_firstTime)/_period; phase -= floor(phase); phase *= (2.0 * osg::PI); osg::Quat rotation; rotation.makeRotate(phase,1.0f,1.0f,1.0f); pat->setAttitude(rotation); pat->setPosition(osg::Vec3(0.0f,0.0f,sin(phase))*_range); } // must traverse the Node's subgraph traverse(node,nv); } double _firstTime; double _period; double _range; }; osg::Node* createLights(osg::BoundingBox& bb,osg::StateSet* rootStateSet) { osg::Group* lightGroup = new osg::Group; float modelSize = bb.radius(); // create a spot light. osg::Light* myLight1 = new osg::Light; myLight1->setLightNum(0); myLight1->setPosition(osg::Vec4(bb.corner(4),1.0f)); myLight1->setAmbient(osg::Vec4(1.0f,0.0f,0.0f,1.0f)); myLight1->setDiffuse(osg::Vec4(1.0f,0.0f,0.0f,1.0f)); myLight1->setSpotCutoff(20.0f); myLight1->setSpotExponent(50.0f); myLight1->setDirection(osg::Vec3(1.0f,1.0f,-1.0f)); osg::LightSource* lightS1 = new osg::LightSource; lightS1->setLight(myLight1); lightS1->setLocalStateSetModes(osg::StateAttribute::ON); lightS1->setStateSetModes(*rootStateSet,osg::StateAttribute::ON); lightGroup->addChild(lightS1); // create a local light. osg::Light* myLight2 = new osg::Light; myLight2->setLightNum(1); myLight2->setPosition(osg::Vec4(0.0,0.0,0.0,1.0f)); myLight2->setAmbient(osg::Vec4(0.0f,1.0f,1.0f,1.0f)); myLight2->setDiffuse(osg::Vec4(0.0f,1.0f,1.0f,1.0f)); myLight2->setConstantAttenuation(1.0f); myLight2->setLinearAttenuation(2.0f/modelSize); myLight2->setQuadraticAttenuation(2.0f/osg::square(modelSize)); osg::LightSource* lightS2 = new osg::LightSource; lightS2->setLight(myLight2); lightS2->setLocalStateSetModes(osg::StateAttribute::ON); lightS2->setStateSetModes(*rootStateSet,osg::StateAttribute::ON); osg::MatrixTransform* mt = new osg::MatrixTransform(); { // set up the animation path osg::AnimationPath* animationPath = new osg::AnimationPath; animationPath->insert(0.0,osg::AnimationPath::ControlPoint(bb.corner(0))); animationPath->insert(1.0,osg::AnimationPath::ControlPoint(bb.corner(1))); animationPath->insert(2.0,osg::AnimationPath::ControlPoint(bb.corner(2))); animationPath->insert(3.0,osg::AnimationPath::ControlPoint(bb.corner(3))); animationPath->insert(4.0,osg::AnimationPath::ControlPoint(bb.corner(4))); animationPath->insert(5.0,osg::AnimationPath::ControlPoint(bb.corner(5))); animationPath->insert(6.0,osg::AnimationPath::ControlPoint(bb.corner(6))); animationPath->insert(7.0,osg::AnimationPath::ControlPoint(bb.corner(7))); animationPath->insert(8.0,osg::AnimationPath::ControlPoint(bb.corner(0))); animationPath->setLoopMode(osg::AnimationPath::SWING); mt->setUpdateCallback(new osg::AnimationPathCallback(animationPath)); } // create marker for point light. osg::Geometry* marker = new osg::Geometry; osg::Vec3Array* vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(0.0,0.0,0.0)); marker->setVertexArray(vertices); marker->addPrimitiveSet(new osg::DrawArrays(GL_POINTS,0,1)); osg::StateSet* stateset = new osg::StateSet; osg::Point* point = new osg::Point; point->setSize(4.0f); stateset->setAttribute(point); marker->setStateSet(stateset); osg::Geode* markerGeode = new osg::Geode; markerGeode->addDrawable(marker); mt->addChild(lightS2); mt->addChild(markerGeode); lightGroup->addChild(mt); return lightGroup; } osg::Geometry* createWall(const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3,osg::StateSet* stateset) { // create a drawable for occluder. osg::Geometry* geom = new osg::Geometry; geom->setStateSet(stateset); unsigned int noXSteps = 100; unsigned int noYSteps = 100; osg::Vec3Array* coords = new osg::Vec3Array; coords->reserve(noXSteps*noYSteps); osg::Vec3 dx = (v2-v1)/((float)noXSteps-1.0f); osg::Vec3 dy = (v3-v1)/((float)noYSteps-1.0f); unsigned int row; osg::Vec3 vRowStart = v1; for(row=0;rowpush_back(v); v += dx; } vRowStart+=dy; } geom->setVertexArray(coords); osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0].set(1.0f,1.0f,1.0f,1.0f); geom->setColorArray(colors, osg::Array::BIND_OVERALL); for(row=0;rowreserve(noXSteps*2); for(unsigned int col=0;colpush_back((row+1)*noXSteps+col); quadstrip->push_back(row*noXSteps+col); } geom->addPrimitiveSet(quadstrip); } // create the normals. osgUtil::SmoothingVisitor::smooth(*geom); return geom; } osg::ref_ptr createRoom(const osg::ref_ptr& loadedModel) { // default scale for this model. osg::BoundingSphere bs(osg::Vec3(0.0f,0.0f,0.0f),1.0f); osg::Group* root = new osg::Group; if (loadedModel) { const osg::BoundingSphere& loaded_bs = loadedModel->getBound(); osg::PositionAttitudeTransform* pat = new osg::PositionAttitudeTransform(); pat->setPivotPoint(loaded_bs.center()); pat->setUpdateCallback(new ModelTransformCallback(loaded_bs)); pat->addChild(loadedModel); bs = pat->getBound(); root->addChild(pat); } bs.radius()*=1.5f; // create a bounding box, which we'll use to size the room. osg::BoundingBox bb; bb.expandBy(bs); // create statesets. osg::StateSet* rootStateSet = new osg::StateSet; root->setStateSet(rootStateSet); osg::StateSet* wall = new osg::StateSet; wall->setMode(GL_CULL_FACE,osg::StateAttribute::ON); osg::StateSet* floor = new osg::StateSet; floor->setMode(GL_CULL_FACE,osg::StateAttribute::ON); osg::StateSet* roof = new osg::StateSet; roof->setMode(GL_CULL_FACE,osg::StateAttribute::ON); osg::Geode* geode = new osg::Geode; // create front side. geode->addDrawable(createWall(bb.corner(0), bb.corner(4), bb.corner(1), wall)); // right side geode->addDrawable(createWall(bb.corner(1), bb.corner(5), bb.corner(3), wall)); // left side geode->addDrawable(createWall(bb.corner(2), bb.corner(6), bb.corner(0), wall)); // back side geode->addDrawable(createWall(bb.corner(3), bb.corner(7), bb.corner(2), wall)); // floor geode->addDrawable(createWall(bb.corner(0), bb.corner(1), bb.corner(2), floor)); // roof geode->addDrawable(createWall(bb.corner(6), bb.corner(7), bb.corner(4), roof)); root->addChild(geode); root->addChild(createLights(bb,rootStateSet)); return root; } int main( int argc, char **argv ) { // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); // construct the viewer. osgViewer::Viewer viewer; // load the nodes from the commandline arguments. osg::ref_ptr loadedModel = osgDB::readRefNodeFiles(arguments); // if not loaded assume no arguments passed in, try use default mode instead. if (!loadedModel) loadedModel = osgDB::readRefNodeFile("glider.osgt"); // create a room made of foor walls, a floor, a roof, and swinging light fitting. osg::ref_ptr rootnode = createRoom(loadedModel); // run optimization over the scene graph osgUtil::Optimizer optimzer; optimzer.optimize(rootnode); // add a viewport to the viewer and attach the scene graph. viewer.setSceneData(rootnode); // create the windows and run the threads. viewer.realize(); viewer.getCamera()->setCullingMode( viewer.getCamera()->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING); return viewer.run(); }