osg三维世界中,会使用到几个不同的坐标系统,下面会讲解几个常用概念,通过使用照相机拍照的过程进行类比:
一、模型视点变换
这个过程就相当于我们拍照时调整被拍摄物体的位置和姿态以及调整相机的位置和姿态。物体的位置和姿态成为模型变换;相机的位置和姿态称为视点变换,这两种变换在一起统称为模型视点变换。
相机的位置和姿态又三个参数来决定:视点位置eye、参考点位置center和视点向上位置up。
在拍摄一个物体的时候,移动物体的位置姿态和移动相机的位置姿态可以达到同样的效果。比如物体向X轴方向移动了10米,相当于相机在X轴方向上移动了-10米。也就是说模型变换和视点变换是互逆的。
经过模型视点变换之后的场景有世界坐标系装换成相机坐标系。
二、投影变换
相当于在拍照时选择镜头和调整焦距等,将场景景物投射到二维底片的过程。例如:增加相机拍摄距离的镜头称为长焦镜头,增大视角的镜头称为广角镜头。在OSG中三维的投影变换,主要的操作对象是一个立方体或者棱台形状的视景体。
在视景体之外的场景不会被投影到二维平面上,视景体的远近裁切平面相当于长短焦镜头的作用,而棱台状视景体还可以通过改变棱台上底面与试点的距离来改变视角的范围,起到广角镜头的作用。
立方体形状的视景体称为平行视景体,其结果是生成一个正射投影矩阵。
棱台式视景体又称为视锥体,主要用来透视投影。即:离视点近的物体看上去较大,离视点远的物体看上去较小。
投影变换相当于把相机坐标系装换成投影坐标系。
三、视口变换
场景投影变换的图像反映到屏幕窗口上去的,相当于把底片冲洗出照片来。还可以将照片进行放大或者缩小,以及拉伸等。最终将场景变换到窗口坐标系中。
四、相机节点
三维场景中的视点变换,也就是Camera。视点矩阵又称观察矩阵,它负责将世界坐标系装换成相机坐标系。同时相机节点还负责构建观察的投影矩阵和窗口矩阵,实现三维场景到二维场景的映射;并且通过观察矩阵、投影矩阵和窗口矩阵的不断变化实现三维浏览和场景的漫游。
多个相机节点允许共享一颗子节点书结构,也就是多台相机可以从不同的角度、以不同的方式观察同一个模型物体。
Camera节点和普通的节点有很大的不同,它是场景裁剪和渲染过程的一个重要载体。而普通的节点只是一个保存场景数据的工具。一个相机的所有子节点都只会被渲染到这个相机所对应的图形设备中。相机的设置参数也决定了它所采用的场景裁剪方法及其子节点是否在裁剪过程中被剔除等属性。
设置一个相机的正交投影从场景正上方观看模型场景,如图所示。
void createCamera() {
osg::ref_ptr<osg::Group> root = new osg::Group;
osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile("cow.osgt");
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
//清除颜色和深度缓存,这个相机在渲染子场景是将会覆盖之前任何相机的渲染数据
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//设置相机的坐标系,ABSOLUTE_RF相机所有的变换矩阵和观察/投影矩阵都是相对于世界坐标系的,不会受到上一级矩阵的影响
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
osg::BoundingSphere bs = cowNode->getBound();
float r = bs.radius();
float near = r;
float far = 3 * r;
//设置正交投影
camera->setProjectionMatrixAsOrtho(-r, r, -r, r, near, far);
//沿着X轴的正方向观看
osg::Vec3 up = osg::Vec3(1.0, 0.0, 0.0);
//视点中心也是场景中心
osg::Vec3 center = bs.center();
//相机视点的位置
osg::Vec3 eye = osg::Vec3(0.0, 0.0, 50.0);
//设置观察矩阵
camera->setViewMatrixAsLookAt(eye, center, up);
camera->addChild(cowNode);
root->addChild(camera);
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
viewer->addEventHandler(new osgViewer::WindowSizeHandler());
viewer->addEventHandler(new osgViewer::StatsHandler());
viewer->setSceneData(root.get());
viewer->realize();
viewer->run();
}
aaa