一、需求来源
需求来自于病害提取,需要有个框选功能,用于框选病害区域,三维转二维图像,在二维图像进行标注病害最后在三维中体现出来,为满足胡妈要求,特此写这个文章,记录一下。
二、要求
要求不改变框选部分网格拓扑关系,纹理也需要在,相当于复制了网格的一部分。
三、方法1 osg碰撞
使用杨石兴老师方法,他给出了两个osg框选案例,这是杨老师的实现方式。修改之后就是通过记录鼠标的拖动的最大值和最小值,通过osg内置的碰撞检测来实现。通过区域内的密集碰撞,拿到碰撞的面片点,面片纹理坐标,面片纹理指针,最后组合成一个新的Geometry。
优点就是快,缺点也很明显了,有一些奇特的三角面片比较小,由于osg碰撞密度太稀疏,就会碰不到,就会会产生网格漏洞,其实可以将漏洞连接起来,因为纹理坐标是在的,所以按理说,连接起来以后不会出现纹理错乱的情况,但事实上,本人能力有限不会检查漏洞,漏洞算法又是几何学上的一个大问题。同时如果有两个相邻的三角面片都没有连接,那么我们怎么连接,连错了就是改变拓扑结构,谢t!CGAL貌似可以做网格布尔运算,但不带纹理,也会改变网格,opencascade应该可以,很现实的问题是我不会,我也不可能在短时间内去熟悉它,导师提个要求,就得学个新库,而且要5天内解决怎么可能。
方法二 索引查找
osg读入网格模型以后就有了纹理索引、图元索引等等,从网格索引中下手。首先框选能拿到选框的四个点,然后选框的中间点去碰撞,拿到中间碰撞得到的三角面片索引其中一个Index1,判断一下Index1在不在框内(三维坐标MVPW矩阵三维转屏幕点,在二维使用向量判断在不在框内),然后查找有哪些map中存在Index1,每组里的另外两个三角面片索引存上,再每组另外两个索引依次查在那个组里,在不在框内,用索引找索引,再用索引找索引,例如{1,2,3}{1,2,6}{2,5,8}查1,发现在1,2组里,另外四个索引是2,3,2,6为了减少计算(现在看的挺少的,真到了网格里成倍数的增加计算)使用std::set给去重就剩下了{2,3,6}在找2,发现是是5,8(查过的就不查了),在继续找3,发现已经没了,都检查完,挨个按照索引把顶点坐标,纹理坐标填进去,组成一个新的Geometry。
优点不会出现漏洞。缺点计算慢框选越大,计算的越慢,等着再优化一下,用一下QtConcurrent::mapped或者扔到GPU中去给它算,应该快很多了。
这个方法比遍历所有顶点快多了,遍历所有顶点又涉及到背面的问题,在选框内模型正面和背面,背面应该丢弃,又涉及到视口远近好像是叫拣选,麻烦。
参考过cloudCompare,发现人家人家深度集合于CCCore,看完以后沉默了,我这个就写一个一个事件,和一个查找索引的类,它那个代码太多了。不过还得多参考,人家那个快。
还有个Curve-库,blender里面使用了,可以带纹理的裁剪,好家伙下来一看,Linux,改了改cmakelist,又改了很多代码,真的麻烦,遂放弃。
还有个方法,就是仅碰撞四个点,然后拿到四个点的纹理坐标,组成个新的,像个平面,而且三维转二维也得投影不久省了一步,但事与愿违。小点的没问题。大点的纹理就乱了。乱了原因大概是纹理贴图在内插的时候就错了,一个三角面片内,内插没问题,一堆三件面片就给四个点,在内插纹理坐标就属于扯淡了。
另外的方法就是使用clipNode,这个简单,就给个裁剪平面就完了,但ClipNode就是影响显示在屏幕上的模型而已,并没有对顶点做出实质改变。
快毕业了,在三维引擎开发,图形学路上慢慢前进。