《拜见罗宾逊一家》又叫做《未来小子》,原名叫做《ADayWithWilburRobinson》。它取材于WilliamJoyce颇富奇想的绘本故事童书,情节十分简单,讲述一个男孩Lewis跟着他来自未来的朋友Wilbur拜访他各具特色的家人,让Lewis度过奇妙的一天。在《拜见罗宾逊一家》中,Lewis的眼球渲染是一个技术难点,而迪斯尼很好地处理了这个问题。
面临挑战
《四眼天鸡》(Chicken Little)的初始眼球悬挂在动画师悬挂中完成了所有的工作,包括处理所有的缩放、旋转,甚至可以做出虹膜和瞳孔区域的缩放,还有眼球范围的保持,这些都应用到了由一组复杂的变形器提供的单表面上。我们绘制了最终表面,一切的效果都刚刚好。动画师的所见即所得。
问题:这个悬挂的复杂程度要乘以两倍,因为有两个眼球。
悬挂部门可以制作一个更加轻量的悬挂,其中眼球的表面是一个简单的构造几何实体(constructive solid geometry, CSG),它由一个球体和两个从球心向外指向的圆柱之间的布尔运算生成。不过我们不能轻易的绘制或者渲染那些表面。
解决方法:着色器会将动画师看到的内容重新生成。用于生成虹膜和瞳孔布尔形的两个圆柱能够非常好地帮助着色器中的投影椭圆。
我们认为我们需要以下的控制:
•一个定义眼球中心以及所有旋转信息的坐标系。
•虹膜大小、高度和宽度
•瞳孔大小、高度和宽度
我们随后在眼球周围添加了旋转。
眼球的悬挂控制了坐标系(每个眼球一个)的生成,并将它们连接到动画师的控制,以及追踪上面提到的其他设置。它们会作为补充属性来处理,然后直接输出到镜头完成的RIB中,它们会在这个阶段覆盖着色器。使用标准的RAT格式来指定基本变量(请在你的Renderman文档中查看Application Note #22),Maya的属性如下:
我们在视觉发展部门有这些默认数值,也有它们在坐标系上的默认位置,不过当场景制作到了镜头完成的阶段时,这些都会被动画师的最终设置替换掉。
着色器
实际上,我们的虹膜和瞳孔都被定义成单位圆上的投影椭圆。着色器知道每个区域的大小,并将这些信息投射会单材质贴图上,这些贴图已经对眼球、瞳孔和巩膜范围硬编码成s和t材质贴图调用。首先我们会定义表面上的一个点与眼球中心的相对位置,这刚好就是我们坐标轴上的z轴。
// transform sample point into the center pivot coord system
varying point Pt = transform("current", coordSysName, Pbase);
// unit vector from origin pointing toward current sample
varying vector vecP = normalize(vector(Pt));
// angle between current sample and z axis
varying float angleP = acos(comp(vecP,2));
现在我们知道该点与眼球中心的相对位置,这样我们只需将它代入到我们的材质贴图中。一般来说,我们只需对角度进行测量,并利用测量结果,但是由于我们需要有能力对眼球的某些区域(瞳孔和虹膜)以任意数值进行缩放,所以我们的过程变得非常复杂。
考虑到两个区域的的大小,并假设瞳孔的大小总是比虹膜要小,我们现在就可以预测该点会出现在哪个区域,并将该信息映射回材质贴图。首先,我们要定义这些区域:
// get regions edge angles in the direction of the current sample
varying float pupilAngle = ellipseAngle( Pt, pupilX, pupilY, rotation);
varying float irisAngle = ellipseAngle( Pt, irisX, irisY, rotation);
上面的函数(在附录中有提供)将表示瞳孔、虹膜和巩膜之间界限的角度返回。现在我们简单地将该点映射到瞳孔、虹膜或者巩膜上的表面。然后该取值会经过标准化,并重新映射到单材质贴图中。材质贴图区域会被硬编码到着色器中,而且所有绘制的贴图必须符合这些设置。
瞳孔、虹膜和巩膜区域
利用Z轴(眼球中心)与该点之间的角度,我们现在可以定义该点会在哪里映射到我们的眼球材质贴图中,该距离为t:
// get v texture coord (same for all regions)
varying float angleV = atan(comp(Pt,0),comp(Pt,1));
map_tt = (angleV + PI)/(2*PI); // normalize angle
现在我们已经有了s和t的值,材质贴图参考能够正常处理。
简单材质贴图
值得一提的是,这种投影技术不会限制于完美球形的眼球。虽然初始投影是在一个单位球体上完成的,但是我们可以将眼球区域的结果投影到任意的最终形状上。球体会有最好的效果,而且形状越接近球体的话,投影就会出现越少的变形。
不同的眼球形状
执行细节
每只眼球都由两个球体来表示,眼球的主体含有上文提到的瞳孔、虹膜以及巩膜区域。另外一个稍微大一点的球体是用来表示角膜。它渲染出来的效果是完全透明的,只有一些反射以及高光部分。
我们在两个球体上都使用了位移。对于眼球本身,我们将虹膜和瞳孔向下移动,做出更加接近真实眼睛的反射效果。我们发现如果跳过这一步的话,眼睛看起来会很奇怪,而且没有对焦的感觉。奇怪的是,动画师们使用的眼球悬挂却没有这种位移。不过它的旋转是由一个定位器确定的,能够确定角色确实在看的方向。他们没有精细地微调眼球的焦点,只需要定义它的朝向就行了。
两个加上最终外观的球体,有位移与无位移
Lewis的凝视表情,加入位移之前与之后
另外,我们在角膜上有一个突出贴图,用来定义角膜突出,以及少量的突出噪点。我们选择比真实位移更大的突出,这是为了避免眼睑向内陷进去的问题。突出贴图为我们很好地将眼球上的直接高光分开,跟真正的角膜很相似。
角膜突出
将来的工作
这里会介绍我们的眼球投影技术背后的核心功能。从眼球的中心投影这一基础概念让我们可以在简单地材质投影之外添加很多其他的特性。我们添加了一些可以柔化和混合瞳孔、虹膜和巩膜之间的边缘的特性。另外,将来的制作会将着色器模块扩展,具体如下:
虹膜和巩膜的连续位移,用于避免我们现有贴图中的异常顶点产生的位移假象。
为镜面高光添加矢量补偿,这样灯光师可以将它向左或向右移动,而不需要调整灯光。
为镜面高光添加形状控制,这样它就能够变成灯光师想要的形状,比如标准的球体或者椭圆或者其他的形状。
在虹膜的反面添加镜面高光,做出丰富的焦散效果。这点也可以使用矢量补偿来实现。
在阴影计算中添加一个比例系数,这样做实际上是一种取巧,沿着眼睑的内部生成阴影。
相似地,由于我们的坐标系有向上的概念,我们可以旋转阴影贴图,在上眼睑上生成更深的阴影。
最后,当我们将动画师的悬挂更好的适配到我们渲染的内容之后,外观发展过程就完整了。我们没有使用CSG几何图形,而是生成了一个Maya的硬件着色器插件,它能够准确复制RenderMan着色器投影技术。这个插件实际上将Nvidia的Cg着色器语言加入到了Maya当中,并让我们能够使用各种属性调整着色器设置。在这种情况下,同样的rmanFirisX会控制RenderMan的着色器。我们甚至会参考同样的默认材质文件。事实证明这样会比之前的解决方案更准确,而且更快。
Maya的硬件着色器的截图
ellipseAngle()计算的可视化表示