OSG入坑之路[转]
转载自: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类。如要设置渲染状态的值,需要:
- 得到某节点的stateset实例;
- 设置该实例的渲染属性(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自带的几何图形时,总是:
- 声明geode节点
- 创建几何对象
- 设置几何对象的参数
- 申请一个osg::ShapeDrawable
- 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继承关系:!
自定义几何体时:
- 申请geometry对象,自定义绘制的顶点、法向量、颜色等(如果需要的话)数组
- 将自定的各种数组传递给geode,并设置绑定方式。
- 设置各个顶点之间的关联方式(也就是绘制什么图形)
- 将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 *
的。
对比:
- 前者的主要作用是利用外部设备等影响场景中的主相机位置以及相应事件。事件相应的主要目的是为了修改相机参数矩阵,以实现漫游的目的。
设置漫游的本质就是修改主相机的各种参数矩阵,并将修改后的参数返回场景中的主相机
(影响的最顶层的相机节点). - 后者顾名思义,就是为了相应各种键盘、鼠标等外部设备事件事件,当然可以影响主场景中的相机。
其实本质上)
:从类的继承关系来看,漫游器是从事件处理类中继承而来,如果事件处理函数个人写得足够好、足够丰富,应该能够替代漫游器的,这也是为什么两者在很多时候添加自定义类时程序并不报错,但就是达不到预想效果的原因。
进一步讲,漫游器是对事件处理的更进一步的丰富,其"丰富"的主要内容应该是矩阵的自动返回操作
,从而控制相机,其矩阵自动返回的主要函数是:
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入坑之路[转]的更多相关文章
- 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 ...
- Python的入坑之路(1)
(故事背景:由于涉及到机密的原因,暂时不方便透露,待后期再写.) 国庆长假过完之后,回来上班第二天下午,Boss跟龙哥把我叫了出去,问我要不要转人工智能.一脸懵逼的我,带着一脸懵逼听Boss说人工智能 ...
- 【Django入坑之路】Models操作
1:字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pr ...
- k8s入坑之路(14)scheduler调度 kubelet管理及健康检查 更新策略
kubelet 主要功能 Pod 管理 在 kubernetes 的设计中,最基本的管理单位是 pod,而不是 container.pod 是 kubernetes 在容器上的一层封装,由一组运行在同 ...
- k8s入坑之路(9)k8s网络插件详解
Flannel: 最成熟.最简单的选择 Calico: 性能好.灵活性最强,目前的企业级主流 Canal: 将Flannel提供的网络层与Calico的网络策略功能集成在一起. Weave: 独有的功 ...
- k8s入坑之路(7)kubernetes设计精髓List/Watch机制和Informer模块详解
1.list-watch是什么 List-watch 是 K8S 统一的异步消息处理机制,保证了消息的实时性,可靠性,顺序性,性能等等,为声明式风格的API 奠定了良好的基础,它是优雅的通信方式,是 ...
- k8s入坑之路(4)kubenetes安装
三种安装方法: 1.kubeadm 2.kubespray 3.二进制安装 kubespray安装kubernetes集群 优点: 1.kuberspray对比kubeadm更加简洁内部集成了kube ...
- 【Django入坑之路】Django后台上传图片,以及前端的显示
#setting配置: MEDIA_URL = "/media/" MEDIA_ROOT = os.path.join(BASE_DIR, "media") # ...
- 【Django入坑之路】Django与Query Ajax的交互
1:Jquery.ajax后端交互数据 $.ajax({ Url: /路由处理/, Type: GET/POST, #传送请求类型 Data: {user: “ XXXX”,pass:”XXXX”}, ...
随机推荐
- 购物车实现 <Block实现回调>
效果图如下: 具体代码实现如下: Model: #import <Foundation/Foundation.h> @interface ShopCarModel : NSObject @ ...
- 【Adobe Air程序开发】用Adobe Flex3开发AIR应用程序–入门指南
1 安装Adobe AIR 运行时,和java的JVM类似.Adobe AIR 运行时允许在桌面运行AIR应用程序,脱离游览器的束缚.下载安装文件http://labs.adobe.com/downl ...
- 【计算机视觉】【并行计算与CUDA开发】GPU硬编码
一.OpenCV中的硬编码 OpenCV2.4.6中,已实现利用GPU进行写视频,编码过程由cv::gpu::VideoWriter_GPU完成,其示例程序如下. 1 int main(int arg ...
- git 命令 git diff 查看 Git 区域文件的具体改动
查看 Git 区域文件的具体改动 git diff git status 只能让我们知道文件在 Git 区域内的改动状态,但如果我们想查看某个文件内具体改了什么(也可以理解为在不同 Git 区域中的差 ...
- 基于模板匹配的目标跟踪(OpenCV)
基于VS2010+ OpenCV2.代码可以读入视频,也可以读摄像头,两者的选择只需要在代码中稍微修改即可.对于视频来说,运行会先显示第一帧,然后我们用鼠标框选要跟踪的目标,然后跟踪器开始跟踪每一帧. ...
- delphi 相关好的资料网站
1.Delphi编程技巧大全 http://www.delphitop.com/ (实例讲解所有组件) 2.Delphi学习大师 Delphi基础教程 视频教程 http://www.xue ...
- Vue里标签嵌套限制问题解决------解析DOM模板时注意事项:
受到html本身的一些限制,像<ul>.<ol>.<table>.<select>这样的元素里允许包含的元素有限制,而另一些像<option> ...
- HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)
layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...
- DRF 序列化组件 序列化的两种方式 反序列化 反序列化的校验
序列化组件 django自带的有序列化组件不过不可控不建议使用(了解) from django.core import serializers class Books(APIView): def ge ...
- 经验:什么影响了数据库查询速度、什么影响了MySQL性能 (转)
一.什么影响了数据库查询速度 1.1 影响数据库查询速度的四个因素 1.2 风险分析 QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定 ...