osg:多方位观察牛~

透视投影与正视投影图:

正视投影正上方观察牛的代码:

#include <osg/Camera>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>

osg::Camera* createBirdsEye( const osg::BoundingSphere& bs )
{
    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
    camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
    
    double viewDistance = 2.0 * bs.radius();
    double znear = viewDistance - bs.radius();
    double zfar = viewDistance + bs.radius();
    float top = bs.radius();
    float right = bs.radius();
    float bottom = top;
    float left = right;
    //osg左手系坐标(z+向上,x+向右,y+向里)

    camera->setProjectionMatrixAsOrtho( -left, right, -bottom, top, znear, zfar );//设置正投影

    //牛的身长变短了(在视口大小没有变化的情况下,加大left和right(原本是6.3),牛的左右相对于裁剪区域来说,就缩小了,我是这么理解。)
    //camera->setProjectionMatrixAsOrtho( -10, 10, -bottom, top, znear, zfar );

    //牛的身长变窄了(同上理)
    //camera->setProjectionMatrixAsOrtho( -left, right, -20, 20, znear, zfar );

    //改变了znear和zfar,好像没什么变化,为什么呢,待找答案。****
     //camera->setProjectionMatrixAsOrtho( -left, right, -bottom, top, 1, 1 );

    /********* openGL解释***************************************************************************
        setProjectionMatrixAsOrtho(left,right,bottom,top,zNear,zFar);

        left和right表示最小和最大x值,top和bottom是最小和最大的y值,near和far是最小和最大的z值。

        left:裁剪区域最左边的坐标。
        right:裁剪区域最右边的坐标。

        bottom:最底部的坐标。
        top:最顶部的坐标。

        near:从原点距离观察者的最小位置。
        far:从原点距离观察者的最大位置。
    **************************************************************************************************/
    
    osg::Vec3d upDirection( 0.0,1.0,0.0 );
    osg::Vec3d viewDirection( 0.0,0.0,1.0 );
    osg::Vec3d center = bs.center();
    osg::Vec3d eyePoint = center + viewDirection * viewDistance;
    //从前面看牛
    //eyePoint.set(0.77,-10,0.5);

    //从牛头看牛
    //upDirection.set(0.0,0.0,1.0);
    //eyePoint.set(10,-0.4,0.5);

    //从牛下巴看牛
    //upDirection.set(1.0,0.0,-1.0);
    //eyePoint.set(100,-0.4,-100);

    camera->setViewMatrixAsLookAt( eyePoint, center, upDirection );//相机位置(眼睛位置,眼睛看到的场景中心位置,视点向上的量)
    //eyePoint(0.77,-0.4,12.7) center(0.77,-0.4,0.0) upDirection(0,1,0) zfar = 19,redius = 6.3
    
    return camera.release();
}

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::Node* model = osgDB::readNodeFiles( arguments );
    if ( !model ) model = osgDB::readNodeFile( "cow.osg" );
    
    osg::Camera* camera = createBirdsEye( model->getBound() );
    camera->addChild( model );
    
    osgViewer::Viewer viewer;
    viewer.setSceneData( camera );
    viewer.setUpViewInWindow(40,40,800,600);
    return viewer.run();
}

代码执行效果:

  

放开代码中相应的注释,可以看到下面的效果:

从前面看牛

    

从牛头看牛:

  

从牛下巴看牛:

  

再加入一头牛,使两头牛的坐标分别为(0.0,-10.0,0.0)、(0.0,-30.0,0.0),改用透视投影,视点的坐标为(0.0,-50.0,5)。代码如下:

 1 #include <osg/Camera>
 2 #include <osgDB/ReadFile>
 3 #include <osgViewer/Viewer>
 4 #include <osg/PositionAttitudeTransform>
 5 
 6 osg::Camera* createBirdsEye( const osg::BoundingSphere& bs )
 7 {
 8     osg::ref_ptr<osg::Camera> camera = new osg::Camera;
 9     camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
10     camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
11     
12     double viewDistance = 2.0 * bs.radius();
13     double znear = viewDistance - bs.radius();
14     double zfar = viewDistance + bs.radius();
15     float top = bs.radius();
16     float right = bs.radius();
17     float bottom = top;
18     float left = right;
19     //osg左手系坐标(z+向上,x+向右,y+向里)
20 
21     //透视投影
22     camera->setProjectionMatrixAsFrustum( -left, right, -bottom, top, 18, 39.2 );
23 
24     osg::Vec3d upDirection( 0.0,1.0,0.0 );
25     osg::Vec3d viewDirection( 0.0,0.0,1.0 );
26     osg::Vec3d center = bs.center();
27     osg::Vec3d eyePoint = center + viewDirection * viewDistance;
28     //从前面看牛(视点)
29     eyePoint.set(0.0,-50.0,5.0);
30 
31     //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
32     camera->setViewMatrixAsLookAt( eyePoint, center, upDirection );//相机位置(眼睛位置,眼睛看到的场景中心位置,视点向上的量)
33     // center(0.77,-0.4,0.0) upDirection(0,1,0) zfar = 19,redius = 6.3
34     
35     return camera.release();
36 }
37 
38 int main( int argc, char** argv )
39 {
40     osg::ArgumentParser arguments( &argc, argv );
41     osg::Node* model = osgDB::readNodeFiles( arguments );
42     if ( !model ) model = osgDB::readNodeFile( "cow.osg" );
43 
44     
45     osg::Camera* camera = createBirdsEye( model->getBound() );
46 
47     //牛1
48     osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;
49     pat->setPosition(osg::Vec3(0.0,-30.0,0.0));
50     pat->addChild(model);
51 
52     //牛2
53     osg::ref_ptr<osg::PositionAttitudeTransform> pat2 = new osg::PositionAttitudeTransform;
54     pat2->setPosition(osg::Vec3(0.0,-10.0,0.0));
55     pat2->addChild(model);
56 
57 
58 
59     camera->addChild(pat);
60     camera->addChild(pat2);
61 
62     osgViewer::Viewer viewer;
63     viewer.setSceneData( camera );
64     viewer.setUpViewInWindow(40,40,800,600);
65     return viewer.run();
66 }

运行效果:

  

 如果打开31行的注释(如果不打开这个注释,osg默认对near、far不做裁剪),其运行效果如下:

  

可以看到后边的牛只显示了半个,另外半个被裁剪掉了,图解如下:

  

黄色区域为near、far所表示的裁剪区域,牛2被裁剪了。

 (有五个窗口)单个视景器多个从相机看一头牛:

  

上述效果实现代码:

#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/PositionAttitudeTransform>

//为相机设置图形设备对象并返回相机
osg::Camera* createCamera( int x, int y, int w, int h )
{
    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    traits->windowDecoration = false;//是否设置标题栏,这里设定为否,有标题栏的话,中间会被标题难割开。
    traits->x = x;//左上角坐标x
    traits->y = y;//左上角坐标y
    traits->width = w; 
    traits->height = h;
    traits->doubleBuffer = true;
    
    osg::DisplaySettings* ds = osg::DisplaySettings::instance();
    traits->alpha = ds->getMinimumNumAlphaBits();
    traits->stencil = ds->getMinimumNumStencilBits(); //模板缓存
    traits->sampleBuffers = ds->getMultiSamples();//重采样缓存
    traits->samples = ds->getNumMultiSamples();//重采样数

    //构建图形设备对象
    osg::ref_ptr<osg::GraphicsContext> gc =osg::GraphicsContext::createGraphicsContext( traits.get() );
    
    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
    camera->setGraphicsContext( gc.get() );//设置相机的图形设备对象
    camera->setViewport( new osg::Viewport(0,0, traits->width, traits->height) );
    return camera.release();
}

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::Node* model = osgDB::readNodeFiles( arguments );
    if ( !model ) model = osgDB::readNodeFile( "cow.osg" );
    osgViewer::Viewer viewer;
    //不做投影偏移的牛
    viewer.addSlave( createCamera(900,300,600,450), osg::Matrixd::translate( 0.0,0,0.0), osg::Matrixd() );

    viewer.addSlave( createCamera(50,50,400,300), osg::Matrixd::translate( 1.0,-1.0,0.0), osg::Matrixd() );
    viewer.addSlave( createCamera(455,50,400,300), osg::Matrixd::translate(-1.0,-1.0,0.0), osg::Matrixd() );
    viewer.addSlave( createCamera(50,355,400,300), osg::Matrixd::translate( 1.0,1.0,0.0), osg::Matrixd() );
    viewer.addSlave( createCamera(455,355,400,300), osg::Matrixd::translate(-1.0, 1.0,0.0), osg::Matrixd() );
    viewer.setSceneData( model );
    osg::Vec3d center = model ->getBound().center();
    return viewer.run();
}

总结:一头牛,添加了五个从相机去观察,每个相机对应一个图像设备窗口。 

(有两窗口)用多视景器多方位观察一头牛:

  

实现代码:

  

#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgViewer/CompositeViewer>
#include <osg/PositionAttitudeTransform>

//回调函数,让其不断的旋转
class RotateCallback : public osg::NodeCallback
{
public:
    RotateCallback() : _rotateZ(0.0) {}

    virtual void operator()( osg::Node* node, osg::NodeVisitor* nv )
    {
        osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>( node );
        if ( pat )
        {
            osg::Quat quat( osg::DegreesToRadians(_rotateZ), osg::Z_AXIS );
            pat->setAttitude( quat );
            _rotateZ += 1.0;
        }
        traverse( node, nv );//访问器的下一个节点
    }

protected:
    double _rotateZ;
};

osg::Camera* createCamera( const osg::BoundingSphere& bs )
{
    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
    camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF );

    double viewDistance = 2.0 * bs.radius();
    double znear = viewDistance - bs.radius();
    double zfar = viewDistance + bs.radius();
    float top = bs.radius();
    float right = bs.radius();
    float bottom = top;
    float left = right;
    //osg左手系坐标(z+向上,x+向右,y+向里)

    //透视投影
    camera->setProjectionMatrixAsFrustum( -left, right, -bottom, top, znear, zfar );

    osg::Vec3d upDirection( 0.0,0.0,1.0 );
    osg::Vec3d center = bs.center();
    osg::Vec3d eyePoint ;
    eyePoint.set(0.0,0.0,10.0);

    camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
    camera->setViewMatrixAsLookAt( eyePoint, center, upDirection );//相机位置(眼睛位置,眼睛看到的场景中心位置,视点向上的量)
    return camera.release();
}

int main( int argc, char** argv )
{
    //读牛
    osg::ArgumentParser arguments( &argc, argv );
    osg::Node* model = osgDB::readNodeFiles( arguments );
    if ( !model ) model = osgDB::readNodeFile( "cow.osg" );

    //创建投影相机
    osg::Camera* camera = createCamera( model->getBound() );

    //给牛模型设置回调,让其自动旋转
    osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;
    pat->addChild( model );
    pat->setUpdateCallback( new RotateCallback );

    camera->addChild(pat.get());

    //视景器1显示第一个有设置特定相机的牛
    osg::ref_ptr<osgViewer::View> view1 = new osgViewer::View;
    view1->setUpViewInWindow( 0, 50, 320, 240 );
    view1->setSceneData( camera );

    //视景器2显示第二个默认相机的牛
    osg::ref_ptr<osgViewer::View> view2 = new osgViewer::View;
    view2->setUpViewInWindow( 340, 50, 320, 240 );
    view2->setSceneData( pat.get() );

    //多视景器进行管理并渲染
    osgViewer::CompositeViewer compositeViewer;
    compositeViewer.addView( view1.get() );
    compositeViewer.addView( view2.get() );
    return compositeViewer.run();
}

总结:一个图像设备,多视景器管理着两个视景器,每个视景器对应一个相机(camera本身也是一个矩阵)。 

单窗口显示两头牛:

  

  实现代码:

  

#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/PositionAttitudeTransform>
#include <osgViewer/CompositeViewer>
int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::Node* model = osgDB::readNodeFiles( arguments );
    if ( !model ) model = osgDB::readNodeFile( "cow.osg" );


    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    traits->windowDecoration = false;//是否设置标题栏,这里设定为否,有标题栏的话,中间会被标题难割开。
    traits->x = 0;//左上角坐标x
    traits->y = 0;//左上角坐标y
    traits->width = 800; 
    traits->height = 800;
    traits->doubleBuffer = true;

    osg::DisplaySettings* ds = osg::DisplaySettings::instance();
    traits->alpha = ds->getMinimumNumAlphaBits();
    traits->stencil = ds->getMinimumNumStencilBits(); //模板缓存
    traits->sampleBuffers = ds->getMultiSamples();//重采样缓存
    traits->samples = ds->getNumMultiSamples();//重采样数

    //构建图形设备对象
    osg::ref_ptr<osg::GraphicsContext> gc =osg::GraphicsContext::createGraphicsContext( traits.get() );

    osgViewer::CompositeViewer *v = new osgViewer::CompositeViewer();
    osg::ref_ptr<osg::Group> g = new osg::Group;
    osg::ref_ptr<osg::Group> g2 = new osg::Group;

    osgViewer::View  *v1 = new osgViewer::View();
    osgViewer::View  *v2 = new osgViewer::View();

    v->addView(v1);
    v->addView(v2);

    v1->setSceneData(model);
    v2->setSceneData(model);

    v1->getCamera()->setViewport(new osg::Viewport(0,0,400,600));
    v1->getCamera()->setGraphicsContext(gc.get());

    v2->getCamera()->setViewport(new osg::Viewport(410,0,400,600));
    v2->getCamera()->setGraphicsContext(gc.get());

    return v->run();
}
原文地址:https://www.cnblogs.com/airduce/p/9835892.html