所谓“入坑”,只不过为本身的不熟练找借口而已。
如今学习OSG已经三周,跟着书、视频作些简简单单的小demo而已,有时候真是感受本身无从下手。
不晓得的本身算不算是转行,以前研究点云数据处理
,有一点点opengl的基础,虽然说工做进入某高校,项目是某沉浸式VR系统开发,目前为止也止有我一我的在搞!
。。。。
有些扯远了,上述纯属瞎扯淡,毫无逻辑。。。。。。node
断断续续的用了大半个月的osg,给个人感受就是:出了问题不知如何下手处理!好比对某图形节点设置状态,可是可视化出来却没有本身想要的效果,程序也不报错。
之因此会有上述烦恼,可能缘由在于本身对opengl和计算机图形学并不深刻了解,理论上的匮乏形成了实际问题没法有效解决,这是其一;其二,或许是我的经验不够,思考很少,在学校习惯了被老师同窗指点,本身缺不去深刻考虑,经验须要积累,在之后工做中要多思考,多感悟,多总结,不怕错
坏了,又有些扯远了,仍是回到osg吧!记性很差,就多记录一下本身的小收获吧!segmentfault
osg中,当设置某节点的渲染状态时,该状态会赋予当前节点及其子节点
,所以,若要实现多节点多状态渲染时,必定注意节点之间的父子关系,最好一个节点设置一个本身想要的状态,除非父节点及其子节点的渲染状态同样。
渲染状态的管理经过osg::StateSet
管理,能够将其添加到任意的节点(node、group、geode等)和DrawAble类。如要设置渲染状态的值,须要:数组
osg::StateSet *state = obj->getOrCreatStateSet() ;
其中,obj
能够是节点或Drawable实例,且:getOrCreatStateSet()
方法是在osg::Node中声明的,这就意味着geode或group均可以使用。state>setMode(GL_LIGHTING,osg::StateAttribute::OFF);//关闭灯光状态 state->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);//设置纹理 //开启shader osg::ref_ptr<osg::Program> shaderProg = new osg::Program; shaderProg->addShader(new osg::Shader(osg::Shader::VERTEX,vertexShader)); shaderProg->addShader(new osg::Shader(osg::Shader::FRAGMENT,fragShader)); state->setAttributeAndModes(shaderProg,osg::StateAttribute::ON); //设置渲染属性和模式 ->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);//管理深度测试 //设置渲染顺序,第一个参数越小,渲染越靠前,默认第一个参数为 -1 state->setRenderBinDetails(10, "RenderBin"); //默认渲染排序 state->setRenderBinDetails(100,"DepthSortedBin"); //由远到近 state->setRenderBinDetails(1000,"TraversalOrderBin"); //按遍历顺序 //开启混合透明度 state->setMode(GL_BLEND,osg::StateAttribute::ON); //设置渲染模式
等等等等缓存
显然,geode是几何节点,且是叶节点,geometry类管理osg中各类各样的几何体。
我的总结:在使用geode画osg自带的几何图形时,老是:ide
//画个圆柱 osg::TessellationHints *hins = new osg::TessellationHints; hins->setDetailRatio(1.0f);//设置圆柱的精度为0.1,值越小,精度越小 osg::ref_ptr<osg::Cylinder> cy = new osg::Cylinder; //圆柱 osg::ref_ptr<osg::ShapeDrawable> sd = new osg::ShapeDrawable(cy); //直接用几何对象初始化shapedrawable实例 cy->setCenter(osg::Vec3(400.0,300,0)); cy->setHeight(0.1); cy->setRadius(150); sd->setTessellationHints(hins); geode->addDrawable(sd); //必不可少(到这里才真正绘制) /*以上啰嗦代码固然能够这样写:*/ geode->addDrawable(new osg::ShapeDrawable(osg::Cylinder(center),Radius,Height),teseel); //画个盒子 osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints; //设置精度 hints->setDetailRatio(0.1); osg::ref_ptr<osg::ShapeDrawable> shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(x,y,z),长,宽,高),hints.get()); geode->addDrawable(shape);
TessellationHints(精度)参数对圆柱几何的影响以及shapedrawable继承关系:!函数
自定义几何体时:学习
osg::ref_ptr<osg::Geode> geo = new osg::Geode; osg::ref_ptr<osg::Geometry> geom = new osg::Geometry(); osg::ref_ptr<osg::Vec3Array> vex = new osg::Vec3Array; osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array; osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array; osg::ref_ptr<osg::LineWidth> width = new osg::LineWidth; //线宽 //设置法向量及其绑定方式 geom->setNormalArray(normal,osg::Array::Binding::BIND_OVERALL); normal->push_back(osg::Vec3(0.0,-1.0,0.0)); //设置顶点 vex->push_back(osg::Vec3(-10.5,5,-10.0)); vex->push_back(osg::Vec3(10.5,5,-10.0)); vex->push_back(osg::Vec3(10.0,5,10.0)); vex->push_back(osg::Vec3(-10.0,5,10.0)); geom->setVertexArray(vex.get()); //设置颜色 color->push_back(osg::Vec4(0.1,0.2,0.3,0.5)); color->push_back(osg::Vec4(1.1,0.9,0.3,0.50)); color->push_back(osg::Vec4(0.2,0.5,0.3,0.50)); color->push_back(osg::Vec4(0.4,0.2,0.7,0.50)); geom->setColorArray(color); geom->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX); //设置纹理绑定方式 osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints; hints->setDetailRatio(0.1); //设置透明度 geom->getOrCreateStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON); /*osg::DrawArrays至关于对opengl中glDrawarray的封装*/ geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::Mode::LINE_LOOP,0,4)); //设置顶点的关联方式(此处,以线段的方式链接) //设置线宽 width->setWidth(20.0); geom->getOrCreateStateSet()->setAttributeAndModes(width); geo->addDrawable(geom.get());
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::Mode::LINE_LOOP,0,4));
的基本图元及drawable继承方式:测试
固然,上一篇入门文章viewer::run()多多少少也和camera有关。如今算是进一步吧。
先看看camera的继承关系图
spa
很明显,camera继承自node、group、transform,也就是说他们具备的属性,camera也具备。设计
就像上篇文章所述,osgviewer->run()会自动设置一个场景漫游器,该漫游器包含了透视投影矩阵、视口大小、屏幕宽高比以及远近裁剪面、摄像机位置等等参数,若是想要修改远近裁剪面应该首先关闭osg的自动判断远近裁剪面的函数:
viewer->getCamera()->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR); viewer->getCamera()->setProjectionMatrixAsPerspective(fovy,aspectRatio,zNear,zFarSurface);
osgUtil::CullVisitor
是osg的场景拣选访问器。
osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); if (!wsi) return ; unsigned int height,width; wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0),width,height); //获取屏幕的长宽 //设置图形环境特性 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(); traits->x = 0; traits->y = 0; traits->width = width; traits->height = height; traits->windowDecoration = false; //窗口修饰 关 traits->doubleBuffer = true; //是否支持双缓存 traits->sharedContext = false; osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits); if (!gc.valid()) { return ; } gc->setClearMask(GL_COLOR_BUFFER_BIT); gc->setClearColor(osg::Vec4(0.5,0.5,0.5,1.0)); //设置全局上下文的背景色 osg::ref_ptr<osg::Camera> master = new osg::Camera; master->setGraphicsContext(gc); viewer->addSlave(master); //将相机添加到场景中。
在HUD和RTT中,建立相机是很是重要的,HUD的相机要最后渲染,防止被覆盖
HUD相机:
osg::Camera *CreatTextHUD() { osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setViewMatrix(osg::Matrix::identity()); //设置视图矩阵为单位矩阵 camera->setAllowEventFocus(false); //不响应其余鼠标事件 camera->setRenderOrder(osg::Camera::POST_RENDER);//最后渲染 camera->setClearMask(GL_DEPTH_BUFFER_BIT); camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);//设置参考帧 为绝对坐标系 camera->setProjectionMatrixAsOrtho2D(0,1024,0,768); //设置二维正交投影 osg::ref_ptr<osg::Geode> geode = new osg::Geode; geode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);//关闭灯光状态 osg::ref_ptr<osgText::Text> text = new osgText::Text; geode->addDrawable(text); text->setPosition(osg::Vec3(0,0,0)); text->setFont("simsun.ttc"); //设置为宋体 text->setText(L"宋体 测试"); //必定不要忘记加“L”字符 text->setCharacterSize(50); camera->addChild(geode); return camera.release(); }
RTT相机
void CreatRTT(osgViewer::Viewer *viewer) { osg::ref_ptr<osg::Group> group = new osg::Group; osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("nathan.osg"); group->addChild(node); //设置图形上下文 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 0; traits->y = 0; traits->width = 800; traits->height = 600; traits->sharedContext = false; traits->doubleBuffer = true; traits->windowDecoration = false; osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits); //建立主相机 osg::ref_ptr<osg::Camera> master = new osg::Camera; master->setGraphicsContext(gc); master->setViewport(0,0,800,600); viewer->addSlave(master); //建立rtt相机 osg::ref_ptr<osg::Camera> rttCamera = new osg::Camera; rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); rttCamera->setGraphicsContext(gc); rttCamera->setViewport(0,0,800,600); rttCamera->addChild(node); //添加相机并设置瞄准镜的放大倍数为8倍,最后false表示:该添加入的相机不接受主窗口任何内容。 viewer->addSlave(rttCamera,osg::Matrix::scale(8,8,8),osg::Matrix::identity(),false); osg::Texture2D *t2d = new osg::Texture2D; t2d->setInternalFormat(GL_RGBA); rttCamera->attach(osg::Camera::COLOR_BUFFER,t2d); group->addChild(CreatHUD(t2d)); viewer->setSceneData(group); return ; }
上边的函数实际上是建立了一个瞄准镜的效果:
自我感受(或许并不对,仅限于目前认知水平)
:osg添加多相机主要功能是为了多窗口多视图显示。一个相机可以渲染多个视图,一个场景可以添加多个相机,多个相机可以实现从不一样角度、方位、视角观察同时观察同一个模型。
viewer->setCameraManipulator(osgGA::CameraMaipulator *)
,和viewer->addEventHandler(osgGA::EventHandler *)
,前者的函数参数是osgGA::CameraMaipulator *
类型,后者参数为osgGA::EventHandler *
类型,且osgGA::CameraMaipulator *
是继承自osgGA::EventHandler *
的。
对比:
设置漫游的本质就是修改主相机的各类参数矩阵,并将修改后的参数返回场景中的主相机
(影响的最顶层的相机节点).其实本质上)
:从类的继承关系来看,漫游器是从事件处理类中继承而来,若是事件处理函数我的写得足够好、足够丰富,应该可以替代漫游器的,这也是为何二者在不少时候添加自定义类时程序并不报错,但就是达不到预想效果的缘由。矩阵的自动返回操做
,从而控制相机,其矩阵自动返回的主要函数是:virtual void setByMatrix(const osg::Matrixd& matrix) = 0; //设置相机的位置姿态矩阵 virtual void setByInverseMatrix(const osg::Matrixd& matrix) = 0; //设置相机的视图矩阵 virtual osg::Matrixd getMatrix() const = 0; //获取相机的姿态矩阵 virtual osg::Matrixd getInverseMatrix() const = 0;
这也就是为何自定义的漫游器必须重载这四个函数的缘由所在。(事件处理不须要重载这几个函数)
关系:
若是总结为一句话,应该是:CameraManipulator是EventHanler的子类,EventHandler自己也能够实现漫游功能,只不过osg开发者为了更加丰富便捷的控制事件与漫游,从而单独设计了一个漫游操做器,以便使用者可以更加轻松方便的控制本身的场景。
清除camera中的深度缓存:camera->setclearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH)
;
注:以上内容只是本身在比较皮毛的层面的记录,并无过多的深刻源码解析,内容或许有误,恳请指正留言,不胜感激!
另:有作点云处理研究的朋友也可多多交流。