
《最长的一帧》学习
文章平均质量分 60
directx3d_beginner
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
渲染流程简析--第二次调试osg最长的一帧心得
前三次只看不调,感觉像看天书。第一次调试osg最长的一帧时,感觉有些机械。第二次调试后,感觉osg最长的一帧真是没一句废话,字字珠玑。好像懂了不少。特将渲染流程的心得记录如下。(不看代码,不看电子书)一osg渲染流程1,摄像机添加场景。通过摄像机的图形上下文或者渲染器进行cull,draw或者cull_draw进行对SceneView筛选和绘制。(由不同的线程模型决定)2,cullvisitor筛选场景,构造渲染树和状态树3,渲染台遍历其成员渲染叶列表(半透明)和状态树中的渲染叶(不透明),通过st原创 2021-12-16 21:19:25 · 721 阅读 · 0 评论 -
SingleThreaded是如何进入cull_draw()的?
正如以前所说,单线程模式是通过cull_draw()进行剔除绘制的。如何进入的呢?其实很简单。逆推下最后,回到梦开始的地方原创 2021-11-16 10:00:16 · 275 阅读 · 0 评论 -
单线程不走Renderer::cull()和Renderer::draw(),而是Renderer::cull_draw()
在<<osg最长的一帧>>中,说单线程走Renderer::cull()和Renderer::draw(),实际上是错误的,正确的是Renderer::cull_draw()相关代码如下:可见,只有DrawThreadPerContext走renderer->cull()在绘制时原创 2021-10-22 01:14:11 · 108 阅读 · 0 评论 -
Renderer::cull()简析
在cull时,如果摄像机没有用线程剔除,则用Renderer::cull(),在最长的一帧里用到了这种方法。这里有个osgUtil::SceneView类,仅由renderer调用。这个SceneView类一开始我还以为时osgViewer;:Viewer,其实是两码事。osgUtil::SceneView类一般是双缓存,放在_availableQueue里可以说,Renderer的剔除过程也就是osgUtil::SceneView的操作过程分几步1,取出_availableQueue中取出第一原创 2021-10-21 20:30:33 · 152 阅读 · 0 评论 -
ViewerBase::renderingTraversals()的简易理解
前两篇说到了camera用来剔除,context用来渲染,多线程渲染就是把cpu尽可能的分配给context,如果土豪的话,在剔除过程也分配cpu另外,也要注意到过期请求数据不处理。当然,首先要获取场景,摄像机和上下文现在看下摄像机剔除可见,...原创 2021-10-15 10:29:16 · 209 阅读 · 0 评论 -
设置线程模型的依据--ViewerBase::suggestBestThreadingModel()
这个函数困扰了很久,四个线程模型SingleThreaded,CullDrawThreadPerContext ,DrawThreadPerContext,CullThreadPerCameraDrawThreadPerContext到底是如何判断的。依据是什么?我谈谈个人理解,不一定对。首先说下,摄像机在这里指代什么?context指代什么?我一开始以为摄像机是大屏,哈哈。这几个线程模型的用在renderingTraversals(); 场景的渲染遍历工作阶段。这个阶段两个重要工作1,剔原创 2021-10-13 11:10:52 · 183 阅读 · 0 评论 -
分页数据库其实就是两个生产者与消费者
再次看osg《最长的一帧》,因为分页数据库适合于PagedLod和ProxyNode,一般调试还得准备数据,比较麻烦。突然想起,和我以前封装的引擎类似。分页数据库就是几个生产者与消费者。回过头来看这个图。看似复杂,实际上并不复杂。如果简化,只需要一个数据请求列表和等待合并列表就够了。请求什么数据,就合并什么数据即可。当然,合并前清空数据。也就是说,在请求数据时,用生产者和消费者的方式;同样,在合并时,也用生产者和消费者的模式。如果,再考虑效率,就要加上等待编译列表,把stateset和draw原创 2021-10-13 07:43:02 · 133 阅读 · 0 评论 -
调试osg最长的一帧(第30天)
终于快结束了,再接再厉。GOGOGO!对于剩下的两个线程模型,一,默认的线程模式是DrawThreadPerContext其实,前面有些已经跟踪过了,再一边抄一边调试,熟悉下,一遍肯定记不住。如果ViewerBase类的成员函数suggestBestThreadingModel(),没有找到适合当前计算机系统的线程模式的话,将自动采用这一模式来完成渲染的工作。DrawThreadPerContext模式没有设置渲染启动栅栏和结束栅栏。因此,这一渲染模式下将不会在.原创 2021-02-14 18:53:26 · 479 阅读 · 9 评论 -
调试最长的一帧(第29天)
GraphicsContext::createGraphicsThread()创建线程时,得到一个osg::GraphicsThread线程对象而使用Camera::createCamera创建线程时,得到的是osg::OperationThread对象,它是GraphicsThread的父类。可见osg::OperationThread是osg::GraphicsThread的父类。这...原创 2021-02-13 15:24:22 · 244 阅读 · 5 评论 -
调试最长的一帧(第28天)
电子书对同步三兄弟的初始化做了介绍,再看看它们三个在哪里初始化的呢?动态绘制阻塞器_endDynamicDrawBlock的作用就是避免DYNAMIC对象的运行时更改影响后台渲染的工具。在初始化时,我们需要设置它的最大计数值,当completed函数的执行次数达到这一数值时,将释放被阻塞的线程,也就是主进程。这一最大计数值正是场景中摄像机渲染器Renderer的个数。这里State::_dynamicObjectC...原创 2021-02-11 22:59:32 · 103 阅读 · 0 评论 -
调试最长的一帧(第27天)
对于几个多线程渲染中的成员变量原创 2021-02-11 15:47:49 · 156 阅读 · 0 评论 -
调试最长的一帧(第26天)
在第25天,这个例子可能会有误导,因为用的是pagedlod的方式触发的,实际上,任何一个可绘制节点都可以,因为最终在渲染叶中,再改到最简单,依然触发这里没有设置,所以直接返回false...原创 2021-02-10 21:11:26 · 182 阅读 · 0 评论 -
调试最长的一帧(第25天)
目前已经到了单线程渲染的尾声了,先看看总体框架,看看还是否忘记了。昨天,看到的第24天内容结尾,有点懵逼,下面这个图以前看的也有点懵,直到这两者都看了后,突然有点明白了,从渲染元和状态节点起始,由osg状态机为中转核心。在看电子书之前,先在源码把这张图上的这些找到,观其大略。再对照下电子书,看看自己的思路有什么问题。可见,moveStateGraph在状态节点中与状态机之间搭建了桥梁。渲染元与渲染叶之间,RenderLeaft::render()是在RenderBi...原创 2021-01-10 22:28:33 · 212 阅读 · 0 评论 -
调试最长的一帧(第24天)
电子书开始主要介绍了要解决的问题。抄一抄。首先,我们要解决的问题是RenderStage::runCameraSetUp和RenderStage::copyTexture这两个函数的工作内容。事实上也是对“什么是渲染目标实现方式”进行讨论。渲染到纹理。RTT技术意味着我们可以将后台实时绘制得到的场景图像直接作为另一个场景中对象的纹理,从而实现更加丰富的场景表达效果。在viewer::eventTraversal函数中调用camera::getRenderTargetImplementation()进原创 2021-01-09 22:06:52 · 250 阅读 · 0 评论 -
调试最长的一帧(第23天)
看看总体进度第22天通过CUllvisitor创建了渲染树和状态树,并进行必要的剔除。接下来进行排序和优化RenderStage::sort函数时按照前序渲染台,当前渲染台和后续渲染台的顺序进行,其中前序渲染台和后续渲染台通过Camera::setRenderOrder实现,保存了指定摄像机及其场景子树和渲染树结构。渲染树及其各个分支中数据的排序工作实际上时通过RenderBin::sortImplementation函数实现的,如果希望能实现自定义的渲染树排序动作,通过Re原创 2021-01-02 17:24:49 · 222 阅读 · 0 评论 -
调试最长的一帧(第22天)
先看看全流程先抄一抄节点访问器NodeVisitor的工作原理.当我们执行节点的accept(NodeVisitor* nv)函数时,当前节点自动调哟个NodeVisitor::apply方法,将自身的信息传递给节点访问器nv,由它负责执行相应的处理工作;然后节点将自动执行Node::traverse函数,调用所有子节点的accept函数,从而实现了节点数的遍历。在遍历的过程中,每个节点都会调用NodeVisitor::apply,将自身的指针传递给访问器,因此,NodeVisito..原创 2021-01-01 20:20:05 · 205 阅读 · 2 评论 -
调试最长的一帧(第21天)
看看全流程,主要讲sceneview::cull(),跟过去重点在cullstage()下一步深入展开osgUtil::CullVisitor::pushStateSet() ...原创 2020-12-27 20:36:49 · 176 阅读 · 0 评论 -
调试最长的一帧(第20天)
电子书上给了个例子,抄一抄,加深下印象,也验证下以前的想法对不对对于场景实例其中"ss"加上数字代号来标识这些Stateset对象,后面括号中的两个参数分别表示setRenderBinDetails的两个设置项("-"表示空字串,"R"表示"RenderBin","D"表示"DepthSortedBin"即ss03->setRenderBinDetails(0,""); //缺省设置ss11->setRenderBinDetails(0,"");ss13->..原创 2020-12-22 17:57:22 · 344 阅读 · 0 评论 -
调试最长的一帧(第19天)
这个主要是理论了。抄一抄。最常用到场景管理方式时场景节点树结构,场景树顶点的叶节点osg::Geode包含了各种需要渲染的几何体的顶点和渲染状态信息;而组节点osg::Group及其派生出的各种特殊功能节点则作为场景树的各个枝节节点 ,它们也可以拥有不同的渲染状态;有且只有一个节点可以直接作为整个场景的根节点,使用setSceneData将其设置为场景的视景器系统,即等同于将整个场景树传递给OSG的渲染和显示系统。而保存节点和几何体的各种渲染属性(osg::StateAttribute,例如纹理、雾原创 2020-12-22 16:33:56 · 226 阅读 · 0 评论 -
调试最长的一帧(第18天)
发现一个错别字,改过来,哈哈,先看看总体流程直奔renderer::draw()为了查询gpu,在main()函数先设置,要不没法往下调试重点落在sceneView::draw()以后深入...原创 2020-12-22 12:23:40 · 204 阅读 · 0 评论 -
调试最长的一帧(第17天)
先看看流程电子书上介绍了渲染器osgViewer::Renderer类,osgViewer::Renderer为摄像机渲染场景的工作提供了一个公共接口,当我们向视景器viewer添加了一个新的摄像机camera时,一个与摄像机相关联的渲染器Renderer也会被自动创建。当准备渲染场景时,与特定图形设备GraphicsContext相关联的摄像机也会自动调用其渲染器的响应函数,执行场景筛选与绘制等工作。渲染器负责调用场景视图获取摄像机附带渲染器的代码:关于场景视图在.原创 2020-12-22 06:40:11 · 258 阅读 · 1 评论 -
调试最长的一帧(第16天)
终于到达绘制了,先看总体流程阶段然而,从并行堆栈上看,已经有渲染线程开启了跟着电子书走,先是介绍,抄一抄,加深印象。osg的场景渲染过程可以简单地分为三个阶段:用户APP阶段,更新用户数据、负责场景对象的运动和管理等;筛选cull阶段,负责对场景中的对象进行筛选裁剪,略过那些不会被用户所见(因而不必渲染)的物体,并根据渲染状态的相似性对即将进入渲染管线的对象排序(从而避免OpenGL状态量的频繁切换);绘制(DRAW)阶段,执行各种OpenGL操作,将数据送入OpenGL渲染管线及.原创 2020-12-21 18:11:04 · 156 阅读 · 0 评论 -
调试最长的一帧(第15天)
第14天的有个错误关于一开始用的这个pagedLod结构,既然setFileName和setrange()了,就不该addChild()了,这才是动态加载。也就是只需设置各个子节点的文件名和出现范围即可。继续调试,先看总体流程这一节主要是总结了,再把大图拷过来左上角还没有调试跟着电子书走一走,抄一抄1,首先osg::PagedLOD节点或者osg::ProxyNode节点使用setFileName函数,请求运行时加载模型文件为子节点。初始化时已经...原创 2020-12-21 16:08:46 · 357 阅读 · 0 评论 -
调试最长的一帧(第14天)
看看流程可见分页数据库的更新也是和场景的筛选绘制是同时进行的。再看看大图第14天要进行左下角的依照惯例,跟过去现在开始步入正轨发现第0个fileName为空,这是有问题的创建pagelod时修正为这次进来了在这里删除放入removeChildren跳了过去,可以设置开启渲染状态共享器果然到这里了不过电子书上说效率不好,暂时就不用了,只是调试下。判断databaseRequest->_groupForAdding原创 2020-12-21 11:52:04 · 194 阅读 · 0 评论 -
调试最长的一帧(第13天)
现在因为要进行 DatabasePager::DatabaseThread::run()的跟踪,已经在renderingTraversals()流程了。整个流程如下可见,场景剔除影响到了分页数据库的变化,跟踪如果请求加载的文件来自HTTP网络且已经设置了OSG_FILE_CACHE,则本地文件处理线程将尝试建立同名的文件缓存路径每次循环开始时,阻塞数据处理线程,避免无谓的系统消耗,知道updateBlock函数在外面执行才被放行,继续下面的代码。可以看到updateB原创 2020-12-21 08:31:47 · 226 阅读 · 0 评论 -
调试最长的一帧(第12天)
先看看总体流程走到了更新分页数据库分页数据库的数据流图先找上图的4个成员变量上图中,左侧的图框表示数据的检索和输入;中间的白色图框表示用于数据存储的内存空间,而右边的图框表示存储数据的输出。此外,蓝绿色图框表示可以在DataBaseThread线程中完成的工作,而橙色图框表示由线程之外的函数完成的工作。从上图可以看出osg的分页数据库使用线程处理的事情,抄一抄。1,删除过期的场景数据,为了避免场景渲染的延迟,所以不在仿真循环中进行,而是采用线程来处理。过期对象的统一删除工原创 2020-12-20 19:15:12 · 168 阅读 · 4 评论 -
调试最长的一帧(第11天)
这一天,与流程无关,是多线程库OpenThreads,第三天已经分析过了,本质上就是windows核心编程中的事件,临界区和信号量,存储区和构造时加锁,析构时解锁的类。再看看这个库是怎么封装的。抄抄。1,Thread类,线程实现类。它是一个面向对象的线程实现接口,每定义一个Thread类,就相当于...原创 2020-12-20 12:28:44 · 246 阅读 · 2 评论 -
调试最长的一帧(第十天)
依照惯例,先看总体流程到了更新回调。一边抄一边记忆OSG更新回调的作用与事件回调有类似之处,由专门的访问器对象_updateVisitor负责场景图形更新遍历所有的节点和Drawable几何体对象都可以使用setUpdateCallback设置更新回调通过重载NodeCallback::operator()或者Drawable::UpdateCallback::update函数,可以在回调对象中添加自定义的工作。.原创 2020-12-18 17:57:41 · 283 阅读 · 0 评论 -
调试最长的一帧(第九天)
看看整体流程如果有osgGA::GUIEventAdapter::QUIT_APPLICATION,就可以随时关闭程序这里对退出起作用的是结束键退出键不一定按esc键,也可以是其他键,增加灵活性,保证随时退出当然,最终是因为_done起作用,所以可以直接设置,直接终止。比如,当前事件是WM_MOVE注册的事件处理器有8个,依次处理...原创 2020-12-18 10:04:53 · 167 阅读 · 0 评论 -
调试最长的一帧(第八天)
先看看总体进度先获取所有的图形上下文,然后进行checkEvents()请求分发消息并通过takeEvents()获取交互事件,再交由GUIEventHandler处理交互事件。中间的步骤,在checkeEvents里面,消息分发函数,消息处理回调函数WM..把消息加到Events处理y轴方向设置焦点摄像机将焦点摄像机坐标转换到主摄像机坐标(非主摄像机坐标范围(-1,1),(-1,1))...原创 2020-12-14 19:28:40 · 134 阅读 · 0 评论 -
调试最长的一帧(第七天)
先看看总体进展,eventTraversal函数的任务:在每帧仿真过程中,取出已经发生的所有事件,摒弃哪些对场景不会有助益的(比如, 在视口外的鼠标事件),依次交付给各个事件处理器,最后清空现有的事件队列,等待下一帧的到来。在View的几个成员变量中,_eventHandler处理由图形设备传递到事件队列_eventQueue的各种事件。添加事件处理器由View::addEventHandler添加,事件处理器可以通过继承事件处理器基类osgGA::GUIEven..原创 2020-12-14 14:37:17 · 135 阅读 · 0 评论 -
调试最长的一帧(第六天)
依照往常,先看总体进度终于进入仿真循环,推动时间下一步进行处理交互事件电子书上先给出了视景器、漫游器、事件处理器、场景、摄像机之间的关系,如下图看看这几个类的相关成员变量...原创 2020-12-13 12:13:19 · 138 阅读 · 0 评论 -
调试最长的一帧(第五天)
调着比较上瘾了。没第三天那么费劲了。先看总体依然在realize()里面,不过第五天就要把这个解决了。继续跟过去原创 2020-12-11 23:09:13 · 212 阅读 · 0 评论 -
调试最长的一帧(第四天)
第三天的内容,调试用了我三天的业余时间,最后都不想说话了,想吐,直接上代码了事。终于明白电子书上说的, 不想赶上资本论的规模了。因为根据图形上下文创建设备,不只是窗口,还涉及到了背后的消息队列。接着奏乐接着舞,进行第四天。按照老规矩,先看全局。介绍了几个函数,再回顾一下取得与平台相关的视频API接口类,是个纯虚基类,父类调用子类的方式去实现。View::setUpViewAcrossAllScreens()还有一种多个从摄像机对应多个屏幕的情况,在else里...原创 2020-12-10 22:36:27 · 252 阅读 · 0 评论 -
调试最长的一帧(第三天)
先看看整体,以及进度第三天的内容,主要讲根据窗口参数建立图形上下文设备原创 2020-12-10 00:41:01 · 2147 阅读 · 6 评论 -
调试最长的一帧(第二天)
先看下全局及下一步位置,免得迷茫了查看是图形上下文数组中是否有准备好的这里Contexts是图形上下文数组从成员变量上看,也是个多线程的东西包括嵌入窗口特性,窗口位置和宽高等。派生自ScreenIdentifier,从成员变量可知,与主机名,屏幕数和显示数有关在这里发现,主摄像机没有图形上下文设备指针,因为没有创建图形上下文如果多个,则需要排序图形上下文因此,也图形上下文设备数目也为0所以,要执行rea.原创 2020-12-06 17:45:00 · 234 阅读 · 0 评论 -
调试最长的一帧(第一天)
突然觉得调试更一目了然。避免“看过就学会,收藏即学习”先加载个牛直奔主题frame()这里用到的是基类viewerBase::frame(),单视景器和多视景器都调用它。这里是单视景器视景器初始化转到了osgViewer::viewer::Init(),为什么呢?因为主函数调用就是单视景器osgViewer::Viewer派生自ViewerBase和osgViewer::View,所以调用的是基类ViewerBase的frame()...原创 2020-12-06 09:08:39 · 443 阅读 · 0 评论 -
第二天(八)osg::Object* readObjectFile(const std::string& filename,const ReaderWriter::Options* options)
目前流程是:osgViewer::viewBase:: frame(){viewerInit();[//创建帧事件,并将漫游器与事件和视口相关联->osgViewer::Viewer::ViewerInit()->osgViewer::View::Init();...原创 2020-05-17 08:11:54 · 297 阅读 · 0 评论 -
四种线程渲染模型
一、问题的引入:如何筛选,如何绘制,对动态对象该怎么处理二、四种线程模型.1,单线程2,CullDrawThreadPerContext:系统为每个图形设备创建一个线程,每一帧结束前强制同步所有的线程,也就是说每帧前都要绘制完3,DrawThreadPerContext,系统为每个图形设备创建一个线程,并且在当前帧的所有线程完成工作之前,开始下一帧4,CullThreadPerCameraDrawThreadPerContext:系统为每个图形设备和每个摄像机创建线程,并且在当前帧.原创 2020-05-11 11:26:09 · 751 阅读 · 0 评论 -
第二天(七)osg::Object* readObjectFile_const std::string& filename_const ReaderWriter::Options* options
目前流程是:osgViewer::viewBase:: frame(){viewerInit();[ //创建帧事件,并将漫游器与事件和视口相关联 -> osgViewer::Viewer::ViewerInit()...原创 2020-04-22 05:55:23 · 310 阅读 · 0 评论