透视投影与正视投影图:
正视投影正上方观察牛的代码:
#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(); }