转载自:https://segmentfault.com/a/1190000010506374?utm_source=tag-newest

osg插件原理:https://blog.csdn.net/weitaming1/article/details/88954231

一、 渲染状态(render state)

osg中,当设置某节点的渲染状态时,该状态会赋予当前节点及其子节点,因此,若要实现多节点多状态渲染时,一定注意节点之间的父子关系,最好一个节点设置一个自己想要的状态,除非父节点及其子节点的渲染状态一样。
渲染状态的管理通过osg::StateSet管理,可以将其添加到任意的节点(node、group、geode等)和DrawAble类。如要设置渲染状态的值,需要:

  1. 得到某节点的stateset实例;
  2. 设置该实例的渲染属性(attribute)和模式(mode)
    例: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); //设置渲染模式

等等等等

二、 geometry和geode

显然,geode是几何节点,且是叶节点,geometry类管理osg中各种各样的几何体。
个人总结:在使用geode画osg自带的几何图形时,总是:

  1. 声明geode节点
  2. 创建几何对象
  3. 设置几何对象的参数
  4. 申请一个osg::ShapeDrawable
  5. geode->addDrawable
    列子:
//画个圆柱
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继承关系:
!

自定义几何体时:

  1. 申请geometry对象,自定义绘制的顶点、法向量、颜色等(如果需要的话)数组
  2. 将自定的各种数组传递给geode,并设置绑定方式。
  3. 设置各个顶点之间的关联方式(也就是绘制什么图形)
  4. 将geometry对象添加到geode->addDrawable(geometry);
    在第三步骤中,geom->addPrimitiveSet();函数需要一个Drawarrays指针和原始点的连接方式
    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继承方式:

三、Camera

当然,上一篇入门文章viewer::run()多多少少也和camera有关。现在算是进一步吧。
先看看camera的继承关系图

很明显,camera继承自node、group、transform,也就是说他们具有的属性,camera也具有。

1. 裁剪面

就像上篇文章所述,osgviewer->run()会自动设置一个场景漫游器,该漫游器包含了透视投影矩阵、视口大小、屏幕宽高比以及远近裁剪面、摄像机位置等等参数,如果想要修改远近裁剪面应该首先关闭osg的自动判断远近裁剪面的函数:

viewer->getCamera()->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);
viewer->getCamera()->setProjectionMatrixAsPerspective(fovy,aspectRatio,zNear,zFarSurface);

osgUtil::CullVisitor是osg的场景拣选访问器。

2. 获取自己设备的图形环境、HUD、RTT:

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添加多相机主要功能是为了多窗口多视图显示。一个相机能够渲染多个视图,一个场景能够添加多个相机,多个相机能够实现从不同角度、方位、视角观察同时观察同一个模型。

3. 两个小函数:

viewer->setCameraManipulator(osgGA::CameraMaipulator *),和viewer->addEventHandler(osgGA::EventHandler *),前者的函数参数是osgGA::CameraMaipulator *类型,后者参数为osgGA::EventHandler *类型,且osgGA::CameraMaipulator *是继承自osgGA::EventHandler *的。
对比:

  1. 前者的主要作用是利用外部设备等影响场景中的主相机位置以及相应事件。事件相应的主要目的是为了修改相机参数矩阵,以实现漫游的目的。设置漫游的本质就是修改主相机的各种参数矩阵,并将修改后的参数返回场景中的主相机(影响的最顶层的相机节点).
  2. 后者顾名思义,就是为了相应各种键盘、鼠标等外部设备事件事件,当然可以影响主场景中的相机。其实本质上):从类的继承关系来看,漫游器是从事件处理类中继承而来,如果事件处理函数个人写得足够好、足够丰富,应该能够替代漫游器的,这也是为什么两者在很多时候添加自定义类时程序并不报错,但就是达不到预想效果的原因。
    进一步讲,漫游器是对事件处理的更进一步的丰富,其"丰富"的主要内容应该是矩阵的自动返回操作,从而控制相机,其矩阵自动返回的主要函数是:
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)

:以上内容只是自己在比较皮毛的层面的记录,并没有过多的深入源码解析,内容或许有误,恳请指正留言,不胜感激!
:有做点云处理研究的朋友也可多多交流。

OSG入坑之路[转]的更多相关文章

  1. Idea+springboot入坑之路

    环境准备 IDEA 社区版: 2019.3 jdk: 1.8.0_241 tomcat: 7.0.99 maven: 3.6.3 spring-boot:2.2.5.RELEASE 插件 spring ...

  2. Python的入坑之路(1)

    (故事背景:由于涉及到机密的原因,暂时不方便透露,待后期再写.) 国庆长假过完之后,回来上班第二天下午,Boss跟龙哥把我叫了出去,问我要不要转人工智能.一脸懵逼的我,带着一脸懵逼听Boss说人工智能 ...

  3. 【Django入坑之路】Models操作

    1:字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pr ...

  4. k8s入坑之路(14)scheduler调度 kubelet管理及健康检查 更新策略

    kubelet 主要功能 Pod 管理 在 kubernetes 的设计中,最基本的管理单位是 pod,而不是 container.pod 是 kubernetes 在容器上的一层封装,由一组运行在同 ...

  5. k8s入坑之路(9)k8s网络插件详解

    Flannel: 最成熟.最简单的选择 Calico: 性能好.灵活性最强,目前的企业级主流 Canal: 将Flannel提供的网络层与Calico的网络策略功能集成在一起. Weave: 独有的功 ...

  6. k8s入坑之路(7)kubernetes设计精髓List/Watch机制和Informer模块详解

    1.list-watch是什么 List-watch 是 K8S 统一的异步消息处理机制,保证了消息的实时性,可靠性,顺序性,性能等等,为声明式风格的API 奠定了良好的基础,它是优雅的通信方式,是 ...

  7. k8s入坑之路(4)kubenetes安装

    三种安装方法: 1.kubeadm 2.kubespray 3.二进制安装 kubespray安装kubernetes集群 优点: 1.kuberspray对比kubeadm更加简洁内部集成了kube ...

  8. 【Django入坑之路】Django后台上传图片,以及前端的显示

    #setting配置: MEDIA_URL = "/media/" MEDIA_ROOT = os.path.join(BASE_DIR, "media") # ...

  9. 【Django入坑之路】Django与Query Ajax的交互

    1:Jquery.ajax后端交互数据 $.ajax({ Url: /路由处理/, Type: GET/POST, #传送请求类型 Data: {user: “ XXXX”,pass:”XXXX”}, ...

随机推荐

  1. 【Hadoop】MapReduce自定义分区Partition输出各运营商的手机号码

    MapReduce和自定义Partition MobileDriver主类 package Partition; import org.apache.hadoop.io.NullWritable; i ...

  2. NetCore 对Json文件的读写操作

    nuget Microsoft.Extensions.Configuration; Microsoft.Extensions.Configuration.Json; Newtonsoft.Json; ...

  3. mdk3 工具使用-表白神器

    一:在root目录下新建个txt文档,用vim编辑文档,写几段暧昧的话 二:终端执行命令: 开启网卡监听模式 airmon-ng start wlan0 开启无线广播 mdk3 wlan0mon b ...

  4. 【jQuery】attr()、prop()、css() 的区别(转载)

    .attr( ) 可以设置元素的属性(也就是给元素新增加一个原来并不存在的属性)也可以获取元素的本来就有的属性以及额外设置的属性.如果要获取的属性没有设置,那么获取到的结果是 undefined; . ...

  5. Java 基础篇之泛型

    背景 在没有泛型前,一旦把一个对象丢进集合中,集合就会忘记对象的类型,把所有的对象都当成 Object 类型处理.当程序从集合中取出对象后,就需要进行强制类型转换,这种转换很容易引起 ClassCas ...

  6. 【计算机视觉】OpenCV之GPU与OpenCL的相关内容说明

    1 扩展库简介OpenCV(Open Source Computer Vision Library)是一个致力于实时处理计算机视觉问题的开源库.它最初由Intel公司开发,以GPL许可协议发布,后来由 ...

  7. vs2015试用到期,不能输入序列号

    如果是社区版,登录账号即可, 如果不能登录账号,可以执行修复再登录账号: 控制面板-程序和应用-vs2015(我写的是简称)-右键-更改-修复-输入序列号

  8. 学习笔记:html学习之一:html基本标记

    1. 概论 一个完整的 HTML 文档必须包含 3 个部分: 一个由 元素定义的文档版本信息. 一个由 定义各项声明的文档头部, 作为各种声明信息的包含元素出现在文档的顶端,并且要先于 出现. 一个由 ...

  9. Win7/Win2008下IIS配置Asp站点启用父路径的设置方法

    iis日志错误如下: 修改路径文件权限问题依旧. 解决方式:

  10. Excel导入异常Cannot get a text value from a numeric cell解决

    POI操作Excel时偶尔会出现Cannot get a text value from a numeric cell的异常错误. 异常原因:Excel数据Cell有不同的类型,当我们试图从一个数字类 ...