osg指南针 Compass 类 源码

本文介绍了一个基于OpenSceneGraph (OSG) 的指南针组件实现细节,该组件能够显示方向信息并随场景旋转。文章深入讲解了如何利用OSG API创建定制化的视觉元素,并通过代码示例展示了指南针的设计和集成。

//**********************Compass.h**********************

#include <osg/MatrixTransform>
#include <osg/Projection>
#include <osg/Vec4>

#include <osg/NodeVisitor>
#include <osg/ClipPlane>
#include <osg/Viewport>


class Compass : public osg::Projection
{
    public:
        Compass( osg::Viewport *vp);

    protected:

        virtual void traverse(osg::NodeVisitor&);
        //static const osg::Vec4 color;

    private:
        osg::ref_ptr<osg::MatrixTransform> _tx;
        osg::ref_ptr<osg::MatrixTransform> _ltx;
        osg::ref_ptr<osg::ClipPlane> _clipPlane;

        osg::ref_ptr<osg::Geode> _makeGeode();
        osg::ref_ptr<osg::Geode> _lineGeode();

};


//********************************Compass.cpp********************************

#include <stdio.h>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/MatrixTransform>
#include <osg/LineWidth>
#include <osgText/Text>
#include <osgUtil/CullVisitor>
#include <osg/ClipPlane>

#include "Compass.h"

//const osg::Vec4 Compass::color = osg::Vec4( 0, 0.6, 0, 1.0 );

osg::Vec4 color( 0, 0.6, 0, 1.0 );

Compass::Compass(osg::Viewport *vp)
{
    osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;

    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE );
    stateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE );
    stateSet->setTextureMode( 0, GL_TEXTURE_2D, osg::StateAttribute::OFF );
    stateSet->setRenderBinDetails( 110, "RenderBin" );

    stateSet->setAttribute( vp ); 
    double ar = 120.0/640.0;
    setMatrix( osg::Matrix::frustum( -0.35, 0.35, -0.35 * ar, 0.35 * ar, 1.0, 10000.0 ));
    //setMatrix( osg::Matrix::ortho2D( -1, 1, 0, 2 * ar ));

    _clipPlane =  new osg::ClipPlane( 0, osg::Plane( 0.0, -1.0, 0.0, 0.0 ));
    stateSet->setAttributeAndModes( _clipPlane.get() );
    stateSet->setAttributeAndModes( new osg::LineWidth( 4.0 ));

    setStateSet( stateSet.get());
    setCullingActive( false );

    _tx = new osg::MatrixTransform;
    _tx->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
    _tx->addChild( _makeGeode().get() );
    addChild(_tx.get());

    _ltx = new osg::MatrixTransform;
    _ltx->addChild(_lineGeode().get());
    _tx->addChild( _ltx.get() );
}

osg::ref_ptr<osg::Geode> Compass::_lineGeode()
{
    osg::ref_ptr<osg::Vec3Array> coords  = new osg::Vec3Array;
    coords->push_back( osg::Vec3(-0.03, -1.0, -0.07) );
    coords->push_back( osg::Vec3( 0.0,  -1.0, -0.01) );
    coords->push_back( osg::Vec3( 0.0,  -1.0, -0.01) );
    coords->push_back( osg::Vec3( 0.03, -1.0, -0.07) );

    /*
    coords->push_back( osg::Vec3(-0.03, -1.0,  0.15) );
    coords->push_back( osg::Vec3( 0.0,  -1.0,  0.11) );
    coords->push_back( osg::Vec3( 0.0,  -1.0,  0.11) );
    coords->push_back( osg::Vec3( 0.03, -1.0,  0.15) );
    */

    osg::ref_ptr<osg::Vec4Array> colors   = new osg::Vec4Array;
    colors->push_back( color );

    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
    geometry->setVertexArray(coords.get());
    geometry->setColorArray(colors.get());
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
    geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, coords->size()));

    osg::ref_ptr<osg::Geode> geode = new  osg::Geode;
    geode->addDrawable( geometry.get() );

    return geode;
}

osg::ref_ptr<osg::Geode> Compass::_makeGeode()
{
    osg::ref_ptr<osg::Vec3Array> coords  = new osg::Vec3Array;
    osg::ref_ptr<osg::Vec4Array> colors   = new osg::Vec4Array;

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;

    for( int i = 0; i < 360; i += 5 )
    {
        double a = osg::DegreesToRadians( double(i-180) );

        coords->push_back( osg::Vec3( sin(-a), cos(-a), 0.0 ));
        if( !(i%10 ) )
            coords->push_back( osg::Vec3( sin(-a), cos(-a), 0.06 ));
        else
            coords->push_back( osg::Vec3( sin(-a), cos(-a), 0.02 ));

        if( !(i % 30 ))
        {
            osg::ref_ptr<osgText::Text> text = new osgText::Text;
            text->setFont( "fonts/arial.ttf" );
            text->setAlignment( osgText::Text::CENTER_CENTER );
            text->setFontResolution(100,100);
            text->setCharacterSize( 0.1 );
            text->setColor( color );

            osg::Matrix m = osg::Matrix::rotate( osg::PI*0.5, 1, 0, 0 ) *
                            osg::Matrix::rotate( osg::PI + a, 0, 0, 1 );
            osg::Quat q;
            q.set( m );
            text->setRotation( q );

            char buff[8];

            (i == 0 )   ?  sprintf( buff, "N" ):
            (i == 90 )  ?  sprintf( buff, "W" ):
            (i == 180 ) ?  sprintf( buff, "S" ):
            (i == 270 ) ?  sprintf( buff, "E" ): sprintf( buff, "%2d", (((360-i)%360)/10));

            text->setText( buff );
            text->setPosition( osg::Vec3( sin(-a),  cos(-a), 0.1 ));

            geode->addDrawable( text.get() );
        }
    }

    colors->push_back( color );

    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
    geometry->setVertexArray(coords.get());
    geometry->setColorArray(colors.get());
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
    geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, coords->size()));

    //geometry->getOrCreateStateSet()->setAttributeAndModes( new osg::LineWidth( 4.0 ));
    geode->addDrawable( geometry.get() );

    return geode;
}


void Compass::traverse(osg::NodeVisitor&nv)
{
    if( nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR )
    {
        osgUtil::CullVisitor *cv = dynamic_cast<osgUtil::CullVisitor *>(&nv);
        osg::Matrix ivm = cv->getState()->getInitialViewMatrix();
        ivm(3,0) = ivm(3,1) = ivm(3,2) = 0.0;
        osg::Vec3 v = osg::Vec3(0,1,0) * ivm * osg::Matrix::rotate( osg::PI*0.5, 1, 0, 0 );
        double a = atan2( v[0], v[1] );
        _tx->setMatrix( osg::Matrix::rotate( -a, 0, 0, 1 ) * 
                        osg::Matrix::translate( 0.0, 3.0, -0.05 ) *
                        osg::Matrix::rotate( -osg::PI*0.5, 1, 0, 0 ) );

        osg::Vec4d cp = osg::Vec4d(0.0, -1.0, 0.0, -0.75 ) * osg::Matrix::rotate( a, 0, 0, 1 );
        _clipPlane->setClipPlane( cp );

        _ltx->setMatrix( osg::Matrix::rotate(  a, 0, 0, 1 ) );


    }
    osg::Projection::traverse( nv );
}


//*************main.cpp***********************

#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osgViewer/Viewer>

#include <osg/NodeCallback>
#include <osg/StateSet>
#include <osg/LightModel>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/GUIEventHandler>
#include <osgViewer/ViewerEventHandlers>
#include "Compass.h"



int main(int argc, char **argv)
{
    // Parse command line arguments 
    osg::ArgumentParser args( &argc, argv );
    osg::ref_ptr<osg::Group> root = new osg::Group;


    // Set up the viewer
    osgViewer::Viewer viewer(args);

    // Set the clear color to black
   // viewer.getCamera()->setClearColor(osg::Vec4(0,0,0,1));

    // Use a default camera manipulator
    osgGA::TrackballManipulator* manip = new osgGA::TrackballManipulator;
    viewer.setCameraManipulator(manip);
    // Initially, place the TrackballManipulator so it's in the center of the scene
    manip->setHomePosition(osg::Vec3(0,0,0), osg::Vec3(0,1,0), osg::Vec3(0,0,1));
    manip->home(0);

    // Add some useful handlers to see stats, wireframe and onscreen help
    viewer.addEventHandler(new osgViewer::StatsHandler);
    viewer.addEventHandler(new osgGA::StateSetManipulator(root->getOrCreateStateSet()));
    viewer.addEventHandler(new osgViewer::HelpHandler);

    // Tell the viewer what to display for a help message
    viewer.getUsage(*args.getApplicationUsage());


    // Load up the models specified on the command line
    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("dumptruck.osg");
    if( model.valid() )
        root->addChild( model.get() );

    // Add a compass model so we can see which way we are facing
    osg::ref_ptr<osg::Viewport> vp = new osg::Viewport( 320, 20, 640, 100 );
    root->addChild( new Compass( vp.get() ));


    // Set some acceptable defaults.
    double latitude = 38.4765;                                  // San Francisco, California
    double longitude = -122.493;
 
    //Experiment with setting the LightModel to very dark to get better sun lighting effects
    {
        osg::ref_ptr<osg::StateSet> sset = root->getOrCreateStateSet();
        osg::ref_ptr<osg::LightModel> lightModel = new osg::LightModel;
        lightModel->setAmbientIntensity( osg::Vec4( 0.0025, 0.0025,0.0025, 1.0 ));
        sset->setAttributeAndModes( lightModel.get() );
    }


    osgUtil::Optimizer optimizer;
    optimizer.optimize(root.get());

    // set the scene to render
    viewer.setSceneData(root.get());


    // Realize the viewer
    viewer.realize();
    while( !viewer.done() )
    {
        viewer.frame();
    }
    return 0;
}


见图:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值