osglight解析

来源:互联网 发布:我国关于网络诈骗法律 编辑:程序博客网 时间:2024/05/16 14:10

osglight解析如下: 

// 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<osg::PositionAttitudeTransform*>(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);//PositionAttitudeTransform位置变换节点->旋转

               

                pat->setPosition(osg::Vec3(0.0f,0.0f,sin(phase))*_range);//PositionAttitudeTransform位置变换节点->平移

            }

       

            // 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);

   

    //MatrixTransform设置路径动画

    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)

{

    //其实是以v1,v2,v3画了一个矩形,但进行了细分.

    //也可以直接根据矩形的个点直接画,但由于插值,效果不好,颜色不纯.noXSteps=noYSteps=100改成

    //noXSteps=noYSteps=2则与直接画矩形的效果类似

 

   // 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;row<noYSteps;++row)

    {

        osg::Vec3 v = vRowStart;

        for(unsigned int col=0;col<noXSteps;++col)       

        {

            coords->push_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);

    geom->setColorBinding(osg::Geometry::BIND_OVERALL);

   

   

    for(row=0;row<noYSteps-1;++row)

    {

        osg::DrawElementsUShort* quadstrip = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);

        quadstrip->reserve(noXSteps*2);

        for(unsigned int col=0;col<noXSteps;++col)       

        {

            quadstrip->push_back((row+1)*noXSteps+col);

            quadstrip->push_back(row*noXSteps+col);

        }  

        geom->addPrimitiveSet(quadstrip);

    }

   

    // create the normals.   

    osgUtil::SmoothingVisitor::smooth(*geom);

   

    return geom;

 

}

 

 

osg::Node* createRoom(osg::Node* 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 )

{

   ......

    if (!loadedModel) loadedModel = osgDB::readNodeFile("glider.osg");

   

    // create a room made of foor walls, a floor, a roof, and swinging light fitting.

    osg::Node* rootnode = createRoom(loadedModel);

 

    viewer.setSceneData( rootnode );

   

    .....

    viewer.getCamera()->setCullingMode( viewer.getCamera()->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

 

    return viewer.run();

}

 

立体包围盒的8个点的索引号如图(如顶是(4576),前是0154):

 

Osglight完整源代码如下:

#include <osgViewer/Viewer>

 

#include <osg/Group>

#include <osg/Node>

 

#include <osg/Light>

#include <osg/LightSource>

#include <osg/StateAttribute>

#include <osg/Geometry>

#include <osg/Point>

 

#include <osg/MatrixTransform>

#include <osg/PositionAttitudeTransform>

 

#include <osgDB/Registry>

#include <osgDB/ReadFile>

 

#include <osgUtil/Optimizer>

#include <osgUtil/SmoothingVisitor>

 

#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<osg::PositionAttitudeTransform*>(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;row<noYSteps;++row)

    {

        osg::Vec3 v = vRowStart;

        for(unsigned int col=0;col<noXSteps;++col)       

        {

            coords->push_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);

    geom->setColorBinding(osg::Geometry::BIND_OVERALL);

   

   

    for(row=0;row<noYSteps-1;++row)

    {

        osg::DrawElementsUShort* quadstrip = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);

        quadstrip->reserve(noXSteps*2);

        for(unsigned int col=0;col<noXSteps;++col)       

        {

            quadstrip->push_back((row+1)*noXSteps+col);

            quadstrip->push_back(row*noXSteps+col);

        }  

        geom->addPrimitiveSet(quadstrip);

    }

   

    // create the normals.   

    osgUtil::SmoothingVisitor::smooth(*geom);

   

    return geom;

 

}

 

 

osg::Node* createRoom(osg::Node* 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::Node* loadedModel = osgDB::readNodeFiles(arguments);

   

    // if not loaded assume no arguments passed in, try use default mode instead.

    if (!loadedModel) loadedModel = osgDB::readNodeFile("glider.osg");

   

    // create a room made of foor walls, a floor, a roof, and swinging light fitting.

    osg::Node* 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();

}

 

原创粉丝点击