代码改变世界

08年末工作报告流水账--Spherical Parametrization实践

2010-05-29 15:54  六水  阅读(506)  评论(0编辑  收藏  举报
关键字 Spherical Parametrization,Progressive mesh,流形,保角变换,调和映射,Distortion Metric 拉普拉斯算子,网格松弛
images/pmsp.jpg

先贴个试验结果效果图,流程也在这了。

这贴去年就该发了,只是一直懒着在那,不想动手,但不发又
不好交待,譬如那天叶起涟漪在群里问我最近都在干嘛,无言以对。这段时间
确实比较烦,干活效率低。由于家里又有些事,一直心情不大好。不过做这个
spherical parametrization还真的蛮折腾的,12月份基本上就花在这个上了
(当然是业余时间做了,白天还要上班呢)

总的操作分两步,第一步是用PM简化模型,直到形成凸体。第二步是基于这个
凸体进行顶点分裂,直到形成与原始模型的网格结构一致为止。

具体就参考 周昆《数字几何处理:理论与应用》
和 Emil Praun,Hugues Hoppe《Spherical Parametrization and Remeshing》
至于这个球参数化有什么用,我也不在这多说了,参考这文章。

关于渐进网格
progressive mesh(PM)是比较好的lod方案。有关球参数化的实现的论文里也经常使
用这种方法,我也不例外。一般用来简化模型的话,实现起来是比较容易的,
记得我学3D不久的时候也做过。但用来做这个球参数化的化了,要求就比较高
了。简化过程中的所有数据几乎都要保存下来,以便用来实现顶点的参数化。
我用的具体方法是边折叠的方法,也就是说,每次简化操作,会删除两个顶点。
而产生一个新的顶点。这两个被删除的顶点,就分别参数化到新顶点周围一圈
的某两个三角形里。但是由于严格地要求简化结果是一个凸体,于是会产生以下
新的问题:

关于避免形成非流形
我们这里处理的都是流形,而且亏格都是为0的网格。
但PM简化网格的时候有时会形成非流形,一单某个步骤产生了非流形, 那最终结
果就形成不了凸体了,因为在形成非流行的那刻起,模型的拓扑已经发生了变化。
我们后来寻找好的办法,后来采取了基于二次误差度量(Quadric Error Metric)的
算法(Garland,1997)。这种办法从测试结果来是,简化效果是最好的。但当我们拿
比较复杂的模型进行测试时,也会导致产生非流形。可见这种办法并不是很严格,
并不能保证简化过程中绝对不产生非流形。
这时我也不想在去寻找啥办法了,干脆自己分析,想办法添加些逻辑进去来避免这
个问题。后来分析出,在折叠某条边的时候,如果发现该边能在模型表面形成不止
两条三角形回路,那该边就不能进行折叠,就先折叠其他边。 测试结果表明,添
加这个逻辑是有效的,后来测试了很多复杂的模型也不会导致这种问题了。
关于这个问题,我后来也去请教Alice了,问她看看有没有好的办法。她的
思路是,不能让折叠过程产生面积为0的三角形。我开始还一直不明白,这种办法怎
么能解决我那个问题。后来她说那个三角回路也算是一个存在的三角形。关于这个
三角形的定义我们还争执了一下,后来觉得其实这种问题是无所谓的了,就看你用
什么方式去理解一个问题而已。

局部参数化的问题
进行边折叠的时候,需要把它的两个顶点局部参化到新顶点周围一圈的某三角形里。
怎么计算是参数化到哪个三角形呢?参数坐标是多少呢?这要用同时用到保角变换
和调和映射两项技术。先把新顶点一圈的三角形保角变换到平面上,然后再把当前
被折叠边周围一圈的三角形用调和映射,也变换到平面上去,所有位置关系都已经
得到了,就可以方便地分别计算出这两个顶点的局部参数坐标。然而这并没有想象
的那么顺利,最主要的问题就在于调和映射的问题了。在大量的测试下,我发现,
如果网格内部的边分布很不均匀,譬如有些边很短,有些边很长,往往会导致内部
点的坐标(uv)会超出网格的边界。这种结果是不能用于计算局部参数坐标的。分
析了一下,这种情况是由于这方法本身的计算公式的问题。这方法在用于有着大量
三角形的网格上,是可以产生理想的结果的。我以前做geometry image的时候也用
过,我深信这方法的有效性。但我们现在只需要参数化某条边周围一圈的几个三角形
公式问题就暴露了出来。我去修改了一下它的公式,最终解决了这个问题。尽管这个
动作很不具有安全感,但测试结果表明是没问题的。这个问题可能以后要深入去研究
下,以得出比较合理的解决方案。
总的来说,这个局部参数化的问题花了我很长很长时间,非常郁闷。

接下来是从凸体生成球
总的来说,这步只是PM边折叠的逆操作。但具体问题就集中在逆操作的时候,分裂出
来的两个新顶点,该摆在什么位置的问题了。文章的办法是,根据边折叠过程中形成的
局部参数坐标进行计算。于是也草草地用这种办法去计算,发现对于均匀的物体来说,
这样就能生成比较正常的球了,但对于稍微不均匀的模型,就生不成了。因为在顶点分
裂过程中,很容易形成三角形翻转。文中也提到这个问题了,说可以用拉普拉斯算子去
解决这种问题。但经我测试下,如果在分裂的过程中使用这个拉普拉斯算子去调整顶点
的位置,那很可能会形成凹体,到之后也无法生成正常的球。我后来的办法是在分裂完
成后才去统一调整的,最后确实是解决了这个问题。

另外还有问题就是,参数化不均匀的问题了。因为顶点的局部参数化坐标只是一个局部
优化的结果,没经过全局优化,因此最终计算出来的球面坐标也并不均匀。于是又用了
[Sander2001]中的形变度量的方法,迭代地调整每个顶点的位置,直到形变因子的值
小于一定值,或者超过迭代次数位置。这种办法在很多文章都提到的,但很少提到具体
的过程,都说得不详细,具体方法还得自己去设计。有些文章说用叫
bracketed parabolic minimization的方法。。。于是有得去研究这方法了。。。。
用了该形变度量的方法去调整网格后,发现网格的密度还是很不均匀啊,特别是象动物
的腿的地方,在球上这部分网格就非常密。还是得想办法去解决这种问题,后来采用了
使用网格松弛法去处理这个密度问题。球的网格的密度总算是比较均匀了。

还好了,到最后总算是生成了比较均匀,形变也比较小的参数化球。这一步也是花了我很
长时间,是整个流程里最耗费精力的了。这次简直就是挑战了自己的耐性。

但由于造型差异的问题,球上的网格还不是绝对均匀的,这个问题是球参数化的
硬伤。这个问题,许多学者认为可以在后期采样的时候,进行密度自适应的采样方法,
以尽量降低该硬伤导致的影响。我暂时还没做到采样以及网格重建,以后再看这种问题。

附:
测试模型的问题
在网上找了那几个经典的模型,当时拿到的模型格式都是自定义的,幸亏是很简单的
格式,用文本记录的。接着就赶快拿去测试,然后发现这些模型都不能顺利地简化成
一个凸体(我用的是四面体)。猜测原因有几个:一是那些模型本来并不是封闭的;
而是那些模型,有可能里面不止一个封闭表面。无论原因是哪个,我也没办法自己用
程序去修改了,干脆就导到3dsmax里去修改算了,然后再导出。
于是就搞起久违了的max插件,不过写import插件还是第一次。装完插件向导后,发
现向导不能工作了,说项目生成失败。汗一个,查了很久也没查处是什么原因,后来
发现是VC向导版本的问题,他是7.0版,但我的VC是8.0。没办法了,暂时就叫朋友
帮我生成个导入插件项目算了。于是去叫老狼 ,汗一个,这家伙恰好不在线,囧啊。
还好了, 我忽然想起,MAX的SDK里也有一个导入插件的例子,于是把项目和代码拷
一份过来用算了。这例子写的代码还是挺多的,我完全不需要那么多功能。于是阅读
了一下导入流程之后,开始狂删代码,加入自己的代码。这次写插件居然极其顺利。
我从来没试过写max插件写得那么爽的,居然20分钟就写完了。汗一个。。。。。。
把那些模型到进去,嗯,一个个都修改为亏格为0的封闭流形。然后导出,测试。

第二天老狼终于回复,给我发了一个生成好的项目。还帮我解决了我这里项目无法生
成的问题,其实就是改了一个地方,使用3dsmaxpluginwizardvs_net2003遇到类似问
题的朋友就注意了,看看:
3dsmaxPluginWizard.vsz这个文件里,有一行是这样的
Wizard=VsWizard.VsWizardEngine.7.1
如果你用的ide是vc 2005,则要改成:
Wizard=VsWizard.VsWizardEngine.8.0
然后我再去生成,果然成功了。汗,怎么会想到改这种地方了,
read me.txt里也没提这种问题。