毛发渲染 ———— Real-Time Fur over Arbitrary Surfaces部分翻译

来源:互联网 发布:迪拜旅游攻略大全网络 编辑:程序博客网 时间:2024/05/02 00:00

请原谅我搓搓的英语翻译水平0.0(仅作参考)
http://research.microsoft.com/en-us/um/people/hoppe/fur.pdf

前人的研究:主要是使用Shell方法@@
缺点:
1、需要surface的全局参数,但是并不是所有surface都具备这一特性(比如一些特定的表面。没有事先切分成片和分开渲染他们)
2、需要大量的纹理内存,每个shell需要不同纹理覆盖整个表面,而且纹理要足够大区解决单独的头发
3、Shell方法只有在实现方向大致垂直于surface时,才对体积纹理提供了一种有效的近似。轮廓附近的地方(shell在掠视角(grazing angles)内被观察),头发将过于透明,而且在不同shell之间,会很明显

改算法对这些的改进:
1、——使用lapped texture(解决问题1,2):
Lapped textures可以通过将重复(wrap mode?)粘贴小块面(Small patches of example texture)覆盖特定的拓扑结构。因此我们只需要单独patch的局部参数,而不是全局参数。而且大量小块面他们共用一张贴图,所以可以解决纹理内存过大的问题。
2、对于轮廓问题:(这里的轮廓指的是刚好与视线垂直的表面)
这其实并不是Shell方法才具备的问题。在交互设置时,设计师为了保证高帧率,他们会采用低模。Detailed Texture有助于美化这些粗糙的模型,除了在轮廓那些切线不连续的地方,那些地方视觉效果将下降。而在毛发渲染的时候,轮廓的视觉效果在感知上扮演着十分重要的角色。对于这种情况,人工的多边形可以采用更高的分辨率来缓解,或者使用Sander的方法–clipping到一个高分辨率的2D轮廓。
为了解决这个问题,我们引入了一个方案:垂直渲染fins到轮廓表面的地方。fins纹理使用跟Shell 纹理同样体积的模型来模拟毛发,但是他们将会在不同方向(更加适合倾斜视角的方向)进行采样,或者让美术直接创建一个fin纹理
我们提供对毛发的局部和全局属性的控制,比如方向,长度,颜色。

Contribution:
1、结合lapped texture和Shell method 允许覆盖任意拓扑结构和减少纹理内存
2、提高在轮廓位置的视觉效果
3、提供对毛发的全局或者局部控制

Approach

我们的系统需要输入生物的模型和毛发的参数模型。在实时渲染之前,我们需要执行两个操作:
1)、几何预处理:计算lapped texture 小面片的的参数

2)、纹理预处理:建立一个毛发块的几何模型,并将其采样到shell和fin纹理中。
到了实时渲染的时候,我们渲染一系列从原来surface偏移过的,已经贴好图,同心的shell,和垂直surface的fins(更好地支持轮廓附近的毛发)

几何预处理:
为了建立patch(小面片)的参数,我们使用Praun的方法获得lapped texture。简单来说,该方法将patch随机建立在surface未覆盖的地方。并且使用一种优化过的方式将他们局部参数化到texture domain。
在原来的lapped texture方法,为了让patch之间的缝隙不那么明显,采用的是将patch交叠在一起,然后给他们分配不规则的边界和alphablend这些边界。而对于很多类型的头发纹理(头发是树立起来的),这些措施并不需要(缝隙明显很正常…)相反地,我们可以让patch的边界与mesh的边缘对应,这样就能完全消除在patch之间的重叠。由于头发纹理是随机的,由此产生的沿着网格边缘的纹理不连续问题几乎是不存在了。这种非重叠纹理参数化(non-overlapping texture parameterization)的好处在于每个shell的三角形网格只需要渲染一次,而不是每个patch都要overlapping它一次。另一个好处在于我们不需要边界(Boundary)了。这样我们的patch纹理就可以环形的,使用tilling覆盖更大的pacth表面。

尽管使用non-overlapped parameterization,我们仍然可以得到很多好处:
1)、让 patch对准一个全局方向(we still benefit from the alignment of the patches to a global direction field over the surface. )这个常量方向可以帮助我们隐藏patch之间的缝隙(头发有一个优先生长的方向)
2)、由于不规则的“污点”形状,使得每个patch的有一个不平坦的网格边缘边界。比如毛骨悚然的时候,我们可以忽略全局方向,创建一个各向同性的参数,让他们的局部取向不对准相邻的patch

纹理预处理:
使用Lengyel的方法,我们基于头发缕的几何体创建Shell纹理。头发缕是由粒子系统模拟出来的,为了让体积纹理可以平铺,这种模拟发生在一个小型的长方体,长方体沿着皮肤两个轴环形对称。通过改变参数,我们可以得到不同的头发(直的,卷的…)

Shell Texture
Shell方法通过覆盖在头发缕的bounding box上的grid,为每一个shell model 的layer创建一个RGBA图片。在每一个grid point上,我们通过对头发进行一个高频的高斯滤波过滤,来计算颜色和透明度。使用高频是因为Shell里面的间距比在每个shell中的grid要大得多。对于最里面的Shell,将完全不透明,因为只是皮肤的表面。
为了将lapped texture和shell方法结合,我们采用通过每个patch的参数来获得不同layer的shell texture。因此,对于每一个layer,为了生成覆盖整个mesh的半透明的Shell,patch纹理是反复实例化的。这个过程对每个layer都会进行。

Fin texture
我们用一个单一的fin texture,弄在所有轮廓的表面。这个texture是通过 从任意表面切线方向合成一个geometric hair的slab生成的。Slab的宽度确定了毛发对于fin的密度。当渲染每一个fin时,我们随机地选择纹理坐标区间来代表边缘的长度。Scaleing factor 与参数化网格的lapped texture的数据是一致的。理想情况下,每条边都有自己的fin texture(他们在整个头发模型的适当地方中采样,参考他们的曲率和密度)。然而我们发现,这是不必要的(因为使用通用的fin texture的视觉效果已经足够好了)而且这样做会增加纹理内存。由于fin的局部密度取决于模型的复杂性,我们手动地为每个模型选择合成的slab的宽度,这样就可以对已有的模型和纹理选择一个适当的密度。

Runtime Rendering
Surface rendering
每一帧,我们先渲染一个不透明的网格,并且将设置Z-buffer。这里包括最里面的layer和没有毛发的区域
Fin rendering
然后,我们渲染fins,每个fin是一个quad,嵌在mesh的边缘而且沿着法线方向延伸。我们发现仅仅渲染在轮廓的fin将会得到更好的结果。为了保持时间相关性,随着fin越来越靠近轮廓,我们使用下述方法逐渐将其淡出:对于每个mesh边缘,我们计算fin法线和视线的点乘p,然后乘以fin的透明度(0,2|p|-1).我们收集非透明的fin,并渲染他们,进行深度检测,但并不写入Z-buffer。需要注意的是,我们会渲染那些对于一些边是看不见的fin,因为对于那些fin,他们的尖端是可以被看见的。Fin的渲染数量只占边缘总数的一部分,而且都集中在Shell的layers的面上。因此fin rendering对性能并没有产生较大的影响,但是提高了视觉效果。

Shell rendering
接下来,我们从里到外渲染偏移过的shell。对于每一层,我们合成那些已经被渲染过的lapped texture(半透明)的patch。在Shell rendering时,我们同时进行深度测试和深度写入,开启alpha-testing去避免写入那些alpha为0的像素的深度。为了让Shell纹理可以平铺到大的patch,我们还开启了texture wrapping。

Rendering Discussion@_@

0 0
原创粉丝点击